]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_get.c
Fix escape_string buffer overflows
[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 /*
13    Copyright (C) 2000-2003 Kern Sibbald and John Walker
14
15    This program is free software; you can redistribute it and/or
16    modify it under the terms of the GNU General Public License as
17    published by the Free Software Foundation; either version 2 of
18    the License, or (at your option) any later version.
19
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23    General Public License for more details.
24
25    You should have received a copy of the GNU General Public
26    License along with this program; if not, write to the Free
27    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28    MA 02111-1307, USA.
29
30  */
31
32 /* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
33
34 /* The following is necessary so that we do not include
35  * the dummy external definition of DB.
36  */
37 #define __SQL_C                       /* indicate that this is sql.c */
38
39 #include "bacula.h"
40 #include "cats.h"
41
42 #if    HAVE_MYSQL || HAVE_SQLITE
43
44 /* -----------------------------------------------------------------------
45  *
46  *   Generic Routines (or almost generic)
47  *
48  * -----------------------------------------------------------------------
49  */
50
51 /* Forward referenced functions */
52 static int db_get_file_record(B_DB *mdb, FILE_DBR *fdbr);
53 static int db_get_filename_record(B_DB *mdb);
54 static int db_get_path_record(B_DB *mdb);
55
56
57 /* Imported subroutines */
58 extern void print_result(B_DB *mdb);
59 extern int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
60 extern void split_path_and_filename(B_DB *mdb, char *fname);
61
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(B_DB *mdb, char *fname, FILE_DBR *fdbr)
72 {
73    int stat;
74    Dmsg1(20, "Enter get_file_from_catalog fname=%s \n", fname);
75
76    db_lock(mdb);
77    split_path_and_filename(mdb, fname);
78
79    fdbr->FilenameId = db_get_filename_record(mdb);
80
81    fdbr->PathId = db_get_path_record(mdb);
82
83    stat = db_get_file_record(mdb, 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(B_DB *mdb, FILE_DBR *fdbr)
104 {
105    SQL_ROW row;
106    int stat = 0;
107
108    Mmsg(&mdb->cmd, 
109 "SELECT FileId, LStat, MD5 from File where File.JobId=%u and File.PathId=%u and \
110 File.FilenameId=%u", fdbr->JobId, fdbr->PathId, fdbr->FilenameId);
111
112    Dmsg3(050, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
113       fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
114       
115    Dmsg1(100, "Query=%s\n", mdb->cmd);
116
117    if (QUERY_DB(mdb, mdb->cmd)) {
118
119       mdb->num_rows = sql_num_rows(mdb);
120       Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows);
121
122       if (mdb->num_rows > 1) {
123          Mmsg1(&mdb->errmsg, _("get_file_record want 1 got rows=%d\n"),
124             mdb->num_rows);
125       }
126       if (mdb->num_rows >= 1) {
127          if ((row = sql_fetch_row(mdb)) == NULL) {
128             Mmsg1(&mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
129          } else {
130             fdbr->FileId = (FileId_t)str_to_int64(row[0]);
131             bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
132             bstrncpy(fdbr->MD5, row[2], sizeof(fdbr->MD5));
133             stat = 1;
134          }
135       } else {
136          Mmsg2(&mdb->errmsg, _("File record not found for PathId=%u FilenameId=%u\n"),
137             fdbr->PathId, fdbr->FilenameId);
138       }
139       sql_free_result(mdb);
140    }
141    return stat;
142
143 }
144
145 /* Get Filename record   
146  * Returns: 0 on failure
147  *          FilenameId on success
148  *
149  *   DO NOT use Jmsg in this routine (see notes for get_file_record)
150  */
151 static int db_get_filename_record(B_DB *mdb)
152 {
153    SQL_ROW row;
154    int FilenameId = 0;
155
156    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
157    db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl);
158    sm_check(__FILE__, __LINE__, True);
159    
160    Mmsg(&mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
161    if (QUERY_DB(mdb, mdb->cmd)) {
162
163       mdb->num_rows = sql_num_rows(mdb);
164
165       if (mdb->num_rows > 1) {
166          Mmsg1(&mdb->errmsg, _("More than one Filename!: %d\n"), (int)(mdb->num_rows));
167       }
168       if (mdb->num_rows >= 1) {
169          if ((row = sql_fetch_row(mdb)) == NULL) {
170             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
171          } else {
172             FilenameId = atoi(row[0]);
173             if (FilenameId <= 0) {
174                Mmsg2(&mdb->errmsg, _("Get DB Filename record %s found bad record: %d\n"),
175                   mdb->cmd, FilenameId); 
176                FilenameId = 0;
177             }
178          }
179       } else {
180          Mmsg1(&mdb->errmsg, _("Filename record: %s not found.\n"), mdb->fname);
181       }
182       sql_free_result(mdb);
183    }
184    return FilenameId;
185 }
186
187 /* Get path record   
188  * Returns: 0 on failure
189  *          PathId on success
190  *
191  *   DO NOT use Jmsg in this routine (see notes for get_file_record)
192  */
193 static int db_get_path_record(B_DB *mdb)
194 {
195    SQL_ROW row;
196    uint32_t PathId = 0;
197
198    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
199    db_escape_string(mdb->esc_name, mdb->path, mdb->pnl);
200    sm_check(__FILE__, __LINE__, True);
201
202    if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
203        strcmp(mdb->cached_path, mdb->path) == 0) {
204       return mdb->cached_path_id;
205    }          
206
207    Mmsg(&mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
208
209    if (QUERY_DB(mdb, mdb->cmd)) {
210       char ed1[30];
211       mdb->num_rows = sql_num_rows(mdb);
212
213       if (mdb->num_rows > 1) {
214          Mmsg1(&mdb->errmsg, _("More than one Path!: %s\n"), 
215             edit_uint64(mdb->num_rows, ed1));
216          Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
217       } else if (mdb->num_rows == 1) {
218          if ((row = sql_fetch_row(mdb)) == NULL) {
219             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
220          } else {
221             PathId = atoi(row[0]);
222             if (PathId <= 0) {
223                Mmsg2(&mdb->errmsg, _("Get DB path record %s found bad record: %u\n"),
224                   mdb->cmd, PathId); 
225                PathId = 0;
226             } else {
227                /* Cache path */
228                if (PathId != mdb->cached_path_id) {
229                   mdb->cached_path_id = PathId;
230                   mdb->cached_path_len = mdb->pnl;
231                   pm_strcpy(&mdb->cached_path, mdb->path);
232                }
233             }
234          }
235       } else {  
236          Mmsg1(&mdb->errmsg, _("Path record: %s not found.\n"), mdb->path);
237       }
238       sql_free_result(mdb);
239    }
240    return PathId;
241 }
242
243
244 /* 
245  * Get Job record for given JobId or Job name
246  * Returns: 0 on failure
247  *          1 on success
248  */
249 int db_get_job_record(B_DB *mdb, JOB_DBR *jr)
250 {
251    SQL_ROW row;
252
253    db_lock(mdb);
254    if (jr->JobId == 0) {
255       Mmsg(&mdb->cmd, "SELECT VolSessionId,VolSessionTime,\
256 PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,\
257 Type,Level \
258 FROM Job WHERE Job='%s'", jr->Job);
259     } else {
260       Mmsg(&mdb->cmd, "SELECT VolSessionId,VolSessionTime,\
261 PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,\
262 Type,Level \
263 FROM Job WHERE JobId=%u", jr->JobId);
264     }
265
266    if (!QUERY_DB(mdb, mdb->cmd)) {
267       db_unlock(mdb);
268       return 0;                       /* failed */
269    }
270    if ((row = sql_fetch_row(mdb)) == NULL) {
271       Mmsg1(&mdb->errmsg, _("No Job found for JobId %u\n"), jr->JobId);
272       sql_free_result(mdb);
273       db_unlock(mdb);
274       return 0;                       /* failed */
275    }
276
277    jr->VolSessionId = str_to_uint64(row[0]);
278    jr->VolSessionTime = str_to_uint64(row[1]);
279    jr->PoolId = atoi(row[2]);
280    bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime));
281    bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime));
282    jr->JobFiles = atol(row[5]);
283    jr->JobBytes = str_to_int64(row[6]);
284    jr->JobTDate = str_to_int64(row[7]);
285    bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job));
286    jr->JobStatus = (int)*row[9];
287    jr->Type = (int)*row[10];
288    jr->Level = (int)*row[11];
289    sql_free_result(mdb);
290
291    db_unlock(mdb);
292    return 1;
293 }
294
295 /*
296  * Find VolumeNames for a give JobId
297  *  Returns: 0 on error or no Volumes found
298  *           number of volumes on success
299  *              Volumes are concatenated in VolumeNames
300  *              separated by a vertical bar (|).
301  *
302  *  Returns: number of volumes on success
303  */
304 int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, POOLMEM **VolumeNames)
305 {
306    SQL_ROW row;
307    int stat = 0;
308    int i;
309
310    db_lock(mdb);
311    Mmsg(&mdb->cmd, 
312 "SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%u \
313 AND JobMedia.MediaId=Media.MediaId", JobId);
314
315    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
316    *VolumeNames[0] = 0;
317    if (QUERY_DB(mdb, mdb->cmd)) {
318       mdb->num_rows = sql_num_rows(mdb);
319       Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
320       if (mdb->num_rows <= 0) {
321          Mmsg1(&mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
322          stat = 0;
323       } else {
324          stat = mdb->num_rows;
325          for (i=0; i < stat; i++) {
326             if ((row = sql_fetch_row(mdb)) == NULL) {
327                Mmsg2(&mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
328                Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
329                stat = 0;
330                break;
331             } else {
332                if (*VolumeNames[0] != 0) {
333                   pm_strcat(VolumeNames, "|");
334                }
335                pm_strcat(VolumeNames, row[0]);
336             }
337          }
338       }
339       sql_free_result(mdb);
340    }
341    db_unlock(mdb);
342    return stat;
343 }
344
345 /*
346  * Find Volume parameters for a give JobId
347  *  Returns: 0 on error or no Volumes found
348  *           number of volumes on success
349  *           List of Volumes and start/end file/blocks (malloced structure!)
350  *
351  *  Returns: number of volumes on success
352  */
353 int db_get_job_volume_parameters(B_DB *mdb, uint32_t JobId, VOL_PARAMS **VolParams)
354 {
355    SQL_ROW row;
356    int stat = 0;
357    int i;
358    VOL_PARAMS *Vols = NULL;
359
360    db_lock(mdb);
361    Mmsg(&mdb->cmd, 
362 "SELECT VolumeName,FirstIndex,LastIndex,StartFile,EndFile,StartBlock,EndBlock"
363 " FROM JobMedia,Media WHERE JobMedia.JobId=%u"
364 " AND JobMedia.MediaId=Media.MediaId", JobId);
365
366    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
367    if (QUERY_DB(mdb, mdb->cmd)) {
368       mdb->num_rows = sql_num_rows(mdb);
369       Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
370       if (mdb->num_rows <= 0) {
371          Mmsg1(&mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
372          stat = 0;
373       } else {
374          stat = mdb->num_rows;
375          if (stat > 0) {
376             *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
377          }
378          for (i=0; i < stat; i++) {
379             if ((row = sql_fetch_row(mdb)) == NULL) {
380                Mmsg2(&mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
381                Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
382                stat = 0;
383                break;
384             } else {
385                bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH);
386                Vols[i].FirstIndex = atoi(row[1]);
387                Vols[i].LastIndex = atoi(row[2]);
388                Vols[i].StartFile = atoi(row[3]);
389                Vols[i].EndFile = atoi(row[4]);
390                Vols[i].StartBlock = atoi(row[5]);
391                Vols[i].EndBlock = atoi(row[6]);
392             }
393          }
394       }
395       sql_free_result(mdb);
396    }
397    db_unlock(mdb);
398    return stat;
399 }
400
401
402
403 /* 
404  * Get the number of pool records
405  *
406  * Returns: -1 on failure
407  *          number on success
408  */
409 int db_get_num_pool_records(B_DB *mdb)
410 {
411    int stat = 0;
412
413    db_lock(mdb);
414    Mmsg(&mdb->cmd, "SELECT count(*) from Pool");
415    stat = get_sql_record_max(mdb);
416    db_unlock(mdb);
417    return stat;
418 }
419
420 /*
421  * This function returns a list of all the Pool record ids.
422  *  The caller must free ids if non-NULL.
423  *
424  *  Returns 0: on failure
425  *          1: on success
426  */
427 int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
428 {
429    SQL_ROW row;
430    int stat = 0;
431    int i = 0;
432    uint32_t *id;
433
434    db_lock(mdb);
435    *ids = NULL;
436    Mmsg(&mdb->cmd, "SELECT PoolId FROM Pool");
437    if (QUERY_DB(mdb, mdb->cmd)) {
438       *num_ids = sql_num_rows(mdb);
439       if (*num_ids > 0) {
440          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
441          while ((row = sql_fetch_row(mdb)) != NULL) {
442             id[i++] = (uint32_t)atoi(row[0]);
443          }
444          *ids = id;
445       }
446       sql_free_result(mdb);
447       stat = 1;
448    } else {
449       Mmsg(&mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
450       Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
451       stat = 0;
452    }
453    db_unlock(mdb);
454    return stat;
455 }
456
457 /*
458  * This function returns a list of all the Client record ids.
459  *  The caller must free ids if non-NULL.
460  *
461  *  Returns 0: on failure
462  *          1: on success
463  */
464 int db_get_client_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
465 {
466    SQL_ROW row;
467    int stat = 0;
468    int i = 0;
469    uint32_t *id;
470
471    db_lock(mdb);
472    *ids = NULL;
473    Mmsg(&mdb->cmd, "SELECT ClientId FROM Client");
474    if (QUERY_DB(mdb, mdb->cmd)) {
475       *num_ids = sql_num_rows(mdb);
476       if (*num_ids > 0) {
477          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
478          while ((row = sql_fetch_row(mdb)) != NULL) {
479             id[i++] = (uint32_t)atoi(row[0]);
480          }
481          *ids = id;
482       }
483       sql_free_result(mdb);
484       stat = 1;
485    } else {
486       Mmsg(&mdb->errmsg, _("Client id select failed: ERR=%s\n"), sql_strerror(mdb));
487       Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
488       stat = 0;
489    }
490    db_unlock(mdb);
491    return stat;
492 }
493
494
495
496 /* Get Pool Record   
497  * If the PoolId is non-zero, we get its record,
498  *  otherwise, we search on the PoolName
499  *
500  * Returns: 0 on failure
501  *          id on success 
502  */
503 int db_get_pool_record(B_DB *mdb, POOL_DBR *pdbr)
504 {
505    SQL_ROW row;
506    int stat = 0;
507
508    db_lock(mdb);
509    if (pdbr->PoolId != 0) {               /* find by id */
510       Mmsg(&mdb->cmd, 
511 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,\
512 AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,\
513 MaxVolBytes,PoolType,LabelFormat FROM Pool WHERE Pool.PoolId=%u", pdbr->PoolId);
514    } else {                           /* find by name */
515       Mmsg(&mdb->cmd, 
516 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,\
517 AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,\
518 MaxVolBytes,PoolType,LabelFormat FROM Pool WHERE Pool.Name='%s'", pdbr->Name);
519    }  
520
521    if (QUERY_DB(mdb, mdb->cmd)) {
522       mdb->num_rows = sql_num_rows(mdb);
523       if (mdb->num_rows > 1) {
524          char ed1[30];
525          Mmsg1(&mdb->errmsg, _("More than one Pool!: %s\n"), 
526             edit_uint64(mdb->num_rows, ed1));
527          Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
528       } else if (mdb->num_rows == 1) {
529          if ((row = sql_fetch_row(mdb)) == NULL) {
530             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
531             Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
532          } else {
533             pdbr->PoolId = str_to_int64(row[0]);
534             bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name));
535             pdbr->NumVols = str_to_int64(row[2]);
536             pdbr->MaxVols = str_to_int64(row[3]);
537             pdbr->UseOnce = str_to_int64(row[4]);
538             pdbr->UseCatalog = str_to_int64(row[5]);
539             pdbr->AcceptAnyVolume = str_to_int64(row[6]);
540             pdbr->AutoPrune = str_to_int64(row[7]);
541             pdbr->Recycle = str_to_int64(row[8]);
542             pdbr->VolRetention = str_to_int64(row[9]);
543             pdbr->VolUseDuration = str_to_int64(row[10]);
544             pdbr->MaxVolJobs = str_to_int64(row[11]);
545             pdbr->MaxVolFiles = str_to_int64(row[12]);
546             pdbr->MaxVolBytes = str_to_uint64(row[13]);
547             bstrncpy(pdbr->PoolType, row[13]!=NULL?row[14]:"", sizeof(pdbr->PoolType));
548             bstrncpy(pdbr->LabelFormat, row[14]!=NULL?row[15]:"", sizeof(pdbr->LabelFormat));
549             stat = pdbr->PoolId;
550          }
551       }
552       sql_free_result(mdb);
553    }
554    db_unlock(mdb);
555    return stat;
556 }
557
558 /* Get Client Record   
559  * If the ClientId is non-zero, we get its record,
560  *  otherwise, we search on the Client Name
561  *
562  * Returns: 0 on failure
563  *          1 on success 
564  */
565 int db_get_client_record(B_DB *mdb, CLIENT_DBR *cdbr)
566 {
567    SQL_ROW row;
568    int stat = 0;
569
570    db_lock(mdb);
571    if (cdbr->ClientId != 0) {               /* find by id */
572       Mmsg(&mdb->cmd, 
573 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
574 "FROM Client WHERE Client.ClientId=%u", cdbr->ClientId);
575    } else {                           /* find by name */
576       Mmsg(&mdb->cmd, 
577 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
578 "FROM Client WHERE Client.Name='%s'", cdbr->Name);
579    }  
580
581    if (QUERY_DB(mdb, mdb->cmd)) {
582       mdb->num_rows = sql_num_rows(mdb);
583       if (mdb->num_rows > 1) {
584          char ed1[30];
585          Mmsg1(&mdb->errmsg, _("More than one Client!: %s\n"), 
586             edit_uint64(mdb->num_rows, ed1));
587          Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
588       } else if (mdb->num_rows == 1) {
589          if ((row = sql_fetch_row(mdb)) == NULL) {
590             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
591             Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
592          } else {
593             cdbr->ClientId = str_to_int64(row[0]);
594             bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name));
595             bstrncpy(cdbr->Uname, row[2]!=NULL?row[1]:"", sizeof(cdbr->Uname));
596             cdbr->AutoPrune = str_to_int64(row[3]);
597             cdbr->FileRetention = str_to_int64(row[4]);
598             cdbr->JobRetention = str_to_int64(row[5]);
599             stat = 1;
600          }
601       }
602       sql_free_result(mdb);
603    }
604    db_unlock(mdb);
605    return stat;
606 }
607
608
609 /* Get FileSet Record   
610  * If the FileSetId is non-zero, we get its record,
611  *  otherwise, we search on the name
612  *
613  * Returns: 0 on failure
614  *          id on success 
615  */
616 int db_get_fileset_record(B_DB *mdb, FILESET_DBR *fsr)
617 {
618    SQL_ROW row;
619    int stat = 0;
620
621    db_lock(mdb);
622    if (fsr->FileSetId != 0) {               /* find by id */
623       Mmsg(&mdb->cmd, 
624            "SELECT FileSetId, FileSet, MD5 FROM FileSet "
625            "WHERE FileSetId=%u", fsr->FileSetId);
626    } else {                           /* find by name */
627       Mmsg(&mdb->cmd, 
628            "SELECT FileSetId, FileSet, MD5 FROM FileSet "
629            "WHERE FileSet='%s'", fsr->FileSet);
630    }  
631
632    if (QUERY_DB(mdb, mdb->cmd)) {
633       mdb->num_rows = sql_num_rows(mdb);
634       if (mdb->num_rows > 1) {
635          char ed1[30];
636          Mmsg1(&mdb->errmsg, _("Error got %s FileSets but expected only one!\n"), 
637             edit_uint64(mdb->num_rows, ed1));
638          sql_data_seek(mdb, mdb->num_rows-1);
639       }
640       if ((row = sql_fetch_row(mdb)) == NULL) {
641          Mmsg1(&mdb->errmsg, _("Error: FileSet record \"%s\" not found\n"), fsr->FileSet);
642       } else {
643          fsr->FileSetId = atoi(row[0]);
644          bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
645          bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
646          stat = fsr->FileSetId;
647       }
648       sql_free_result(mdb);
649    }
650    db_unlock(mdb);
651    return stat;
652 }
653
654
655 /* 
656  * Get the number of Media records
657  *
658  * Returns: -1 on failure
659  *          number on success
660  */
661 int db_get_num_media_records(B_DB *mdb)
662 {
663    int stat = 0;
664
665    db_lock(mdb);
666    Mmsg(&mdb->cmd, "SELECT count(*) from Media");
667    stat = get_sql_record_max(mdb);
668    db_unlock(mdb);
669    return stat;
670 }
671
672
673 /*
674  * This function returns a list of all the Media record ids.
675  *  The caller must free ids if non-NULL.
676  *
677  *  Returns 0: on failure
678  *          1: on success
679  */
680 int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
681 {
682    SQL_ROW row;
683    int stat = 0;
684    int i = 0;
685    uint32_t *id;
686
687    db_lock(mdb);
688    *ids = NULL;
689    Mmsg(&mdb->cmd, "SELECT MediaId FROM Media");
690    if (QUERY_DB(mdb, mdb->cmd)) {
691       *num_ids = sql_num_rows(mdb);
692       if (*num_ids > 0) {
693          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
694          while ((row = sql_fetch_row(mdb)) != NULL) {
695             id[i++] = (uint32_t)atoi(row[0]);
696          }
697          *ids = id;
698       }
699       sql_free_result(mdb);
700       stat = 1;
701    } else {
702       Mmsg(&mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
703       Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
704       stat = 0;
705    }
706    db_unlock(mdb);
707    return stat;
708 }
709
710
711 /* Get Media Record   
712  *
713  * Returns: 0 on failure
714  *          id on success 
715  */
716 int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr)
717 {
718    SQL_ROW row;
719    int stat = 0;
720
721    db_lock(mdb);
722    if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
723       Mmsg(&mdb->cmd, "SELECT count(*) from Media");
724       mr->MediaId = get_sql_record_max(mdb);
725       db_unlock(mdb);
726       return 1;
727    }
728    if (mr->MediaId != 0) {               /* find by id */
729       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
730 VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,\
731 MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,\
732 Recycle,Slot,FirstWritten,LastWritten \
733 FROM Media WHERE MediaId=%d", mr->MediaId);
734    } else {                           /* find by name */
735       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
736 VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,\
737 MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,\
738 Recycle,Slot,FirstWritten,LastWritten \
739 FROM Media WHERE VolumeName='%s'", mr->VolumeName);
740    }  
741
742    if (QUERY_DB(mdb, mdb->cmd)) {
743       mdb->num_rows = sql_num_rows(mdb);
744       if (mdb->num_rows > 1) {
745          char ed1[30];
746          Mmsg1(&mdb->errmsg, _("More than one Volume!: %s\n"), 
747             edit_uint64(mdb->num_rows, ed1));
748          Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
749       } else if (mdb->num_rows == 1) {
750          if ((row = sql_fetch_row(mdb)) == NULL) {
751             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
752             Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg);
753          } else {
754             /* return values */
755             mr->MediaId = str_to_int64(row[0]);
756             bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
757             mr->VolJobs = str_to_int64(row[2]);
758             mr->VolFiles = str_to_int64(row[3]);
759             mr->VolBlocks = str_to_int64(row[4]);
760             mr->VolBytes = str_to_uint64(row[5]);
761             mr->VolMounts = str_to_int64(row[6]);
762             mr->VolErrors = str_to_int64(row[7]);
763             mr->VolWrites = str_to_int64(row[8]);
764             mr->MaxVolBytes = str_to_uint64(row[9]);
765             mr->VolCapacityBytes = str_to_uint64(row[10]);
766             bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
767             bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
768             mr->PoolId = str_to_int64(row[13]);
769             mr->VolRetention = str_to_uint64(row[14]);
770             mr->VolUseDuration = str_to_uint64(row[15]);
771             mr->MaxVolJobs = str_to_int64(row[16]);
772             mr->MaxVolFiles = str_to_int64(row[17]);
773             mr->Recycle = str_to_int64(row[18]);
774             mr->Slot = str_to_int64(row[19]);
775             bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
776             mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
777             bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
778             mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
779             stat = mr->MediaId;
780          }
781       } else {
782          Mmsg0(&mdb->errmsg, _("Media record not found.\n"));
783       }
784       sql_free_result(mdb);
785    }
786    db_unlock(mdb);
787    return stat;
788 }
789
790
791 #endif /* HAVE_MYSQL || HAVE_SQLITE */