]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_get.c
First cut AutoPrune
[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, 2001, 2002 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, char *fname);
54 static int db_get_path_record(B_DB *mdb, char *path);
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
61
62 /*
63  * Given a full filename (with path), look up the File record
64  * (with attributes) in the database.
65  *
66  *  Returns: 0 on failure
67  *           1 on success with the File record in FILE_DBR
68  */
69 int db_get_file_attributes_record(B_DB *mdb, char *fname, FILE_DBR *fdbr)
70 {
71    int fnl, pnl;
72    char *l, *p;
73    uint64_t id;
74    char file[MAXSTRING];
75    char spath[MAXSTRING];
76    char buf[MAXSTRING];
77    Dmsg0(20, "get_file_from_catalog\n");
78
79    /* Find path without the filename */
80    for (p=l=fname; *p; p++) {
81       if (*p == '/') {
82          l = p;
83       }
84    }
85    if (*l == '/') {
86       l++;
87    }
88
89    fnl = p - l;
90    strcpy(file, l);
91
92    pnl = l - fname;    
93    strncpy(spath, fname, pnl);
94    spath[l-fname] = 0;
95
96    if (pnl == 0) {
97       return 0;
98    }
99
100    strip_trailing_junk(spath);
101    Dmsg1(50, "spath=%s\n", spath);
102
103    strip_trailing_junk(file);
104    Dmsg1(50, "file=%s\n", file);
105
106    db_escape_string(buf, file, fnl);
107    fdbr->FilenameId = db_get_filename_record(mdb, buf);
108    Dmsg1(50, "db_get_filename_record FilenameId=%d\n", fdbr->FilenameId);
109
110    db_escape_string(buf, spath, pnl);
111    fdbr->PathId = db_get_path_record(mdb, buf);
112    Dmsg1(50, "db_get_path_record PathId=%d\n", fdbr->PathId);
113
114    id = db_get_file_record(mdb, fdbr);
115
116    return id;
117 }
118
119  
120
121 /* Get a File record   
122  * Returns: 0 on failure
123  *          1 on success
124  */
125 static
126 int db_get_file_record(B_DB *mdb, FILE_DBR *fdbr)
127 {
128    SQL_ROW row;
129
130    P(mdb->mutex);
131    Mmsg(&mdb->cmd, 
132 "SELECT FileId, LStat, MD5 from File where File.JobId=%d and File.PathId=%d and \
133 File.FilenameId=%d", fdbr->JobId, fdbr->PathId, fdbr->FilenameId);
134
135    if (QUERY_DB(mdb, mdb->cmd)) {
136
137       mdb->num_rows = sql_num_rows(mdb);
138
139       /* 
140        * Note, we can find more than one File record with the same
141        *  filename if the file is linked.   ????????
142        */
143       if (mdb->num_rows > 1) {
144          Emsg1(M_WARNING, 0, _("get_file_record want 1 got rows=%d\n"), mdb->num_rows);
145          Emsg1(M_WARNING, 0, "%s\n", mdb->cmd);
146       }
147       if (mdb->num_rows >= 1) {
148          if ((row = sql_fetch_row(mdb)) == NULL) {
149             Emsg1(M_ERROR, 0, "Error fetching row: %s\n", sql_strerror(mdb));
150          } else {
151             fdbr->FileId = (FileId_t)strtod(row[0], NULL);
152             strncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
153             fdbr->LStat[sizeof(fdbr->LStat)] = 0;
154             strncpy(fdbr->MD5, row[2], sizeof(fdbr->MD5));
155             fdbr->MD5[sizeof(fdbr->MD5)] = 0;
156             sql_free_result(mdb);
157             V(mdb->mutex);
158             return 1;
159          }
160       }
161
162       sql_free_result(mdb);
163    }
164    V(mdb->mutex);
165    return 0;                          /* failed */
166
167 }
168
169 /* Get Filename record   
170  * Returns: 0 on failure
171  *          FilenameId on success
172  */
173 static int db_get_filename_record(B_DB *mdb, char *fname) 
174 {
175    SQL_ROW row;
176    int FilenameId;
177
178    if (*fname == 0) {
179       Mmsg0(&mdb->errmsg, _("Null name given to db_get_filename_record\n"));
180       Emsg0(M_ABORT, 0, mdb->errmsg);
181    }
182
183    P(mdb->mutex);
184    Mmsg(&mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name=\"%s\"", fname);
185    if (QUERY_DB(mdb, mdb->cmd)) {
186
187       mdb->num_rows = sql_num_rows(mdb);
188
189       if (mdb->num_rows > 1) {
190          Mmsg1(&mdb->errmsg, _("More than one Filename!: %d\n"), (int)(mdb->num_rows));
191          Emsg0(M_FATAL, 0, mdb->errmsg);
192       } else if (mdb->num_rows == 1) {
193          if ((row = sql_fetch_row(mdb)) == NULL) {
194             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
195             Emsg0(M_FATAL, 0, mdb->errmsg);
196          }
197          FilenameId = atoi(row[0]);
198          if (FilenameId <= 0) {
199             Mmsg2(&mdb->errmsg, _("Create db Filename record %s found bad record: %d\n"),
200                mdb->cmd, FilenameId); 
201             Emsg0(M_ERROR, 0, mdb->errmsg);
202          }
203          sql_free_result(mdb);
204          V(mdb->mutex);
205          return FilenameId;
206
207       }
208       sql_free_result(mdb);
209    }
210    V(mdb->mutex);
211    return 0;                          /* failed */
212 }
213
214 /* Get path record   
215  * Returns: 0 on failure
216  *          PathId on success
217  */
218 static int db_get_path_record(B_DB *mdb, char *path)
219 {
220    SQL_ROW row;
221    int PathId;
222    /*******FIXME***** move into mdb record and allocate */
223    static int cached_id = 0;
224    static char cached_path[MAXSTRING];
225
226    if (*path == 0) {
227       Emsg0(M_ABORT, 0, _("Null path given to db_get_path_record\n"));
228    }
229    if (cached_id != 0 && strcmp(cached_path, path) == 0) {
230       return cached_id;
231    }          
232
233    P(mdb->mutex);
234    Mmsg(&mdb->cmd, "SELECT PathId FROM Path WHERE Path=\"%s\"", path);
235
236    if (QUERY_DB(mdb, mdb->cmd)) {
237       char ed1[30];
238       mdb->num_rows = sql_num_rows(mdb);
239
240       if (mdb->num_rows > 1) {
241          Mmsg1(&mdb->errmsg, _("More than one Path!: %s\n"), 
242             edit_uint64(mdb->num_rows, ed1));
243          Emsg0(M_FATAL, 0, mdb->errmsg);
244       } else if (mdb->num_rows == 1) {
245          if ((row = sql_fetch_row(mdb)) == NULL) {
246             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
247             Emsg0(M_FATAL, 0, mdb->errmsg);
248          }
249          PathId = atoi(row[0]);
250          if (PathId != cached_id) {
251             cached_id = PathId;
252             strcpy(cached_path, path);
253          }
254          sql_free_result(mdb);
255          V(mdb->mutex);
256          return PathId;
257       }
258
259       sql_free_result(mdb);
260    }
261    V(mdb->mutex);
262    return 0;                          /* failed */
263 }
264
265
266 /* 
267  * Get Job record for given JobId or Job name
268  * Returns: 0 on failure
269  *          1 on success
270  */
271 int db_get_job_record(B_DB *mdb, JOB_DBR *jr)
272 {
273    SQL_ROW row;
274
275    P(mdb->mutex);
276    if (jr->JobId == 0) {
277       Mmsg(&mdb->cmd, "SELECT VolSessionId, VolSessionTime, \
278 PoolId, StartTime, EndTime, JobFiles, JobBytes, JobTDate, Job \
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 \
283 FROM Job WHERE JobId=%d", jr->JobId);
284     }
285
286    if (!QUERY_DB(mdb, mdb->cmd)) {
287       V(mdb->mutex);
288       return 0;                       /* failed */
289    }
290    if ((row = sql_fetch_row(mdb)) == NULL) {
291       Mmsg1(&mdb->errmsg, _("No Job found for JobId %d\n"), jr->JobId);
292       sql_free_result(mdb);
293       V(mdb->mutex);
294       return 0;                       /* failed */
295    }
296
297    jr->VolSessionId = atol(row[0]);
298    jr->VolSessionTime = atol(row[1]);
299    jr->PoolId = atoi(row[2]);
300    strcpy(jr->cStartTime, row[3]);
301    strcpy(jr->cEndTime, row[4]);
302    jr->JobFiles = atol(row[5]);
303    jr->JobBytes = (uint64_t)strtod(row[6], NULL);
304    jr->JobTDate = (btime_t)strtod(row[7], NULL);
305    strcpy(jr->Job, row[8]);
306    sql_free_result(mdb);
307
308    V(mdb->mutex);
309    return 1;
310 }
311
312 /*
313  * Find VolumeNames for a give JobId
314  *  Returns: 0 on error or no Volumes found
315  *           number of volumes on success
316  *              Volumes are concatenated in VolumeNames
317  *              separated by a vertical bar (|).
318  */
319 int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, char *VolumeNames)
320 {
321    SQL_ROW row;
322    int stat = 0;
323    int i;
324
325    P(mdb->mutex);
326    Mmsg(&mdb->cmd, 
327 "SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%d \
328 AND JobMedia.MediaId=Media.MediaId", JobId);
329
330    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
331    VolumeNames[0] = 0;
332    if (QUERY_DB(mdb, mdb->cmd)) {
333       mdb->num_rows = sql_num_rows(mdb);
334       Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
335       if (mdb->num_rows <= 0) {
336          Mmsg1(&mdb->errmsg, _("No volumes found for JobId=%d"), JobId);
337          stat = 0;
338       } else {
339          stat = mdb->num_rows;
340          for (i=0; i < stat; i++) {
341             if ((row = sql_fetch_row(mdb)) == NULL) {
342                Mmsg2(&mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
343                stat = 0;
344                break;
345             } else {
346                if (VolumeNames[0] != 0) {
347                   strcat(VolumeNames, "|");
348                }
349                strcat(VolumeNames, row[0]);
350             }
351          }
352       }
353       sql_free_result(mdb);
354    }
355    V(mdb->mutex);
356    return stat;
357 }
358
359
360 /* 
361  * Get the number of pool records
362  *
363  * Returns: -1 on failure
364  *          number on success
365  */
366 int db_get_num_pool_records(B_DB *mdb)
367 {
368    int stat = 0;
369
370    P(mdb->mutex);
371    Mmsg(&mdb->cmd, "SELECT count(*) from Pool");
372    stat = get_sql_record_max(mdb);
373    V(mdb->mutex);
374    return stat;
375 }
376
377 /*
378  * This function returns a list of all the Pool record ids.
379  *  The caller must free ids if non-NULL.
380  *
381  *  Returns 0: on failure
382  *          1: on success
383  */
384 int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
385 {
386    SQL_ROW row;
387    int stat = 0;
388    int i = 0;
389    uint32_t *id;
390
391    P(mdb->mutex);
392    *ids = NULL;
393    Mmsg(&mdb->cmd, "SELECT PoolId FROM Pool");
394    if (QUERY_DB(mdb, mdb->cmd)) {
395       *num_ids = sql_num_rows(mdb);
396       if (*num_ids > 0) {
397          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
398          while ((row = sql_fetch_row(mdb)) != NULL) {
399             id[i++] = (uint32_t)atoi(row[0]);
400          }
401          *ids = id;
402       }
403       sql_free_result(mdb);
404       stat = 1;
405    } else {
406       Mmsg(&mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
407       stat = 0;
408    }
409    V(mdb->mutex);
410    return stat;
411 }
412
413
414 /* Get Pool Record   
415  * If the PoolId is non-zero, we get its record,
416  *  otherwise, we search on the PoolName
417  *
418  * Returns: 0 on failure
419  *          id on success 
420  */
421 int db_get_pool_record(B_DB *mdb, POOL_DBR *pdbr)
422 {
423    SQL_ROW row;
424    int stat = 0;
425
426    P(mdb->mutex);
427    if (pdbr->PoolId != 0) {               /* find by id */
428       Mmsg(&mdb->cmd, 
429 "SELECT PoolId, Name, NumVols, MaxVols, UseOnce, UseCatalog, AcceptAnyVolume, \
430 AutoPrune, Recycle, VolRetention, \
431 PoolType, LabelFormat FROM Pool WHERE Pool.PoolId=%d", pdbr->PoolId);
432    } else {                           /* find by name */
433       Mmsg(&mdb->cmd, 
434 "SELECT PoolId, Name, NumVols, MaxVols, UseOnce, UseCatalog, AcceptAnyVolume, \
435 AutoPrune, Recycle, VolRetention, \
436 PoolType, LabelFormat FROM Pool WHERE Pool.Name=\"%s\"", pdbr->Name);
437    }  
438
439    if (QUERY_DB(mdb, mdb->cmd)) {
440       mdb->num_rows = sql_num_rows(mdb);
441       if (mdb->num_rows > 1) {
442          char ed1[30];
443          Mmsg1(&mdb->errmsg, _("More than one Pool!: %s\n"), 
444             edit_uint64(mdb->num_rows, ed1));
445          Emsg0(M_ERROR, 0, mdb->errmsg);
446       } else if (mdb->num_rows == 1) {
447          if ((row = sql_fetch_row(mdb)) == NULL) {
448             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
449             Emsg0(M_ERROR, 0, mdb->errmsg);
450          } else {
451             pdbr->PoolId = atoi(row[0]);
452             strcpy(pdbr->Name, row[1]);
453             pdbr->NumVols = atoi(row[2]);
454             pdbr->MaxVols = atoi(row[3]);
455             pdbr->UseOnce = atoi(row[4]);
456             pdbr->UseCatalog = atoi(row[5]);
457             pdbr->AcceptAnyVolume = atoi(row[6]);
458             pdbr->AutoPrune = atoi(row[7]);
459             pdbr->Recycle = atoi(row[8]);
460             pdbr->VolRetention = (btime_t)strtod(row[9], NULL);
461             strcpy(pdbr->PoolType, row[10]);
462             if (row[11]) {
463                strcpy(pdbr->LabelFormat, row[11]);
464             } else {
465                pdbr->LabelFormat[0] = 0;
466             }
467             stat = pdbr->PoolId;
468          }
469       }
470       sql_free_result(mdb);
471    }
472    V(mdb->mutex);
473    return stat;
474 }
475
476
477 /* 
478  * Get the number of Media records
479  *
480  * Returns: -1 on failure
481  *          number on success
482  */
483 int db_get_num_media_records(B_DB *mdb)
484 {
485    int stat = 0;
486
487    P(mdb->mutex);
488    Mmsg(&mdb->cmd, "SELECT count(*) from Media");
489    stat = get_sql_record_max(mdb);
490    V(mdb->mutex);
491    return stat;
492 }
493
494
495 /*
496  * This function returns a list of all the Media record ids.
497  *  The caller must free ids if non-NULL.
498  *
499  *  Returns 0: on failure
500  *          1: on success
501  */
502 int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
503 {
504    SQL_ROW row;
505    int stat = 0;
506    int i = 0;
507    uint32_t *id;
508
509    P(mdb->mutex);
510    *ids = NULL;
511    Mmsg(&mdb->cmd, "SELECT MediaId FROM Media");
512    if (QUERY_DB(mdb, mdb->cmd)) {
513       *num_ids = sql_num_rows(mdb);
514       if (*num_ids > 0) {
515          id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
516          while ((row = sql_fetch_row(mdb)) != NULL) {
517             id[i++] = (uint32_t)atoi(row[0]);
518          }
519          *ids = id;
520       }
521       sql_free_result(mdb);
522       stat = 1;
523    } else {
524       Mmsg(&mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
525       stat = 0;
526    }
527    V(mdb->mutex);
528    return stat;
529 }
530
531
532 /* Get Media Record   
533  *
534  * Returns: 0 on failure
535  *          id on success 
536  */
537 int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr)
538 {
539    SQL_ROW row;
540    int stat = 0;
541
542    P(mdb->mutex);
543    if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
544       Mmsg(&mdb->cmd, "SELECT count(*) from Media");
545       mr->MediaId = get_sql_record_max(mdb);
546       V(mdb->mutex);
547       return 1;
548    }
549    if (mr->MediaId != 0) {               /* find by id */
550       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
551 VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\
552 MediaType,VolStatus,PoolId,VoRetention,Recycle \
553 FROM Media WHERE MediaId=%d", mr->MediaId);
554    } else {                           /* find by name */
555       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
556 VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\
557 MediaType,VolStatus,PoolId,VolRetention,Recycle \
558 FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName);
559    }  
560
561    if (QUERY_DB(mdb, mdb->cmd)) {
562       mdb->num_rows = sql_num_rows(mdb);
563       if (mdb->num_rows > 1) {
564          char ed1[30];
565          Mmsg1(&mdb->errmsg, _("More than one Volume!: %s\n"), 
566             edit_uint64(mdb->num_rows, ed1));
567          Emsg0(M_ERROR, 0, mdb->errmsg);
568       } else if (mdb->num_rows == 1) {
569          if ((row = sql_fetch_row(mdb)) == NULL) {
570             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
571             Emsg0(M_ERROR, 0, mdb->errmsg);
572          } else {
573             /* return values */
574             mr->MediaId = atoi(row[0]);
575             strcpy(mr->VolumeName, row[1]);
576             mr->VolJobs = atoi(row[2]);
577             mr->VolFiles = atoi(row[3]);
578             mr->VolBlocks = atoi(row[4]);
579             mr->VolBytes = (uint64_t)strtod(row[5], NULL);
580             mr->VolMounts = atoi(row[6]);
581             mr->VolErrors = atoi(row[7]);
582             mr->VolWrites = atoi(row[8]);
583             mr->VolMaxBytes = (uint64_t)strtod(row[9], NULL);
584             mr->VolCapacityBytes = (uint64_t)strtod(row[10], NULL);
585             strcpy(mr->MediaType, row[11]);
586             strcpy(mr->VolStatus, row[12]);
587             mr->PoolId = atoi(row[13]);
588             mr->VolRetention = (btime_t)strtod(row[14], NULL);
589             mr->Recycle = atoi(row[15]);
590             stat = mr->MediaId;
591          }
592       } else {
593          Mmsg0(&mdb->errmsg, _("Media record not found.\n"));
594       }
595       sql_free_result(mdb);
596    }
597    V(mdb->mutex);
598    return stat;
599 }
600
601
602 #endif /* HAVE_MYSQL || HAVE_SQLITE */