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