]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_get.c
4068dfbaec4d3447e64de421878812562b9c8aba
[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-2006 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->Digest, row[2], sizeof(fdbr->Digest));
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: false on failure
261  *          true  on success
262  */
263 bool 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,PriorJobId,RealEndTime "
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 false;                   /* 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 false;                   /* 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    jr->PriorJobId = str_to_uint64(row[14]!=NULL?row[14]:(char *)"");
308    bstrncpy(jr->cRealEndTime, row[15]!=NULL?row[15]:"", sizeof(jr->cRealEndTime));
309    sql_free_result(mdb);
310
311    db_unlock(mdb);
312    return true;
313 }
314
315 /*
316  * Find VolumeNames for a given JobId
317  *  Returns: 0 on error or no Volumes found
318  *           number of volumes on success
319  *              Volumes are concatenated in VolumeNames
320  *              separated by a vertical bar (|) in the order
321  *              that they were written.
322  *
323  *  Returns: number of volumes on success
324  */
325 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **VolumeNames)
326 {
327    SQL_ROW row;
328    char ed1[50];
329    int stat = 0;
330    int i;
331
332    db_lock(mdb);
333    /* Get one entry per VolumeName, but "sort" by VolIndex */
334    Mmsg(mdb->cmd,
335         "SELECT VolumeName,MAX(VolIndex) FROM JobMedia,Media WHERE "
336         "JobMedia.JobId=%s AND JobMedia.MediaId=Media.MediaId "
337         "GROUP BY VolumeName "
338         "ORDER BY 2 ASC", edit_int64(JobId,ed1));
339
340    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
341    *VolumeNames[0] = 0;
342    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
343       mdb->num_rows = sql_num_rows(mdb);
344       Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
345       if (mdb->num_rows <= 0) {
346          Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
347          stat = 0;
348       } else {
349          stat = mdb->num_rows;
350          for (i=0; i < stat; i++) {
351             if ((row = sql_fetch_row(mdb)) == NULL) {
352                Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
353                Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
354                stat = 0;
355                break;
356             } else {
357                if (*VolumeNames[0] != 0) {
358                   pm_strcat(VolumeNames, "|");
359                }
360                pm_strcat(VolumeNames, row[0]);
361             }
362          }
363       }
364       sql_free_result(mdb);
365    } else {
366       Mmsg(mdb->errmsg, _("No Volume for JobId %d found in Catalog.\n"), JobId);
367    }
368    db_unlock(mdb);
369    return stat;
370 }
371
372 /*
373  * Find Volume parameters for a give JobId
374  *  Returns: 0 on error or no Volumes found
375  *           number of volumes on success
376  *           List of Volumes and start/end file/blocks (malloced structure!)
377  *
378  *  Returns: number of volumes on success
379  */
380 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS **VolParams)
381 {
382    SQL_ROW row;
383    char ed1[50];
384    int stat = 0;
385    int i;
386    VOL_PARAMS *Vols = NULL;
387
388    db_lock(mdb);
389    Mmsg(mdb->cmd,
390 "SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile,"
391 "JobMedia.EndFile,StartBlock,JobMedia.EndBlock,Copy,"
392 "Slot,StorageId"
393 " FROM JobMedia,Media WHERE JobMedia.JobId=%s"
394 " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId",
395         edit_int64(JobId, ed1));
396
397    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
398    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
399       mdb->num_rows = sql_num_rows(mdb);
400       Dmsg1(200, "Num rows=%d\n", mdb->num_rows);
401       if (mdb->num_rows <= 0) {
402          Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
403          stat = 0;
404       } else {
405          stat = mdb->num_rows;
406          DBId_t *SId;
407          if (stat > 0) {
408             *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
409             SId = (DBId_t *)malloc(stat * sizeof(DBId_t));
410          }
411          for (i=0; i < stat; i++) {
412             if ((row = sql_fetch_row(mdb)) == NULL) {
413                Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
414                Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
415                stat = 0;
416                break;
417             } else {
418                DBId_t StorageId;
419                bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH);
420                bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH);
421                Vols[i].FirstIndex = str_to_uint64(row[2]);
422                Vols[i].LastIndex = str_to_uint64(row[3]);
423                Vols[i].StartFile = str_to_uint64(row[4]);
424                Vols[i].EndFile = str_to_uint64(row[5]);
425                Vols[i].StartBlock = str_to_uint64(row[6]);
426                Vols[i].EndBlock = str_to_uint64(row[7]);
427 //             Vols[i].Copy = str_to_uint64(row[8]);
428                Vols[i].Slot = str_to_uint64(row[9]);
429                StorageId = str_to_uint64(row[10]);
430                Vols[i].Storage[0] = 0;
431                SId[i] = StorageId;
432             }
433          }
434          for (i=0; i < stat; i++) {
435             if (SId[i] != 0) {
436                Mmsg(mdb->cmd, "SELECT Name from Storage WHERE StorageId=%s",
437                   edit_int64(SId[i], ed1));
438                if (QUERY_DB(jcr, mdb, mdb->cmd)) {
439                   if ((row = sql_fetch_row(mdb)) != NULL) {
440                      bstrncpy(Vols[i].Storage, row[0], MAX_NAME_LENGTH);
441                   }
442                }
443             }
444          }
445       }
446       sql_free_result(mdb);
447    }
448    db_unlock(mdb);
449    return stat;
450 }
451
452
453
454 /*
455  * Get the number of pool records
456  *
457  * Returns: -1 on failure
458  *          number on success
459  */
460 int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
461 {
462    int stat = 0;
463
464    db_lock(mdb);
465    Mmsg(mdb->cmd, "SELECT count(*) from Pool");
466    stat = get_sql_record_max(jcr, mdb);
467    db_unlock(mdb);
468    return stat;
469 }
470
471 /*
472  * This function returns a list of all the Pool record ids.
473  *  The caller must free ids if non-NULL.
474  *
475  *  Returns 0: on failure
476  *          1: on success
477  */
478 int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
479 {
480    SQL_ROW row;
481    int stat = 0;
482    int i = 0;
483    uint32_t *id;
484
485    db_lock(mdb);
486    *ids = NULL;
487    Mmsg(mdb->cmd, "SELECT PoolId FROM Pool");
488    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
489       *num_ids = sql_num_rows(mdb);
490       if (*num_ids > 0) {
491          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
492          while ((row = sql_fetch_row(mdb)) != NULL) {
493             id[i++] = str_to_uint64(row[0]);
494          }
495          *ids = id;
496       }
497       sql_free_result(mdb);
498       stat = 1;
499    } else {
500       Mmsg(mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
501       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
502       stat = 0;
503    }
504    db_unlock(mdb);
505    return stat;
506 }
507
508 /*
509  * This function returns a list of all the Client record ids.
510  *  The caller must free ids if non-NULL.
511  *
512  *  Returns 0: on failure
513  *          1: on success
514  */
515 int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
516 {
517    SQL_ROW row;
518    int stat = 0;
519    int i = 0;
520    uint32_t *id;
521
522    db_lock(mdb);
523    *ids = NULL;
524    Mmsg(mdb->cmd, "SELECT ClientId FROM Client");
525    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
526       *num_ids = sql_num_rows(mdb);
527       if (*num_ids > 0) {
528          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
529          while ((row = sql_fetch_row(mdb)) != NULL) {
530             id[i++] = str_to_uint64(row[0]);
531          }
532          *ids = id;
533       }
534       sql_free_result(mdb);
535       stat = 1;
536    } else {
537       Mmsg(mdb->errmsg, _("Client id select failed: ERR=%s\n"), sql_strerror(mdb));
538       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
539       stat = 0;
540    }
541    db_unlock(mdb);
542    return stat;
543 }
544
545
546
547 /* Get Pool Record
548  * If the PoolId is non-zero, we get its record,
549  *  otherwise, we search on the PoolName
550  *
551  * Returns: false on failure
552  *          true on success
553  */
554 bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
555 {
556    SQL_ROW row;
557    bool ok = false;
558    char ed1[50];
559
560    db_lock(mdb);
561    if (pdbr->PoolId != 0) {               /* find by id */
562       Mmsg(mdb->cmd,
563 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
564 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
565 "MaxVolBytes,PoolType,LabelType,LabelFormat FROM Pool WHERE Pool.PoolId=%s", 
566          edit_int64(pdbr->PoolId, ed1));
567    } else {                           /* find by name */
568       Mmsg(mdb->cmd,
569 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
570 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
571 "MaxVolBytes,PoolType,LabelType,LabelFormat FROM Pool WHERE Pool.Name='%s'", 
572          pdbr->Name);
573    }
574
575    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
576       mdb->num_rows = sql_num_rows(mdb);
577       if (mdb->num_rows > 1) {
578          char ed1[30];
579          Mmsg1(mdb->errmsg, _("More than one Pool!: %s\n"),
580             edit_uint64(mdb->num_rows, ed1));
581          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
582       } else if (mdb->num_rows == 1) {
583          if ((row = sql_fetch_row(mdb)) == NULL) {
584             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
585             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
586          } else {
587             pdbr->PoolId = str_to_int64(row[0]);
588             bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name));
589             pdbr->NumVols = str_to_int64(row[2]);
590             pdbr->MaxVols = str_to_int64(row[3]);
591             pdbr->UseOnce = str_to_int64(row[4]);
592             pdbr->UseCatalog = str_to_int64(row[5]);
593             pdbr->AcceptAnyVolume = str_to_int64(row[6]);
594             pdbr->AutoPrune = str_to_int64(row[7]);
595             pdbr->Recycle = str_to_int64(row[8]);
596             pdbr->VolRetention = str_to_int64(row[9]);
597             pdbr->VolUseDuration = str_to_int64(row[10]);
598             pdbr->MaxVolJobs = str_to_int64(row[11]);
599             pdbr->MaxVolFiles = str_to_int64(row[12]);
600             pdbr->MaxVolBytes = str_to_uint64(row[13]);
601             bstrncpy(pdbr->PoolType, row[14]!=NULL?row[14]:"", sizeof(pdbr->PoolType));
602             pdbr->LabelType = str_to_int64(row[15]);
603             bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat));
604             ok = true;
605          }
606       }
607       sql_free_result(mdb);
608    }
609    if (ok) {
610       uint32_t NumVols;
611       Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
612          edit_int64(pdbr->PoolId, ed1));
613       NumVols = get_sql_record_max(jcr, mdb);
614       Dmsg2(400, "Actual NumVols=%d Pool NumVols=%d\n", NumVols, pdbr->NumVols);
615       if (NumVols != pdbr->NumVols) {
616          pdbr->NumVols = NumVols;
617          db_update_pool_record(jcr, mdb, pdbr);
618       }
619    } else {
620       Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n"));
621    }
622    db_unlock(mdb);
623    return ok;
624 }
625
626 /* Get Client Record
627  * If the ClientId is non-zero, we get its record,
628  *  otherwise, we search on the Client Name
629  *
630  * Returns: 0 on failure
631  *          1 on success
632  */
633 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
634 {
635    SQL_ROW row;
636    int stat = 0;
637    char ed1[50];
638
639    db_lock(mdb);
640    if (cdbr->ClientId != 0) {               /* find by id */
641       Mmsg(mdb->cmd,
642 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
643 "FROM Client WHERE Client.ClientId=%s", 
644         edit_int64(cdbr->ClientId, ed1));
645    } else {                           /* find by name */
646       Mmsg(mdb->cmd,
647 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
648 "FROM Client WHERE Client.Name='%s'", cdbr->Name);
649    }
650
651    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
652       mdb->num_rows = sql_num_rows(mdb);
653       if (mdb->num_rows > 1) {
654          Mmsg1(mdb->errmsg, _("More than one Client!: %s\n"),
655             edit_uint64(mdb->num_rows, ed1));
656          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
657       } else if (mdb->num_rows == 1) {
658          if ((row = sql_fetch_row(mdb)) == NULL) {
659             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
660             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
661          } else {
662             cdbr->ClientId = str_to_int64(row[0]);
663             bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name));
664             bstrncpy(cdbr->Uname, row[2]!=NULL?row[2]:"", sizeof(cdbr->Uname));
665             cdbr->AutoPrune = str_to_int64(row[3]);
666             cdbr->FileRetention = str_to_int64(row[4]);
667             cdbr->JobRetention = str_to_int64(row[5]);
668             stat = 1;
669          }
670       } else {
671          Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
672       }
673       sql_free_result(mdb);
674    } else {
675       Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
676    }
677    db_unlock(mdb);
678    return stat;
679 }
680
681 /*
682  * Get Counter Record
683  *
684  * Returns: 0 on failure
685  *          1 on success
686  */
687 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
688 {
689    SQL_ROW row;
690
691    db_lock(mdb);
692    Mmsg(mdb->cmd, "SELECT MinValue,MaxValue,CurrentValue,WrapCounter "
693       "FROM Counters WHERE Counter='%s'", cr->Counter);
694
695    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
696       mdb->num_rows = sql_num_rows(mdb);
697
698       /* If more than one, report error, but return first row */
699       if (mdb->num_rows > 1) {
700          Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), (int)(mdb->num_rows));
701          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
702       }
703       if (mdb->num_rows >= 1) {
704          if ((row = sql_fetch_row(mdb)) == NULL) {
705             Mmsg1(mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb));
706             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
707             sql_free_result(mdb);
708             db_unlock(mdb);
709             return 0;
710          }
711          cr->MinValue = str_to_int64(row[0]);
712          cr->MaxValue = str_to_int64(row[1]);
713          cr->CurrentValue = str_to_int64(row[2]);
714          if (row[3]) {
715             bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter));
716          } else {
717             cr->WrapCounter[0] = 0;
718          }
719          sql_free_result(mdb);
720          db_unlock(mdb);
721          return 1;
722       }
723       sql_free_result(mdb);
724    } else {
725       Mmsg(mdb->errmsg, _("Counter record: %s not found in Catalog.\n"), cr->Counter);
726    }
727    db_unlock(mdb);
728    return 0;
729 }
730
731
732 /* Get FileSet Record
733  * If the FileSetId is non-zero, we get its record,
734  *  otherwise, we search on the name
735  *
736  * Returns: 0 on failure
737  *          id on success
738  */
739 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
740 {
741    SQL_ROW row;
742    int stat = 0;
743    char ed1[50];
744
745    db_lock(mdb);
746    if (fsr->FileSetId != 0) {               /* find by id */
747       Mmsg(mdb->cmd,
748            "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
749            "WHERE FileSetId=%s", 
750            edit_int64(fsr->FileSetId, ed1));
751    } else {                           /* find by name */
752       Mmsg(mdb->cmd,
753            "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
754            "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", fsr->FileSet);
755    }
756
757    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
758       mdb->num_rows = sql_num_rows(mdb);
759       if (mdb->num_rows > 1) {
760          char ed1[30];
761          Mmsg1(mdb->errmsg, _("Error got %s FileSets but expected only one!\n"),
762             edit_uint64(mdb->num_rows, ed1));
763          sql_data_seek(mdb, mdb->num_rows-1);
764       }
765       if ((row = sql_fetch_row(mdb)) == NULL) {
766          Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
767       } else {
768          fsr->FileSetId = str_to_int64(row[0]);
769          bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
770          bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
771          bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime));
772          stat = fsr->FileSetId;
773       }
774       sql_free_result(mdb);
775    } else {
776       Mmsg(mdb->errmsg, _("FileSet record not found in Catalog.\n"));
777    }
778    db_unlock(mdb);
779    return stat;
780 }
781
782
783 /*
784  * Get the number of Media records
785  *
786  * Returns: -1 on failure
787  *          number on success
788  */
789 int db_get_num_media_records(JCR *jcr, B_DB *mdb)
790 {
791    int stat = 0;
792
793    db_lock(mdb);
794    Mmsg(mdb->cmd, "SELECT count(*) from Media");
795    stat = get_sql_record_max(jcr, mdb);
796    db_unlock(mdb);
797    return stat;
798 }
799
800
801 /*
802  * This function returns a list of all the Media record ids for
803  *     the current Pool.
804  *  The caller must free ids if non-NULL.
805  *
806  *  Returns false: on failure
807  *          true:  on success
808  */
809 bool db_get_media_ids(JCR *jcr, B_DB *mdb, uint32_t PoolId, int *num_ids, uint32_t *ids[])
810 {
811    SQL_ROW row;
812    int i = 0;
813    uint32_t *id;
814    char ed1[50];
815    bool ok = false;
816
817    db_lock(mdb);
818    *ids = NULL;
819    Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE PoolId=%s", 
820        edit_int64(PoolId, ed1));
821    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
822       *num_ids = sql_num_rows(mdb);
823       if (*num_ids > 0) {
824          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
825          while ((row = sql_fetch_row(mdb)) != NULL) {
826             id[i++] = str_to_uint64(row[0]);
827          }
828          *ids = id;
829       }
830       sql_free_result(mdb);
831       ok = true;
832    } else {
833       Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
834       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
835       ok = false;
836    }
837    db_unlock(mdb);
838    return ok;
839 }
840
841
842 /* Get Media Record
843  *
844  * Returns: false: on failure
845  *          true:  on success
846  */
847 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
848 {
849    SQL_ROW row;
850    char ed1[50];
851    bool ok = false;
852
853    db_lock(mdb);
854    if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
855       Mmsg(mdb->cmd, "SELECT count(*) from Media");
856       mr->MediaId = get_sql_record_max(jcr, mdb);
857       db_unlock(mdb);
858       return true;
859    }
860    if (mr->MediaId != 0) {               /* find by id */
861       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
862          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
863          "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
864          "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
865          "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
866          "Enabled,LocationId,RecycleCount,InitialWrite,"
867          "ScratchPoolId,RecyclePoolId "
868          "FROM Media WHERE MediaId=%s", 
869          edit_int64(mr->MediaId, ed1));
870    } else {                           /* find by name */
871       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
872          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
873          "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
874          "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
875          "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
876          "Enabled,LocationId,RecycleCount,InitialWrite,"
877          "ScratchPoolId,RecyclePoolId "
878          "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
879    }
880
881    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
882       char ed1[50];
883       mdb->num_rows = sql_num_rows(mdb);
884       if (mdb->num_rows > 1) {
885          Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
886             edit_uint64(mdb->num_rows, ed1));
887          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
888       } else if (mdb->num_rows == 1) {
889          if ((row = sql_fetch_row(mdb)) == NULL) {
890             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
891             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
892          } else {
893             /* return values */
894             mr->MediaId = str_to_int64(row[0]);
895             bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
896             mr->VolJobs = str_to_int64(row[2]);
897             mr->VolFiles = str_to_int64(row[3]);
898             mr->VolBlocks = str_to_int64(row[4]);
899             mr->VolBytes = str_to_uint64(row[5]);
900             mr->VolMounts = str_to_int64(row[6]);
901             mr->VolErrors = str_to_int64(row[7]);
902             mr->VolWrites = str_to_int64(row[8]);
903             mr->MaxVolBytes = str_to_uint64(row[9]);
904             mr->VolCapacityBytes = str_to_uint64(row[10]);
905             bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
906             bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
907             mr->PoolId = str_to_int64(row[13]);
908             mr->VolRetention = str_to_uint64(row[14]);
909             mr->VolUseDuration = str_to_uint64(row[15]);
910             mr->MaxVolJobs = str_to_int64(row[16]);
911             mr->MaxVolFiles = str_to_int64(row[17]);
912             mr->Recycle = str_to_int64(row[18]);
913             mr->Slot = str_to_int64(row[19]);
914             bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
915             mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
916             bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
917             mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
918             mr->InChanger = str_to_uint64(row[22]);
919             mr->EndFile = str_to_uint64(row[23]);
920             mr->EndBlock = str_to_uint64(row[24]);
921             mr->VolParts = str_to_int64(row[25]);
922             mr->LabelType = str_to_int64(row[26]);
923             bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
924             mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
925             mr->StorageId = str_to_int64(row[28]);
926             mr->Enabled = str_to_int64(row[29]);
927             mr->LocationId = str_to_int64(row[30]);
928             mr->RecycleCount = str_to_int64(row[31]);
929             bstrncpy(mr->cInitialWrite, row[32]!=NULL?row[32]:"", sizeof(mr->cInitialWrite));
930             mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
931             mr->ScratchPoolId = str_to_int64(row[33]);
932             mr->RecyclePoolId = str_to_int64(row[34]);
933             
934             ok = true;
935          }
936       } else {
937          if (mr->MediaId != 0) {
938             Mmsg1(mdb->errmsg, _("Media record MediaId=%s not found.\n"), 
939                edit_int64(mr->MediaId, ed1));
940          } else {
941             Mmsg1(mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"),
942                   mr->VolumeName);
943          }
944       }
945       sql_free_result(mdb);
946    } else {
947       if (mr->MediaId != 0) {
948          Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"),
949             mr->MediaId);
950        } else {
951          Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"),
952             mr->VolumeName);
953    }   }
954    db_unlock(mdb);
955    return ok;
956 }
957
958
959 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/