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