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