]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_get.c
Retention period updates
[bacula/bacula] / bacula / src / cats / sql_get.c
1 /*
2  * Bacula Catalog Database Get record interface routines
3  *  Note, these routines generally get a record by id or
4  *        by name.  If more logic is involved, the routine
5  *        should be in find.c 
6  *
7  *    Kern Sibbald, March 2000
8  */
9
10 /*
11    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 /* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
31
32 /* The following is necessary so that we do not include
33  * the dummy external definition of DB.
34  */
35 #define __SQL_C                       /* indicate that this is sql.c */
36
37 #include "bacula.h"
38 #include "cats.h"
39
40 #if    HAVE_MYSQL || HAVE_SQLITE
41
42 /* -----------------------------------------------------------------------
43  *
44  *   Generic Routines (or almost generic)
45  *
46  * -----------------------------------------------------------------------
47  */
48
49 /* Forward referenced functions */
50 static int db_get_file_record(B_DB *mdb, FILE_DBR *fdbr);
51 static int db_get_filename_record(B_DB *mdb, char *fname);
52 static int db_get_path_record(B_DB *mdb, char *path);
53
54
55 /* Imported subroutines */
56 extern void print_result(B_DB *mdb);
57 extern int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
58
59
60 /*
61  * Given a full filename (with path), look up the File record
62  * (with attributes) in the database.
63  *
64  *  Returns: 0 on failure
65  *           1 on success with the File record in FILE_DBR
66  */
67 int db_get_file_attributes_record(B_DB *mdb, char *fname, FILE_DBR *fdbr)
68 {
69    int fnl, pnl;
70    char *l, *p;
71    uint64_t id;
72    char file[MAXSTRING];
73    char spath[MAXSTRING];
74    char buf[MAXSTRING];
75    Dmsg0(20, "get_file_from_catalog\n");
76
77    /* Find path without the filename */
78    for (p=l=fname; *p; p++) {
79       if (*p == '/') {
80          l = p;
81       }
82    }
83    if (*l == '/') {
84       l++;
85    }
86
87    fnl = p - l;
88    strcpy(file, l);
89
90    pnl = l - fname;    
91    strncpy(spath, fname, pnl);
92    spath[l-fname] = 0;
93
94    if (pnl == 0) {
95       return 0;
96    }
97
98    strip_trailing_junk(spath);
99    Dmsg1(50, "spath=%s\n", spath);
100
101    strip_trailing_junk(file);
102    Dmsg1(50, "file=%s\n", file);
103
104    db_escape_string(buf, file, fnl);
105    fdbr->FilenameId = db_get_filename_record(mdb, buf);
106    Dmsg1(50, "db_get_filename_record FilenameId=%d\n", fdbr->FilenameId);
107
108    db_escape_string(buf, spath, pnl);
109    fdbr->PathId = db_get_path_record(mdb, buf);
110    Dmsg1(50, "db_get_path_record PathId=%d\n", fdbr->PathId);
111
112    id = db_get_file_record(mdb, fdbr);
113
114    return id;
115 }
116
117  
118
119 /* Get a File record   
120  * Returns: 0 on failure
121  *          1 on success
122  */
123 static
124 int db_get_file_record(B_DB *mdb, FILE_DBR *fdbr)
125 {
126    SQL_ROW row;
127
128    P(mdb->mutex);
129    Mmsg(&mdb->cmd, 
130 "SELECT FileId, LStat, MD5 from File where File.JobId=%d and File.PathId=%d and \
131 File.FilenameId=%d", fdbr->JobId, fdbr->PathId, fdbr->FilenameId);
132
133    if (QUERY_DB(mdb, mdb->cmd)) {
134
135       mdb->num_rows = sql_num_rows(mdb);
136
137       /* 
138        * Note, we can find more than one File record with the same
139        *  filename if the file is linked.   ????????
140        */
141       if (mdb->num_rows > 1) {
142          Emsg1(M_WARNING, 0, _("get_file_record want 1 got rows=%d\n"), mdb->num_rows);
143          Emsg1(M_WARNING, 0, "%s\n", mdb->cmd);
144       }
145       if (mdb->num_rows >= 1) {
146          if ((row = sql_fetch_row(mdb)) == NULL) {
147             Emsg1(M_ERROR, 0, "Error fetching row: %s\n", sql_strerror(mdb));
148          } else {
149             fdbr->FileId = (FileId_t)strtod(row[0], NULL);
150             strncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
151             fdbr->LStat[sizeof(fdbr->LStat)] = 0;
152             strncpy(fdbr->MD5, row[2], sizeof(fdbr->MD5));
153             fdbr->MD5[sizeof(fdbr->MD5)] = 0;
154             sql_free_result(mdb);
155             V(mdb->mutex);
156             return 1;
157          }
158       }
159
160       sql_free_result(mdb);
161    }
162    V(mdb->mutex);
163    return 0;                          /* failed */
164
165 }
166
167 /* Get Filename record   
168  * Returns: 0 on failure
169  *          FilenameId on success
170  */
171 static int db_get_filename_record(B_DB *mdb, char *fname) 
172 {
173    SQL_ROW row;
174    int FilenameId;
175
176    if (*fname == 0) {
177       Mmsg0(&mdb->errmsg, _("Null name given to db_get_filename_record\n"));
178       Emsg0(M_ABORT, 0, mdb->errmsg);
179    }
180
181    P(mdb->mutex);
182    Mmsg(&mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name=\"%s\"", fname);
183    if (QUERY_DB(mdb, mdb->cmd)) {
184
185       mdb->num_rows = sql_num_rows(mdb);
186
187       if (mdb->num_rows > 1) {
188          Mmsg1(&mdb->errmsg, _("More than one Filename!: %d\n"), (int)(mdb->num_rows));
189          Emsg0(M_FATAL, 0, mdb->errmsg);
190       } else if (mdb->num_rows == 1) {
191          if ((row = sql_fetch_row(mdb)) == NULL) {
192             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
193             Emsg0(M_FATAL, 0, mdb->errmsg);
194          }
195          FilenameId = atoi(row[0]);
196          if (FilenameId <= 0) {
197             Mmsg2(&mdb->errmsg, _("Create db Filename record %s found bad record: %d\n"),
198                mdb->cmd, FilenameId); 
199             Emsg0(M_ERROR, 0, mdb->errmsg);
200          }
201          sql_free_result(mdb);
202          V(mdb->mutex);
203          return FilenameId;
204
205       }
206       sql_free_result(mdb);
207    }
208    V(mdb->mutex);
209    return 0;                          /* failed */
210 }
211
212 /* Get path record   
213  * Returns: 0 on failure
214  *          PathId on success
215  */
216 static int db_get_path_record(B_DB *mdb, char *path)
217 {
218    SQL_ROW row;
219    int PathId;
220    /*******FIXME***** move into mdb record and allocate */
221    static int cached_id = 0;
222    static char cached_path[MAXSTRING];
223
224    if (*path == 0) {
225       Emsg0(M_ABORT, 0, _("Null path given to db_get_path_record\n"));
226    }
227    if (cached_id != 0 && strcmp(cached_path, path) == 0) {
228       return cached_id;
229    }          
230
231    P(mdb->mutex);
232    Mmsg(&mdb->cmd, "SELECT PathId FROM Path WHERE Path=\"%s\"", path);
233
234    if (QUERY_DB(mdb, mdb->cmd)) {
235       char ed1[30];
236       mdb->num_rows = sql_num_rows(mdb);
237
238       if (mdb->num_rows > 1) {
239          Mmsg1(&mdb->errmsg, _("More than one Path!: %s\n"), 
240             edit_uint64(mdb->num_rows, ed1));
241          Emsg0(M_FATAL, 0, mdb->errmsg);
242       } else if (mdb->num_rows == 1) {
243          if ((row = sql_fetch_row(mdb)) == NULL) {
244             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
245             Emsg0(M_FATAL, 0, mdb->errmsg);
246          }
247          PathId = atoi(row[0]);
248          if (PathId != cached_id) {
249             cached_id = PathId;
250             strcpy(cached_path, path);
251          }
252          sql_free_result(mdb);
253          V(mdb->mutex);
254          return PathId;
255       }
256
257       sql_free_result(mdb);
258    }
259    V(mdb->mutex);
260    return 0;                          /* failed */
261 }
262
263
264 /* 
265  * Get Job record for given JobId or Job name
266  * Returns: 0 on failure
267  *          1 on success
268  */
269 int db_get_job_record(B_DB *mdb, JOB_DBR *jr)
270 {
271    SQL_ROW row;
272
273    P(mdb->mutex);
274    if (jr->JobId == 0) {
275       Mmsg(&mdb->cmd, "SELECT VolSessionId, VolSessionTime, \
276 PoolId, StartTime, EndTime, JobFiles, JobBytes, StartDay, Job \
277 FROM Job WHERE Job=\"%s\"", jr->Job);
278     } else {
279       Mmsg(&mdb->cmd, "SELECT VolSessionId, VolSessionTime, \
280 PoolId, StartTime, EndTime, JobFiles, JobBytes, StartDay, Job \
281 FROM Job WHERE JobId=%d", jr->JobId);
282     }
283
284    if (!QUERY_DB(mdb, mdb->cmd)) {
285       V(mdb->mutex);
286       return 0;                       /* failed */
287    }
288    if ((row = sql_fetch_row(mdb)) == NULL) {
289       Mmsg1(&mdb->errmsg, _("No Job found for JobId %d\n"), jr->JobId);
290       sql_free_result(mdb);
291       V(mdb->mutex);
292       return 0;                       /* failed */
293    }
294
295    jr->VolSessionId = atol(row[0]);
296    jr->VolSessionTime = atol(row[1]);
297    jr->PoolId = atoi(row[2]);
298    strcpy(jr->cStartTime, row[3]);
299    strcpy(jr->cEndTime, row[4]);
300    jr->JobFiles = atol(row[5]);
301    jr->JobBytes = (uint64_t)strtod(row[6], NULL);
302    jr->StartDay = (btime_t)strtod(row[7], NULL);
303    strcpy(jr->Job, row[8]);
304    sql_free_result(mdb);
305
306    V(mdb->mutex);
307    return 1;
308 }
309
310 /*
311  * Find VolumeNames for a give JobId
312  *  Returns: 0 on error or no Volumes found
313  *           number of volumes on success
314  *              Volumes are concatenated in VolumeNames
315  *              separated by a vertical bar (|).
316  */
317 int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, char *VolumeNames)
318 {
319    SQL_ROW row;
320    int stat = 0;
321    int i;
322
323    P(mdb->mutex);
324    Mmsg(&mdb->cmd, 
325 "SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%d \
326 AND JobMedia.MediaId=Media.MediaId", JobId);
327
328    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
329    VolumeNames[0] = 0;
330    if (QUERY_DB(mdb, mdb->cmd)) {
331       mdb->num_rows = sql_num_rows(mdb);
332       Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
333       if (mdb->num_rows <= 0) {
334          Mmsg1(&mdb->errmsg, _("No volumes found for JobId=%d"), JobId);
335          stat = 0;
336       } else {
337          stat = mdb->num_rows;
338          for (i=0; i < stat; i++) {
339             if ((row = sql_fetch_row(mdb)) == NULL) {
340                Mmsg2(&mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
341                stat = 0;
342                break;
343             } else {
344                if (VolumeNames[0] != 0) {
345                   strcat(VolumeNames, "|");
346                }
347                strcat(VolumeNames, row[0]);
348             }
349          }
350       }
351       sql_free_result(mdb);
352    }
353    V(mdb->mutex);
354    return stat;
355 }
356
357
358 /* 
359  * Get the number of pool records
360  *
361  * Returns: -1 on failure
362  *          number on success
363  */
364 int db_get_num_pool_records(B_DB *mdb)
365 {
366    int stat = 0;
367
368    P(mdb->mutex);
369    Mmsg(&mdb->cmd, "SELECT count(*) from Pool");
370    stat = get_sql_record_max(mdb);
371    V(mdb->mutex);
372    return stat;
373 }
374
375 /*
376  * This function returns a list of all the Pool record ids.
377  *  The caller must free ids if non-NULL.
378  *
379  *  Returns 0: on failure
380  *          1: on success
381  */
382 int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
383 {
384    SQL_ROW row;
385    int stat = 0;
386    int i = 0;
387    uint32_t *id;
388
389    P(mdb->mutex);
390    *ids = NULL;
391    Mmsg(&mdb->cmd, "SELECT PoolId FROM Pool");
392    if (QUERY_DB(mdb, mdb->cmd)) {
393       *num_ids = sql_num_rows(mdb);
394       if (*num_ids > 0) {
395          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
396          while ((row = sql_fetch_row(mdb)) != NULL) {
397             id[i++] = (uint32_t)atoi(row[0]);
398          }
399          *ids = id;
400       }
401       sql_free_result(mdb);
402       stat = 1;
403    } else {
404       Mmsg(&mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
405       stat = 0;
406    }
407    V(mdb->mutex);
408    return stat;
409 }
410
411
412 /* Get Pool Record   
413  * If the PoolId is non-zero, we get its record,
414  *  otherwise, we search on the PoolName
415  *
416  * Returns: 0 on failure
417  *          id on success 
418  */
419 int db_get_pool_record(B_DB *mdb, POOL_DBR *pdbr)
420 {
421    SQL_ROW row;
422    int stat = 0;
423
424    P(mdb->mutex);
425    if (pdbr->PoolId != 0) {               /* find by id */
426       Mmsg(&mdb->cmd, 
427 "SELECT PoolId, Name, NumVols, MaxVols, UseOnce, UseCatalog, AcceptAnyVolume, \
428 PoolType, LabelFormat FROM Pool WHERE Pool.PoolId=%d", pdbr->PoolId);
429    } else {                           /* find by name */
430       Mmsg(&mdb->cmd, 
431 "SELECT PoolId, Name, NumVols, MaxVols, UseOnce, UseCatalog, AcceptAnyVolume, \
432 PoolType, LabelFormat FROM Pool WHERE Pool.Name=\"%s\"", pdbr->Name);
433    }  
434
435    if (QUERY_DB(mdb, mdb->cmd)) {
436       mdb->num_rows = sql_num_rows(mdb);
437       if (mdb->num_rows > 1) {
438          char ed1[30];
439          Mmsg1(&mdb->errmsg, _("More than one Pool!: %s\n"), 
440             edit_uint64(mdb->num_rows, ed1));
441          Emsg0(M_ERROR, 0, mdb->errmsg);
442       } else if (mdb->num_rows == 1) {
443          if ((row = sql_fetch_row(mdb)) == NULL) {
444             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
445             Emsg0(M_ERROR, 0, mdb->errmsg);
446          } else {
447             pdbr->PoolId = atoi(row[0]);
448             strcpy(pdbr->Name, row[1]);
449             pdbr->NumVols = atoi(row[2]);
450             pdbr->MaxVols = atoi(row[3]);
451             pdbr->UseOnce = atoi(row[4]);
452             pdbr->UseCatalog = atoi(row[5]);
453             pdbr->AcceptAnyVolume = atoi(row[6]);
454             strcpy(pdbr->PoolType, row[7]);
455             if (row[8]) {
456                strcpy(pdbr->LabelFormat, row[8]);
457             } else {
458                pdbr->LabelFormat[0] = 0;
459             }
460             stat = pdbr->PoolId;
461          }
462       }
463       sql_free_result(mdb);
464    }
465    V(mdb->mutex);
466    return stat;
467 }
468
469
470 /* 
471  * Get the number of Media records
472  *
473  * Returns: -1 on failure
474  *          number on success
475  */
476 int db_get_num_media_records(B_DB *mdb)
477 {
478    int stat = 0;
479
480    P(mdb->mutex);
481    Mmsg(&mdb->cmd, "SELECT count(*) from Media");
482    stat = get_sql_record_max(mdb);
483    V(mdb->mutex);
484    return stat;
485 }
486
487
488 /*
489  * This function returns a list of all the Media record ids.
490  *  The caller must free ids if non-NULL.
491  *
492  *  Returns 0: on failure
493  *          1: on success
494  */
495 int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
496 {
497    SQL_ROW row;
498    int stat = 0;
499    int i = 0;
500    uint32_t *id;
501
502    P(mdb->mutex);
503    *ids = NULL;
504    Mmsg(&mdb->cmd, "SELECT MediaId FROM Media");
505    if (QUERY_DB(mdb, mdb->cmd)) {
506       *num_ids = sql_num_rows(mdb);
507       if (*num_ids > 0) {
508          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
509          while ((row = sql_fetch_row(mdb)) != NULL) {
510             id[i++] = (uint32_t)atoi(row[0]);
511          }
512          *ids = id;
513       }
514       sql_free_result(mdb);
515       stat = 1;
516    } else {
517       Mmsg(&mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
518       stat = 0;
519    }
520    V(mdb->mutex);
521    return stat;
522 }
523
524
525 /* Get Media Record   
526  *
527  * Returns: 0 on failure
528  *          id on success 
529  */
530 int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr)
531 {
532    SQL_ROW row;
533    int stat = 0;
534
535    P(mdb->mutex);
536    if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
537       Mmsg(&mdb->cmd, "SELECT count(*) from Media");
538       mr->MediaId = get_sql_record_max(mdb);
539       V(mdb->mutex);
540       return 1;
541    }
542    if (mr->MediaId != 0) {               /* find by id */
543       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
544 VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\
545 MediaType,VolStatus,PoolId \
546 FROM Media WHERE MediaId=%d", mr->MediaId);
547    } else {                           /* find by name */
548       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
549 VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\
550 MediaType,VolStatus,PoolId \
551 FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName);
552    }  
553
554    if (QUERY_DB(mdb, mdb->cmd)) {
555       mdb->num_rows = sql_num_rows(mdb);
556       if (mdb->num_rows > 1) {
557          char ed1[30];
558          Mmsg1(&mdb->errmsg, _("More than one Volume!: %s\n"), 
559             edit_uint64(mdb->num_rows, ed1));
560          Emsg0(M_ERROR, 0, mdb->errmsg);
561       } else if (mdb->num_rows == 1) {
562          if ((row = sql_fetch_row(mdb)) == NULL) {
563             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
564             Emsg0(M_ERROR, 0, mdb->errmsg);
565          } else {
566             /* return values */
567             mr->MediaId = atoi(row[0]);
568             strcpy(mr->VolumeName, row[1]);
569             mr->VolJobs = atoi(row[2]);
570             mr->VolFiles = atoi(row[3]);
571             mr->VolBlocks = atoi(row[4]);
572             mr->VolBytes = (uint64_t)strtod(row[5], NULL);
573             mr->VolMounts = atoi(row[6]);
574             mr->VolErrors = atoi(row[7]);
575             mr->VolWrites = atoi(row[8]);
576             mr->VolMaxBytes = (uint64_t)strtod(row[9], NULL);
577             mr->VolCapacityBytes = (uint64_t)strtod(row[10], NULL);
578             strcpy(mr->MediaType, row[11]);
579             strcpy(mr->VolStatus, row[12]);
580             mr->PoolId = atoi(row[13]);
581             stat = mr->MediaId;
582          }
583       } else {
584          Mmsg0(&mdb->errmsg, _("Media record not found.\n"));
585       }
586       sql_free_result(mdb);
587    }
588    V(mdb->mutex);
589    return stat;
590 }
591
592
593 #endif /* HAVE_MYSQL || HAVE_SQLITE */