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