]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_get.c
This commit was manufactured by cvs2svn to create tag
[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  *    Version $Id$
10  */
11
12 /*
13    Copyright (C) 2000-2005 Kern Sibbald
14
15    This program is free software; you can redistribute it and/or
16    modify it under the terms of the GNU General Public License
17    version 2 as amended with additional clauses defined in the
18    file LICENSE in the main source directory.
19
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
23    the file LICENSE for additional details.
24
25  */
26
27
28 /* The following is necessary so that we do not include
29  * the dummy external definition of DB.
30  */
31 #define __SQL_C                       /* indicate that this is sql.c */
32
33 #include "bacula.h"
34 #include "cats.h"
35
36 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
37
38 /* -----------------------------------------------------------------------
39  *
40  *   Generic Routines (or almost generic)
41  *
42  * -----------------------------------------------------------------------
43  */
44
45 /* Forward referenced functions */
46 static int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr);
47 static int db_get_filename_record(JCR *jcr, B_DB *mdb);
48 static int db_get_path_record(JCR *jcr, B_DB *mdb);
49
50
51 /* Imported subroutines */
52 extern void print_result(B_DB *mdb);
53 extern int QueryDB(const char *file, int line, JCR *jcr, B_DB *db, char *select_cmd);
54 extern void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname);
55
56
57
58 /*
59  * Given a full filename (with path), look up the File record
60  * (with attributes) in the database.
61  *
62  *  Returns: 0 on failure
63  *           1 on success with the File record in FILE_DBR
64  */
65 int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
66 {
67    int stat;
68    Dmsg1(100, "db_get_file_att_record fname=%s \n", fname);
69
70    db_lock(mdb);
71    split_path_and_file(jcr, mdb, fname);
72
73    fdbr->FilenameId = db_get_filename_record(jcr, mdb);
74
75    fdbr->PathId = db_get_path_record(jcr, mdb);
76
77    stat = db_get_file_record(jcr, mdb, jr, fdbr);
78
79    db_unlock(mdb);
80
81    return stat;
82 }
83
84
85 /*
86  * Get a File record
87  * Returns: 0 on failure
88  *          1 on success
89  *
90  *  DO NOT use Jmsg in this routine.
91  *
92  *  Note in this routine, we do not use Jmsg because it may be
93  *    called to get attributes of a non-existent file, which is
94  *    "normal" if a new file is found during Verify.
95  */
96 static
97 int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
98 {
99    SQL_ROW row;
100    int stat = 0;
101    char ed1[50], ed2[50], ed3[50];
102
103    if (jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
104    Mmsg(mdb->cmd,
105 "SELECT FileId, LStat, MD5 FROM File,Job WHERE "
106 "File.JobId=Job.JobId AND File.PathId=%s AND "
107 "File.FilenameId=%s AND Job.Type='B' AND Job.JobSTATUS='T' AND "
108 "ClientId=%s ORDER BY StartTime DESC LIMIT 1",
109       edit_int64(fdbr->PathId, ed1), 
110       edit_int64(fdbr->FilenameId, ed2), 
111       edit_int64(jr->ClientId,ed3));
112
113    } else {
114       Mmsg(mdb->cmd,
115 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
116 "File.FilenameId=%s", 
117       edit_int64(fdbr->JobId, ed1), 
118       edit_int64(fdbr->PathId, ed2), 
119       edit_int64(fdbr->FilenameId,ed3));
120    }
121    Dmsg3(050, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
122       fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
123
124    Dmsg1(100, "Query=%s\n", mdb->cmd);
125
126    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
127       mdb->num_rows = sql_num_rows(mdb);
128       Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows);
129       if (mdb->num_rows > 1) {
130          Mmsg1(mdb->errmsg, _("get_file_record want 1 got rows=%d\n"),
131             mdb->num_rows);
132       }
133       if (mdb->num_rows >= 1) {
134          if ((row = sql_fetch_row(mdb)) == NULL) {
135             Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
136          } else {
137             fdbr->FileId = (FileId_t)str_to_int64(row[0]);
138             bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
139             bstrncpy(fdbr->SIG, row[2], sizeof(fdbr->SIG));
140             stat = 1;
141          }
142       } else {
143          Mmsg2(mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"),
144             edit_int64(fdbr->PathId, ed1), 
145             edit_int64(fdbr->FilenameId, ed2));
146       }
147       sql_free_result(mdb);
148    } else {
149       Mmsg(mdb->errmsg, _("File record not found in Catalog.\n"));
150    }
151    return stat;
152
153 }
154
155 /* Get Filename record
156  * Returns: 0 on failure
157  *          FilenameId on success
158  *
159  *   DO NOT use Jmsg in this routine (see notes for get_file_record)
160  */
161 static int db_get_filename_record(JCR *jcr, B_DB *mdb)
162 {
163    SQL_ROW row;
164    int FilenameId = 0;
165
166    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
167    db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl);
168
169    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
170    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
171       char ed1[30];
172       mdb->num_rows = sql_num_rows(mdb);
173       if (mdb->num_rows > 1) {
174          Mmsg2(mdb->errmsg, _("More than one Filename!: %s for file: %s\n"),
175             edit_uint64(mdb->num_rows, ed1), mdb->fname);
176          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
177       }
178       if (mdb->num_rows >= 1) {
179          if ((row = sql_fetch_row(mdb)) == NULL) {
180             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
181          } else {
182             FilenameId = str_to_int64(row[0]);
183             if (FilenameId <= 0) {
184                Mmsg2(mdb->errmsg, _("Get DB Filename record %s found bad record: %d\n"),
185                   mdb->cmd, FilenameId);
186                FilenameId = 0;
187             }
188          }
189       } else {
190          Mmsg1(mdb->errmsg, _("Filename record: %s not found.\n"), mdb->fname);
191       }
192       sql_free_result(mdb);
193    } else {
194       Mmsg(mdb->errmsg, _("Filename record: %s not found in Catalog.\n"), mdb->fname);
195    }
196    return FilenameId;
197 }
198
199 /* Get path record
200  * Returns: 0 on failure
201  *          PathId on success
202  *
203  *   DO NOT use Jmsg in this routine (see notes for get_file_record)
204  */
205 static int db_get_path_record(JCR *jcr, B_DB *mdb)
206 {
207    SQL_ROW row;
208    uint32_t PathId = 0;
209
210    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
211    db_escape_string(mdb->esc_name, mdb->path, mdb->pnl);
212
213    if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
214        strcmp(mdb->cached_path, mdb->path) == 0) {
215       return mdb->cached_path_id;
216    }
217
218    Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
219
220    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
221       char ed1[30];
222       mdb->num_rows = sql_num_rows(mdb);
223       if (mdb->num_rows > 1) {
224          Mmsg2(mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
225             edit_uint64(mdb->num_rows, ed1), mdb->path);
226          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
227       }
228       /* Even if there are multiple paths, take the first one */
229       if (mdb->num_rows >= 1) {
230          if ((row = sql_fetch_row(mdb)) == NULL) {
231             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
232          } else {
233             PathId = str_to_int64(row[0]);
234             if (PathId <= 0) {
235                Mmsg2(mdb->errmsg, _("Get DB path record %s found bad record: %s\n"),
236                   mdb->cmd, edit_int64(PathId, ed1));
237                PathId = 0;
238             } else {
239                /* Cache path */
240                if (PathId != mdb->cached_path_id) {
241                   mdb->cached_path_id = PathId;
242                   mdb->cached_path_len = mdb->pnl;
243                   pm_strcpy(mdb->cached_path, mdb->path);
244                }
245             }
246          }
247       } else {
248          Mmsg1(mdb->errmsg, _("Path record: %s not found.\n"), mdb->path);
249       }
250       sql_free_result(mdb);
251    } else {
252       Mmsg(mdb->errmsg, _("Path record: %s not found in Catalog.\n"), mdb->path);
253    }
254    return PathId;
255 }
256
257
258 /*
259  * Get Job record for given JobId or Job name
260  * Returns: 0 on failure
261  *          1 on success
262  */
263 int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
264 {
265    SQL_ROW row;
266    char ed1[50];
267
268    db_lock(mdb);
269    if (jr->JobId == 0) {
270       Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
271 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
272 "Type,Level,ClientId,Name "
273 "FROM Job WHERE Job='%s'", jr->Job);
274     } else {
275       Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
276 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
277 "Type,Level,ClientId,Name "
278 "FROM Job WHERE JobId=%s", 
279           edit_int64(jr->JobId, ed1));
280     }
281
282    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
283       db_unlock(mdb);
284       return 0;                       /* failed */
285    }
286    if ((row = sql_fetch_row(mdb)) == NULL) {
287       Mmsg1(mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1));
288       sql_free_result(mdb);
289       db_unlock(mdb);
290       return 0;                       /* failed */
291    }
292
293    jr->VolSessionId = str_to_uint64(row[0]);
294    jr->VolSessionTime = str_to_uint64(row[1]);
295    jr->PoolId = str_to_int64(row[2]);
296    bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime));
297    bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime));
298    jr->JobFiles = str_to_int64(row[5]);
299    jr->JobBytes = str_to_int64(row[6]);
300    jr->JobTDate = str_to_int64(row[7]);
301    bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job));
302    jr->JobStatus = (int)*row[9];
303    jr->JobType = (int)*row[10];
304    jr->JobLevel = (int)*row[11];
305    jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)"");
306    bstrncpy(jr->Name, row[13]!=NULL?row[13]:"", sizeof(jr->Name));
307    sql_free_result(mdb);
308
309    db_unlock(mdb);
310    return 1;
311 }
312
313 /*
314  * Find VolumeNames for a given JobId
315  *  Returns: 0 on error or no Volumes found
316  *           number of volumes on success
317  *              Volumes are concatenated in VolumeNames
318  *              separated by a vertical bar (|) in the order
319  *              that they were written.
320  *
321  *  Returns: number of volumes on success
322  */
323 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **VolumeNames)
324 {
325    SQL_ROW row;
326    char ed1[50];
327    int stat = 0;
328    int i;
329
330    db_lock(mdb);
331    /* Get one entry per VolumeName, but "sort" by VolIndex */
332    Mmsg(mdb->cmd,
333         "SELECT VolumeName,MAX(VolIndex) FROM JobMedia,Media WHERE "
334         "JobMedia.JobId=%s AND JobMedia.MediaId=Media.MediaId "
335         "GROUP BY VolumeName "
336         "ORDER BY 2 ASC", edit_int64(JobId,ed1));
337
338    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
339    *VolumeNames[0] = 0;
340    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
341       mdb->num_rows = sql_num_rows(mdb);
342       Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
343       if (mdb->num_rows <= 0) {
344          Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
345          stat = 0;
346       } else {
347          stat = mdb->num_rows;
348          for (i=0; i < stat; i++) {
349             if ((row = sql_fetch_row(mdb)) == NULL) {
350                Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
351                Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
352                stat = 0;
353                break;
354             } else {
355                if (*VolumeNames[0] != 0) {
356                   pm_strcat(VolumeNames, "|");
357                }
358                pm_strcat(VolumeNames, row[0]);
359             }
360          }
361       }
362       sql_free_result(mdb);
363    } else {
364       Mmsg(mdb->errmsg, _("No Volume for JobId %d found in Catalog.\n"), JobId);
365    }
366    db_unlock(mdb);
367    return stat;
368 }
369
370 /*
371  * Find Volume parameters for a give JobId
372  *  Returns: 0 on error or no Volumes found
373  *           number of volumes on success
374  *           List of Volumes and start/end file/blocks (malloced structure!)
375  *
376  *  Returns: number of volumes on success
377  */
378 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS **VolParams)
379 {
380    SQL_ROW row;
381    char ed1[50];
382    int stat = 0;
383    int i;
384    VOL_PARAMS *Vols = NULL;
385
386    db_lock(mdb);
387    Mmsg(mdb->cmd,
388 "SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile,"
389 "JobMedia.EndFile,StartBlock,JobMedia.EndBlock,Copy,Stripe"
390 " FROM JobMedia,Media WHERE JobMedia.JobId=%s"
391 " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId",
392         edit_int64(JobId, ed1));
393
394    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
395    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
396       mdb->num_rows = sql_num_rows(mdb);
397       Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
398       if (mdb->num_rows <= 0) {
399          Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
400          stat = 0;
401       } else {
402          stat = mdb->num_rows;
403          if (stat > 0) {
404             *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
405          }
406          for (i=0; i < stat; i++) {
407             if ((row = sql_fetch_row(mdb)) == NULL) {
408                Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
409                Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
410                stat = 0;
411                break;
412             } else {
413                bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH);
414                bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH);
415                Vols[i].FirstIndex = str_to_uint64(row[2]);
416                Vols[i].LastIndex = str_to_uint64(row[3]);
417                Vols[i].StartFile = str_to_uint64(row[4]);
418                Vols[i].EndFile = str_to_uint64(row[5]);
419                Vols[i].StartBlock = str_to_uint64(row[6]);
420                Vols[i].EndBlock = str_to_uint64(row[7]);
421 //             Vols[i].Copy = str_to_uint64(row[8]);
422 //             Vols[i].Stripe = str_to_uint64(row[9]);
423             }
424          }
425       }
426       sql_free_result(mdb);
427    }
428    db_unlock(mdb);
429    return stat;
430 }
431
432
433
434 /*
435  * Get the number of pool records
436  *
437  * Returns: -1 on failure
438  *          number on success
439  */
440 int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
441 {
442    int stat = 0;
443
444    db_lock(mdb);
445    Mmsg(mdb->cmd, "SELECT count(*) from Pool");
446    stat = get_sql_record_max(jcr, mdb);
447    db_unlock(mdb);
448    return stat;
449 }
450
451 /*
452  * This function returns a list of all the Pool record ids.
453  *  The caller must free ids if non-NULL.
454  *
455  *  Returns 0: on failure
456  *          1: on success
457  */
458 int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
459 {
460    SQL_ROW row;
461    int stat = 0;
462    int i = 0;
463    uint32_t *id;
464
465    db_lock(mdb);
466    *ids = NULL;
467    Mmsg(mdb->cmd, "SELECT PoolId FROM Pool");
468    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
469       *num_ids = sql_num_rows(mdb);
470       if (*num_ids > 0) {
471          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
472          while ((row = sql_fetch_row(mdb)) != NULL) {
473             id[i++] = str_to_uint64(row[0]);
474          }
475          *ids = id;
476       }
477       sql_free_result(mdb);
478       stat = 1;
479    } else {
480       Mmsg(mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
481       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
482       stat = 0;
483    }
484    db_unlock(mdb);
485    return stat;
486 }
487
488 /*
489  * This function returns a list of all the Client 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_client_ids(JCR *jcr, 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    db_lock(mdb);
503    *ids = NULL;
504    Mmsg(mdb->cmd, "SELECT ClientId FROM Client");
505    if (QUERY_DB(jcr, 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++] = str_to_uint64(row[0]);
511          }
512          *ids = id;
513       }
514       sql_free_result(mdb);
515       stat = 1;
516    } else {
517       Mmsg(mdb->errmsg, _("Client id select failed: ERR=%s\n"), sql_strerror(mdb));
518       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
519       stat = 0;
520    }
521    db_unlock(mdb);
522    return stat;
523 }
524
525
526
527 /* Get Pool Record
528  * If the PoolId is non-zero, we get its record,
529  *  otherwise, we search on the PoolName
530  *
531  * Returns: false on failure
532  *          true on success
533  */
534 bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
535 {
536    SQL_ROW row;
537    bool ok = false;
538    char ed1[50];
539
540    db_lock(mdb);
541    if (pdbr->PoolId != 0) {               /* find by id */
542       Mmsg(mdb->cmd,
543 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
544 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
545 "MaxVolBytes,PoolType,LabelType,LabelFormat FROM Pool WHERE Pool.PoolId=%s", 
546          edit_int64(pdbr->PoolId, ed1));
547    } else {                           /* find by name */
548       Mmsg(mdb->cmd,
549 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
550 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
551 "MaxVolBytes,PoolType,LabelType,LabelFormat FROM Pool WHERE Pool.Name='%s'", 
552          pdbr->Name);
553    }
554
555    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
556       mdb->num_rows = sql_num_rows(mdb);
557       if (mdb->num_rows > 1) {
558          char ed1[30];
559          Mmsg1(mdb->errmsg, _("More than one Pool!: %s\n"),
560             edit_uint64(mdb->num_rows, ed1));
561          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
562       } else if (mdb->num_rows == 1) {
563          if ((row = sql_fetch_row(mdb)) == NULL) {
564             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
565             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
566          } else {
567             pdbr->PoolId = str_to_int64(row[0]);
568             bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name));
569             pdbr->NumVols = str_to_int64(row[2]);
570             pdbr->MaxVols = str_to_int64(row[3]);
571             pdbr->UseOnce = str_to_int64(row[4]);
572             pdbr->UseCatalog = str_to_int64(row[5]);
573             pdbr->AcceptAnyVolume = str_to_int64(row[6]);
574             pdbr->AutoPrune = str_to_int64(row[7]);
575             pdbr->Recycle = str_to_int64(row[8]);
576             pdbr->VolRetention = str_to_int64(row[9]);
577             pdbr->VolUseDuration = str_to_int64(row[10]);
578             pdbr->MaxVolJobs = str_to_int64(row[11]);
579             pdbr->MaxVolFiles = str_to_int64(row[12]);
580             pdbr->MaxVolBytes = str_to_uint64(row[13]);
581             bstrncpy(pdbr->PoolType, row[14]!=NULL?row[14]:"", sizeof(pdbr->PoolType));
582             pdbr->LabelType = str_to_int64(row[15]);
583             bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat));
584             ok = true;
585          }
586       }
587       sql_free_result(mdb);
588    }
589    if (ok) {
590       uint32_t NumVols;
591       Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
592          edit_int64(pdbr->PoolId, ed1));
593       NumVols = get_sql_record_max(jcr, mdb);
594       Dmsg2(400, "Actual NumVols=%d Pool NumVols=%d\n", NumVols, pdbr->NumVols);
595       if (NumVols != pdbr->NumVols) {
596          pdbr->NumVols = NumVols;
597          db_update_pool_record(jcr, mdb, pdbr);
598       }
599    } else {
600       Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n"));
601    }
602    db_unlock(mdb);
603    return ok;
604 }
605
606 /* Get Client Record
607  * If the ClientId is non-zero, we get its record,
608  *  otherwise, we search on the Client Name
609  *
610  * Returns: 0 on failure
611  *          1 on success
612  */
613 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
614 {
615    SQL_ROW row;
616    int stat = 0;
617    char ed1[50];
618
619    db_lock(mdb);
620    if (cdbr->ClientId != 0) {               /* find by id */
621       Mmsg(mdb->cmd,
622 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
623 "FROM Client WHERE Client.ClientId=%s", 
624         edit_int64(cdbr->ClientId, ed1));
625    } else {                           /* find by name */
626       Mmsg(mdb->cmd,
627 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
628 "FROM Client WHERE Client.Name='%s'", cdbr->Name);
629    }
630
631    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
632       mdb->num_rows = sql_num_rows(mdb);
633       if (mdb->num_rows > 1) {
634          Mmsg1(mdb->errmsg, _("More than one Client!: %s\n"),
635             edit_uint64(mdb->num_rows, ed1));
636          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
637       } else if (mdb->num_rows == 1) {
638          if ((row = sql_fetch_row(mdb)) == NULL) {
639             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
640             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
641          } else {
642             cdbr->ClientId = str_to_int64(row[0]);
643             bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name));
644             bstrncpy(cdbr->Uname, row[2]!=NULL?row[2]:"", sizeof(cdbr->Uname));
645             cdbr->AutoPrune = str_to_int64(row[3]);
646             cdbr->FileRetention = str_to_int64(row[4]);
647             cdbr->JobRetention = str_to_int64(row[5]);
648             stat = 1;
649          }
650       } else {
651          Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
652       }
653       sql_free_result(mdb);
654    } else {
655       Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
656    }
657    db_unlock(mdb);
658    return stat;
659 }
660
661 /*
662  * Get Counter Record
663  *
664  * Returns: 0 on failure
665  *          1 on success
666  */
667 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
668 {
669    SQL_ROW row;
670
671    db_lock(mdb);
672    Mmsg(mdb->cmd, "SELECT MinValue,MaxValue,CurrentValue,WrapCounter "
673       "FROM Counters WHERE Counter='%s'", cr->Counter);
674
675    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
676       mdb->num_rows = sql_num_rows(mdb);
677
678       /* If more than one, report error, but return first row */
679       if (mdb->num_rows > 1) {
680          Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), (int)(mdb->num_rows));
681          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
682       }
683       if (mdb->num_rows >= 1) {
684          if ((row = sql_fetch_row(mdb)) == NULL) {
685             Mmsg1(mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb));
686             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
687             sql_free_result(mdb);
688             db_unlock(mdb);
689             return 0;
690          }
691          cr->MinValue = str_to_int64(row[0]);
692          cr->MaxValue = str_to_int64(row[1]);
693          cr->CurrentValue = str_to_int64(row[2]);
694          if (row[3]) {
695             bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter));
696          } else {
697             cr->WrapCounter[0] = 0;
698          }
699          sql_free_result(mdb);
700          db_unlock(mdb);
701          return 1;
702       }
703       sql_free_result(mdb);
704    } else {
705       Mmsg(mdb->errmsg, _("Counter record: %s not found in Catalog.\n"), cr->Counter);
706    }
707    db_unlock(mdb);
708    return 0;
709 }
710
711
712 /* Get FileSet Record
713  * If the FileSetId is non-zero, we get its record,
714  *  otherwise, we search on the name
715  *
716  * Returns: 0 on failure
717  *          id on success
718  */
719 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
720 {
721    SQL_ROW row;
722    int stat = 0;
723    char ed1[50];
724
725    db_lock(mdb);
726    if (fsr->FileSetId != 0) {               /* find by id */
727       Mmsg(mdb->cmd,
728            "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
729            "WHERE FileSetId=%s", 
730            edit_int64(fsr->FileSetId, ed1));
731    } else {                           /* find by name */
732       Mmsg(mdb->cmd,
733            "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
734            "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", fsr->FileSet);
735    }
736
737    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
738       mdb->num_rows = sql_num_rows(mdb);
739       if (mdb->num_rows > 1) {
740          char ed1[30];
741          Mmsg1(mdb->errmsg, _("Error got %s FileSets but expected only one!\n"),
742             edit_uint64(mdb->num_rows, ed1));
743          sql_data_seek(mdb, mdb->num_rows-1);
744       }
745       if ((row = sql_fetch_row(mdb)) == NULL) {
746          Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
747       } else {
748          fsr->FileSetId = str_to_int64(row[0]);
749          bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
750          bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
751          bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime));
752          stat = fsr->FileSetId;
753       }
754       sql_free_result(mdb);
755    } else {
756       Mmsg(mdb->errmsg, _("FileSet record not found in Catalog.\n"));
757    }
758    db_unlock(mdb);
759    return stat;
760 }
761
762
763 /*
764  * Get the number of Media records
765  *
766  * Returns: -1 on failure
767  *          number on success
768  */
769 int db_get_num_media_records(JCR *jcr, B_DB *mdb)
770 {
771    int stat = 0;
772
773    db_lock(mdb);
774    Mmsg(mdb->cmd, "SELECT count(*) from Media");
775    stat = get_sql_record_max(jcr, mdb);
776    db_unlock(mdb);
777    return stat;
778 }
779
780
781 /*
782  * This function returns a list of all the Media record ids for
783  *     the current Pool.
784  *  The caller must free ids if non-NULL.
785  *
786  *  Returns false: on failure
787  *          true:  on success
788  */
789 bool db_get_media_ids(JCR *jcr, B_DB *mdb, uint32_t PoolId, int *num_ids, uint32_t *ids[])
790 {
791    SQL_ROW row;
792    int i = 0;
793    uint32_t *id;
794    char ed1[50];
795    bool ok = false;
796
797    db_lock(mdb);
798    *ids = NULL;
799    Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE PoolId=%s", 
800        edit_int64(PoolId, ed1));
801    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
802       *num_ids = sql_num_rows(mdb);
803       if (*num_ids > 0) {
804          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
805          while ((row = sql_fetch_row(mdb)) != NULL) {
806             id[i++] = str_to_uint64(row[0]);
807          }
808          *ids = id;
809       }
810       sql_free_result(mdb);
811       ok = true;
812    } else {
813       Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
814       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
815       ok = false;
816    }
817    db_unlock(mdb);
818    return ok;
819 }
820
821
822 /* Get Media Record
823  *
824  * Returns: false: on failure
825  *          true:  on success
826  */
827 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
828 {
829    SQL_ROW row;
830    char ed1[50];
831    bool ok = false;
832
833    db_lock(mdb);
834    if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
835       Mmsg(mdb->cmd, "SELECT count(*) from Media");
836       mr->MediaId = get_sql_record_max(jcr, mdb);
837       db_unlock(mdb);
838       return true;
839    }
840    if (mr->MediaId != 0) {               /* find by id */
841       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
842          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
843          "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
844          "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
845          "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId "
846          "FROM Media WHERE MediaId=%s", 
847          edit_int64(mr->MediaId, ed1));
848    } else {                           /* find by name */
849       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
850          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
851          "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
852          "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
853          "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId "
854          "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
855    }
856
857    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
858       char ed1[50];
859       mdb->num_rows = sql_num_rows(mdb);
860       if (mdb->num_rows > 1) {
861          Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
862             edit_uint64(mdb->num_rows, ed1));
863          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
864       } else if (mdb->num_rows == 1) {
865          if ((row = sql_fetch_row(mdb)) == NULL) {
866             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
867             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
868          } else {
869             /* return values */
870             mr->MediaId = str_to_int64(row[0]);
871             bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
872             mr->VolJobs = str_to_int64(row[2]);
873             mr->VolFiles = str_to_int64(row[3]);
874             mr->VolBlocks = str_to_int64(row[4]);
875             mr->VolBytes = str_to_uint64(row[5]);
876             mr->VolMounts = str_to_int64(row[6]);
877             mr->VolErrors = str_to_int64(row[7]);
878             mr->VolWrites = str_to_int64(row[8]);
879             mr->MaxVolBytes = str_to_uint64(row[9]);
880             mr->VolCapacityBytes = str_to_uint64(row[10]);
881             bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
882             bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
883             mr->PoolId = str_to_int64(row[13]);
884             mr->VolRetention = str_to_uint64(row[14]);
885             mr->VolUseDuration = str_to_uint64(row[15]);
886             mr->MaxVolJobs = str_to_int64(row[16]);
887             mr->MaxVolFiles = str_to_int64(row[17]);
888             mr->Recycle = str_to_int64(row[18]);
889             mr->Slot = str_to_int64(row[19]);
890             bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
891             mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
892             bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
893             mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
894             mr->InChanger = str_to_uint64(row[22]);
895             mr->EndFile = str_to_uint64(row[23]);
896             mr->EndBlock = str_to_uint64(row[24]);
897             mr->VolParts = str_to_int64(row[25]);
898             mr->LabelType = str_to_int64(row[26]);
899             bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
900             mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
901             mr->StorageId = str_to_int64(row[28]);
902             ok = true;
903          }
904       } else {
905          if (mr->MediaId != 0) {
906             Mmsg1(mdb->errmsg, _("Media record MediaId=%s not found.\n"), 
907                edit_int64(mr->MediaId, ed1));
908          } else {
909             Mmsg1(mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"),
910                   mr->VolumeName);
911          }
912       }
913       sql_free_result(mdb);
914    } else {
915       if (mr->MediaId != 0) {
916          Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"),
917             mr->MediaId);
918        } else {
919          Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"),
920             mr->VolumeName);
921    }   }
922    db_unlock(mdb);
923    return ok;
924 }
925
926
927 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/