]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_get.c
ebl add RecyclePool to Pool. Media will take Pool.RecyclePool
[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    Bacula® - The Network Backup Solution
13
14    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
15
16    The main author of Bacula is Kern Sibbald, with contributions from
17    many others, a complete list can be found in the file AUTHORS.
18    This program is Free Software; you can redistribute it and/or
19    modify it under the terms of version two of the GNU General Public
20    License as published by the Free Software Foundation plus additions
21    that are listed in the file LICENSE.
22
23    This program is distributed in the hope that it will be useful, but
24    WITHOUT ANY WARRANTY; without even the implied warranty of
25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26    General Public License for more details.
27
28    You should have received a copy of the GNU General Public License
29    along with this program; if not, write to the Free Software
30    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31    02110-1301, USA.
32
33    Bacula® is a registered trademark of John Walker.
34    The licensor of Bacula is the Free Software Foundation Europe
35    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
36    Switzerland, email:ftf@fsfeurope.org.
37 */
38
39
40
41 /* The following is necessary so that we do not include
42  * the dummy external definition of DB.
43  */
44 #define __SQL_C                       /* indicate that this is sql.c */
45
46 #include "bacula.h"
47 #include "cats.h"
48
49 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
50
51 /* -----------------------------------------------------------------------
52  *
53  *   Generic Routines (or almost generic)
54  *
55  * -----------------------------------------------------------------------
56  */
57
58 /* Forward referenced functions */
59 static int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr);
60 static int db_get_filename_record(JCR *jcr, B_DB *mdb);
61 static int db_get_path_record(JCR *jcr, B_DB *mdb);
62
63
64 /*
65  * Given a full filename (with path), look up the File record
66  * (with attributes) in the database.
67  *
68  *  Returns: 0 on failure
69  *           1 on success with the File record in FILE_DBR
70  */
71 int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
72 {
73    int stat;
74    Dmsg1(100, "db_get_file_att_record fname=%s \n", fname);
75
76    db_lock(mdb);
77    split_path_and_file(jcr, mdb, fname);
78
79    fdbr->FilenameId = db_get_filename_record(jcr, mdb);
80
81    fdbr->PathId = db_get_path_record(jcr, mdb);
82
83    stat = db_get_file_record(jcr, mdb, jr, fdbr);
84
85    db_unlock(mdb);
86
87    return stat;
88 }
89
90
91 /*
92  * Get a File record
93  * Returns: 0 on failure
94  *          1 on success
95  *
96  *  DO NOT use Jmsg in this routine.
97  *
98  *  Note in this routine, we do not use Jmsg because it may be
99  *    called to get attributes of a non-existent file, which is
100  *    "normal" if a new file is found during Verify.
101  */
102 static
103 int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
104 {
105    SQL_ROW row;
106    int stat = 0;
107    char ed1[50], ed2[50], ed3[50];
108
109    if (jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
110    Mmsg(mdb->cmd,
111 "SELECT FileId, LStat, MD5 FROM File,Job WHERE "
112 "File.JobId=Job.JobId AND File.PathId=%s AND "
113 "File.FilenameId=%s AND Job.Type='B' AND Job.JobSTATUS='T' AND "
114 "ClientId=%s ORDER BY StartTime DESC LIMIT 1",
115       edit_int64(fdbr->PathId, ed1), 
116       edit_int64(fdbr->FilenameId, ed2), 
117       edit_int64(jr->ClientId,ed3));
118
119    } else {
120       Mmsg(mdb->cmd,
121 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
122 "File.FilenameId=%s", 
123       edit_int64(fdbr->JobId, ed1), 
124       edit_int64(fdbr->PathId, ed2), 
125       edit_int64(fdbr->FilenameId,ed3));
126    }
127    Dmsg3(050, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
128       fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
129
130    Dmsg1(100, "Query=%s\n", mdb->cmd);
131
132    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
133       mdb->num_rows = sql_num_rows(mdb);
134       Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows);
135       if (mdb->num_rows > 1) {
136          Mmsg1(mdb->errmsg, _("get_file_record want 1 got rows=%d\n"),
137             mdb->num_rows);
138       }
139       if (mdb->num_rows >= 1) {
140          if ((row = sql_fetch_row(mdb)) == NULL) {
141             Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
142          } else {
143             fdbr->FileId = (FileId_t)str_to_int64(row[0]);
144             bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
145             bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
146             stat = 1;
147          }
148       } else {
149          Mmsg2(mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"),
150             edit_int64(fdbr->PathId, ed1), 
151             edit_int64(fdbr->FilenameId, ed2));
152       }
153       sql_free_result(mdb);
154    } else {
155       Mmsg(mdb->errmsg, _("File record not found in Catalog.\n"));
156    }
157    return stat;
158
159 }
160
161 /* Get Filename record
162  * Returns: 0 on failure
163  *          FilenameId on success
164  *
165  *   DO NOT use Jmsg in this routine (see notes for get_file_record)
166  */
167 static int db_get_filename_record(JCR *jcr, B_DB *mdb)
168 {
169    SQL_ROW row;
170    int FilenameId = 0;
171
172    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
173    db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl);
174
175    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
176    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
177       char ed1[30];
178       mdb->num_rows = sql_num_rows(mdb);
179       if (mdb->num_rows > 1) {
180          Mmsg2(mdb->errmsg, _("More than one Filename!: %s for file: %s\n"),
181             edit_uint64(mdb->num_rows, ed1), mdb->fname);
182          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
183       }
184       if (mdb->num_rows >= 1) {
185          if ((row = sql_fetch_row(mdb)) == NULL) {
186             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
187          } else {
188             FilenameId = str_to_int64(row[0]);
189             if (FilenameId <= 0) {
190                Mmsg2(mdb->errmsg, _("Get DB Filename record %s found bad record: %d\n"),
191                   mdb->cmd, FilenameId);
192                FilenameId = 0;
193             }
194          }
195       } else {
196          Mmsg1(mdb->errmsg, _("Filename record: %s not found.\n"), mdb->fname);
197       }
198       sql_free_result(mdb);
199    } else {
200       Mmsg(mdb->errmsg, _("Filename record: %s not found in Catalog.\n"), mdb->fname);
201    }
202    return FilenameId;
203 }
204
205 /* Get path record
206  * Returns: 0 on failure
207  *          PathId on success
208  *
209  *   DO NOT use Jmsg in this routine (see notes for get_file_record)
210  */
211 static int db_get_path_record(JCR *jcr, B_DB *mdb)
212 {
213    SQL_ROW row;
214    uint32_t PathId = 0;
215
216    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
217    db_escape_string(mdb->esc_name, mdb->path, mdb->pnl);
218
219    if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
220        strcmp(mdb->cached_path, mdb->path) == 0) {
221       return mdb->cached_path_id;
222    }
223
224    Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
225
226    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
227       char ed1[30];
228       mdb->num_rows = sql_num_rows(mdb);
229       if (mdb->num_rows > 1) {
230          Mmsg2(mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
231             edit_uint64(mdb->num_rows, ed1), mdb->path);
232          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
233       }
234       /* Even if there are multiple paths, take the first one */
235       if (mdb->num_rows >= 1) {
236          if ((row = sql_fetch_row(mdb)) == NULL) {
237             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
238          } else {
239             PathId = str_to_int64(row[0]);
240             if (PathId <= 0) {
241                Mmsg2(mdb->errmsg, _("Get DB path record %s found bad record: %s\n"),
242                   mdb->cmd, edit_int64(PathId, ed1));
243                PathId = 0;
244             } else {
245                /* Cache path */
246                if (PathId != mdb->cached_path_id) {
247                   mdb->cached_path_id = PathId;
248                   mdb->cached_path_len = mdb->pnl;
249                   pm_strcpy(mdb->cached_path, mdb->path);
250                }
251             }
252          }
253       } else {
254          Mmsg1(mdb->errmsg, _("Path record: %s not found.\n"), mdb->path);
255       }
256       sql_free_result(mdb);
257    } else {
258       Mmsg(mdb->errmsg, _("Path record: %s not found in Catalog.\n"), mdb->path);
259    }
260    return PathId;
261 }
262
263
264 /*
265  * Get Job record for given JobId or Job name
266  * Returns: false on failure
267  *          true  on success
268  */
269 bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
270 {
271    SQL_ROW row;
272    char ed1[50];
273
274    db_lock(mdb);
275    if (jr->JobId == 0) {
276       Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
277 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
278 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId "
279 "FROM Job WHERE Job='%s'", jr->Job);
280     } else {
281       Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
282 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
283 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId "
284 "FROM Job WHERE JobId=%s", 
285           edit_int64(jr->JobId, ed1));
286     }
287
288    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
289       db_unlock(mdb);
290       return false;                   /* failed */
291    }
292    if ((row = sql_fetch_row(mdb)) == NULL) {
293       Mmsg1(mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1));
294       sql_free_result(mdb);
295       db_unlock(mdb);
296       return false;                   /* failed */
297    }
298
299    jr->VolSessionId = str_to_uint64(row[0]);
300    jr->VolSessionTime = str_to_uint64(row[1]);
301    jr->PoolId = str_to_int64(row[2]);
302    bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime));
303    bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime));
304    jr->JobFiles = str_to_int64(row[5]);
305    jr->JobBytes = str_to_int64(row[6]);
306    jr->JobTDate = str_to_int64(row[7]);
307    bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job));
308    jr->JobStatus = (int)*row[9];
309    jr->JobType = (int)*row[10];
310    jr->JobLevel = (int)*row[11];
311    jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)"");
312    bstrncpy(jr->Name, row[13]!=NULL?row[13]:"", sizeof(jr->Name));
313    jr->PriorJobId = str_to_uint64(row[14]!=NULL?row[14]:(char *)"");
314    bstrncpy(jr->cRealEndTime, row[15]!=NULL?row[15]:"", sizeof(jr->cRealEndTime));
315    if (jr->JobId == 0) {
316       jr->JobId = str_to_int64(row[16]);
317    }
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.
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, uint32_t PoolId, 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 MediaId FROM Media WHERE PoolId=%s", 
833        edit_int64(PoolId, ed1));
834    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
835       *num_ids = sql_num_rows(mdb);
836       if (*num_ids > 0) {
837          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
838          while ((row = sql_fetch_row(mdb)) != NULL) {
839             id[i++] = str_to_uint64(row[0]);
840          }
841          *ids = id;
842       }
843       sql_free_result(mdb);
844       ok = true;
845    } else {
846       Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
847       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
848       ok = false;
849    }
850    db_unlock(mdb);
851    return ok;
852 }
853
854
855 /* Get Media Record
856  *
857  * Returns: false: on failure
858  *          true:  on success
859  */
860 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
861 {
862    SQL_ROW row;
863    char ed1[50];
864    bool ok = false;
865
866    db_lock(mdb);
867    if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
868       Mmsg(mdb->cmd, "SELECT count(*) from Media");
869       mr->MediaId = get_sql_record_max(jcr, mdb);
870       db_unlock(mdb);
871       return true;
872    }
873    if (mr->MediaId != 0) {               /* find by id */
874       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
875          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
876          "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
877          "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
878          "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
879          "Enabled,LocationId,RecycleCount,InitialWrite,"
880          "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime "
881          "FROM Media WHERE MediaId=%s", 
882          edit_int64(mr->MediaId, ed1));
883    } else {                           /* find by name */
884       Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
885          "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
886          "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
887          "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
888          "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
889          "Enabled,LocationId,RecycleCount,InitialWrite,"
890          "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime "
891          "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
892    }
893
894    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
895       char ed1[50];
896       mdb->num_rows = sql_num_rows(mdb);
897       if (mdb->num_rows > 1) {
898          Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
899             edit_uint64(mdb->num_rows, ed1));
900          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
901       } else if (mdb->num_rows == 1) {
902          if ((row = sql_fetch_row(mdb)) == NULL) {
903             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
904             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
905          } else {
906             /* return values */
907             mr->MediaId = str_to_int64(row[0]);
908             bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
909             mr->VolJobs = str_to_int64(row[2]);
910             mr->VolFiles = str_to_int64(row[3]);
911             mr->VolBlocks = str_to_int64(row[4]);
912             mr->VolBytes = str_to_uint64(row[5]);
913             mr->VolMounts = str_to_int64(row[6]);
914             mr->VolErrors = str_to_int64(row[7]);
915             mr->VolWrites = str_to_int64(row[8]);
916             mr->MaxVolBytes = str_to_uint64(row[9]);
917             mr->VolCapacityBytes = str_to_uint64(row[10]);
918             bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
919             bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
920             mr->PoolId = str_to_int64(row[13]);
921             mr->VolRetention = str_to_uint64(row[14]);
922             mr->VolUseDuration = str_to_uint64(row[15]);
923             mr->MaxVolJobs = str_to_int64(row[16]);
924             mr->MaxVolFiles = str_to_int64(row[17]);
925             mr->Recycle = str_to_int64(row[18]);
926             mr->Slot = str_to_int64(row[19]);
927             bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
928             mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
929             bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
930             mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
931             mr->InChanger = str_to_uint64(row[22]);
932             mr->EndFile = str_to_uint64(row[23]);
933             mr->EndBlock = str_to_uint64(row[24]);
934             mr->VolParts = str_to_int64(row[25]);
935             mr->LabelType = str_to_int64(row[26]);
936             bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
937             mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
938             mr->StorageId = str_to_int64(row[28]);
939             mr->Enabled = str_to_int64(row[29]);
940             mr->LocationId = str_to_int64(row[30]);
941             mr->RecycleCount = str_to_int64(row[31]);
942             bstrncpy(mr->cInitialWrite, row[32]!=NULL?row[32]:"", sizeof(mr->cInitialWrite));
943             mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
944             mr->ScratchPoolId = str_to_int64(row[33]);
945             mr->RecyclePoolId = str_to_int64(row[34]);
946             mr->VolReadTime = str_to_int64(row[35]);
947             mr->VolWriteTime = str_to_int64(row[36]);
948             
949             ok = true;
950          }
951       } else {
952          if (mr->MediaId != 0) {
953             Mmsg1(mdb->errmsg, _("Media record MediaId=%s not found.\n"), 
954                edit_int64(mr->MediaId, ed1));
955          } else {
956             Mmsg1(mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"),
957                   mr->VolumeName);
958          }
959       }
960       sql_free_result(mdb);
961    } else {
962       if (mr->MediaId != 0) {
963          Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"),
964             mr->MediaId);
965        } else {
966          Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"),
967             mr->VolumeName);
968    }   }
969    db_unlock(mdb);
970    return ok;
971 }
972
973
974 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/