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