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