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