]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_list.c
4942ca7940ac6f8be9b2452d870339f144078c0b
[bacula/bacula] / bacula / src / cats / sql_list.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 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 Kern Sibbald.
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 List records interface routines
30  *
31  *    Kern Sibbald, March 2000
32  *
33  *    Version $Id: sql_list.c 8508 2009-03-07 20:59:46Z kerns $
34  */
35
36
37 /* The following is necessary so that we do not include
38  * the dummy external definition of DB.
39  */
40 #define __SQL_C                       /* indicate that this is sql.c */
41
42 #include "bacula.h"
43 #include "cats.h"
44
45 extern int db_type;
46
47 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
48
49 /* -----------------------------------------------------------------------
50  *
51  *   Generic Routines (or almost generic)
52  *
53  * -----------------------------------------------------------------------
54  */
55
56 /*
57  * Submit general SQL query
58  */
59 int db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query, DB_LIST_HANDLER *sendit,
60                       void *ctx, int verbose, e_list_type type)
61 {
62    db_lock(mdb);
63    if (sql_query(mdb, query) != 0) {
64       Mmsg(mdb->errmsg, _("Query failed: %s\n"), sql_strerror(mdb));
65       if (verbose) {
66          sendit(ctx, mdb->errmsg);
67       }
68       db_unlock(mdb);
69       return 0;
70    }
71
72    mdb->result = sql_store_result(mdb);
73
74    if (mdb->result) {
75       list_result(jcr, mdb, sendit, ctx, type);
76       sql_free_result(mdb);
77    }
78    db_unlock(mdb);
79    return 1;
80 }
81
82 void
83 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
84                      DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
85 {
86    db_lock(mdb);
87    if (type == VERT_LIST) {
88       if (pdbr->Name[0] != 0) {
89          Mmsg(mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,"
90             "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes,"
91             "AutoPrune,Recycle,PoolType,LabelFormat,Enabled,ScratchPoolId,"
92             "RecyclePoolId,LabelType "
93             " FROM Pool WHERE Name='%s'", pdbr->Name);
94       } else {
95          Mmsg(mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,"
96             "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes,"
97             "AutoPrune,Recycle,PoolType,LabelFormat,Enabled,ScratchPoolId,"
98             "RecyclePoolId,LabelType "
99             " FROM Pool ORDER BY PoolId");
100       }
101    } else {
102       if (pdbr->Name[0] != 0) {
103          Mmsg(mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat "
104            "FROM Pool WHERE Name='%s'", pdbr->Name);
105       } else {
106          Mmsg(mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat "
107            "FROM Pool ORDER BY PoolId");
108       }
109    }
110
111    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
112       db_unlock(mdb);
113       return;
114    }
115
116    list_result(jcr, mdb, sendit, ctx, type);
117
118    sql_free_result(mdb);
119    db_unlock(mdb);
120 }
121
122 void
123 db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
124 {
125    db_lock(mdb);
126    if (type == VERT_LIST) {
127       Mmsg(mdb->cmd, "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,"
128          "JobRetention "
129          "FROM Client ORDER BY ClientId");
130    } else {
131       Mmsg(mdb->cmd, "SELECT ClientId,Name,FileRetention,JobRetention "
132          "FROM Client ORDER BY ClientId");
133    }
134
135    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
136       db_unlock(mdb);
137       return;
138    }
139
140    list_result(jcr, mdb, sendit, ctx, type);
141
142    sql_free_result(mdb);
143    db_unlock(mdb);
144 }
145
146
147 /*
148  * If VolumeName is non-zero, list the record for that Volume
149  *   otherwise, list the Volumes in the Pool specified by PoolId
150  */
151 void
152 db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
153                       DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
154 {
155    char ed1[50];
156    db_lock(mdb);
157    if (type == VERT_LIST) {
158       if (mdbr->VolumeName[0] != 0) {
159          Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId,"
160             "MediaType,FirstWritten,LastWritten,LabelDate,VolJobs,"
161             "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites,"
162             "VolCapacityBytes,VolStatus,Enabled,Recycle,VolRetention,"
163             "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
164             "EndFile,EndBlock,VolParts,LabelType,StorageId,DeviceId,"
165             "LocationId,RecycleCount,InitialWrite,ScratchPoolId,RecyclePoolId, "
166             "Comment"
167             " FROM Media WHERE Media.VolumeName='%s'", mdbr->VolumeName);
168       } else {
169          Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId,"
170             "MediaType,FirstWritten,LastWritten,LabelDate,VolJobs,"
171             "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites,"
172             "VolCapacityBytes,VolStatus,Enabled,Recycle,VolRetention,"
173             "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
174             "EndFile,EndBlock,VolParts,LabelType,StorageId,DeviceId,"
175             "LocationId,RecycleCount,InitialWrite,ScratchPoolId,RecyclePoolId, "
176             "Comment"
177             " FROM Media WHERE Media.PoolId=%s ORDER BY MediaId",
178             edit_int64(mdbr->PoolId, ed1));
179       }
180    } else {
181       if (mdbr->VolumeName[0] != 0) {
182          Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolStatus,Enabled,"
183             "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten "
184             "FROM Media WHERE Media.VolumeName='%s'", mdbr->VolumeName);
185       } else {
186          Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolStatus,Enabled,"
187             "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten "
188             "FROM Media WHERE Media.PoolId=%s ORDER BY MediaId",
189             edit_int64(mdbr->PoolId, ed1));
190       }
191    }
192
193    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
194       db_unlock(mdb);
195       return;
196    }
197
198    list_result(jcr, mdb, sendit, ctx, type);
199
200    sql_free_result(mdb);
201    db_unlock(mdb);
202 }
203
204 void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
205                               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
206 {
207    char ed1[50];
208    db_lock(mdb);
209    if (type == VERT_LIST) {
210       if (JobId > 0) {                   /* do by JobId */
211          Mmsg(mdb->cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
212             "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
213             "JobMedia.EndBlock "
214             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
215             "AND JobMedia.JobId=%s", edit_int64(JobId, ed1));
216       } else {
217          Mmsg(mdb->cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
218             "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
219             "JobMedia.EndBlock "
220             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId");
221       }
222
223    } else {
224       if (JobId > 0) {                   /* do by JobId */
225          Mmsg(mdb->cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
226             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
227             "AND JobMedia.JobId=%s", edit_int64(JobId, ed1));
228       } else {
229          Mmsg(mdb->cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
230             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId");
231       }
232    }
233    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
234       db_unlock(mdb);
235       return;
236    }
237
238    list_result(jcr, mdb, sendit, ctx, type);
239
240    sql_free_result(mdb);
241    db_unlock(mdb);
242 }
243
244
245 void db_list_copies_records(JCR *jcr, B_DB *mdb, uint32_t limit, char *JobIds,
246                             DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
247 {
248    POOL_MEM str_limit(PM_MESSAGE);
249    POOL_MEM str_jobids(PM_MESSAGE);
250
251    if (limit > 0) {
252 #if HAVE_INGRES
253       Mmsg(str_limit, " FETCH FIRST %d ROWS ONLY", limit);
254 #else
255       Mmsg(str_limit, " LIMIT %d", limit);
256 #endif
257    }
258
259    if (JobIds && JobIds[0]) {
260       Mmsg(str_jobids, " AND (Job.PriorJobId IN (%s) OR Job.JobId IN (%s)) ", 
261            JobIds, JobIds);      
262    }
263
264    db_lock(mdb);
265    Mmsg(mdb->cmd, 
266    "SELECT DISTINCT Job.PriorJobId AS JobId, Job.Job, "
267                    "Job.JobId AS CopyJobId, Media.MediaType "
268      "FROM Job " 
269      "JOIN JobMedia USING (JobId) "
270      "JOIN Media    USING (MediaId) "
271     "WHERE Job.Type = '%c' %s ORDER BY Job.PriorJobId DESC %s",
272         (char) JT_JOB_COPY, str_jobids.c_str(), str_limit.c_str());
273
274    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
275       goto bail_out;
276    }
277
278    if (mdb->result && sql_num_rows(mdb)) {
279       if (JobIds && JobIds[0]) {
280          sendit(ctx, _("These JobIds have copies as follows:\n"));
281       } else {
282          sendit(ctx, _("The catalog contains copies as follows:\n"));
283       }
284
285       list_result(jcr, mdb, sendit, ctx, type);
286    }
287
288    sql_free_result(mdb);
289
290 bail_out:
291    db_unlock(mdb);
292 }
293
294 void db_list_joblog_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
295                               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
296 {
297    char ed1[50];
298
299    if (JobId <= 0) {
300       return;
301    }
302    db_lock(mdb);
303    if (type == VERT_LIST) {
304       Mmsg(mdb->cmd, "SELECT Time,LogText FROM Log "
305            "WHERE Log.JobId=%s", edit_int64(JobId, ed1));
306    } else {
307       Mmsg(mdb->cmd, "SELECT LogText FROM Log "
308            "WHERE Log.JobId=%s", edit_int64(JobId, ed1));
309    }
310    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
311       goto bail_out;
312    }
313
314    list_result(jcr, mdb, sendit, ctx, type);
315
316    sql_free_result(mdb);
317
318 bail_out:
319    db_unlock(mdb);
320 }
321
322
323 /*
324  * List Job record(s) that match JOB_DBR
325  *
326  *  Currently, we return all jobs or if jr->JobId is set,
327  *  only the job with the specified id.
328  */
329 void
330 db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
331                     void *ctx, e_list_type type)
332 {
333    char ed1[50];
334    char limit[100];
335    db_lock(mdb);
336    if (jr->limit > 0) {
337 #if HAVE_INGRES
338       snprintf(limit, sizeof(limit), " FETCH FIRST %d ROWS ONLY", jr->limit);
339 #else
340       snprintf(limit, sizeof(limit), " LIMIT %d", jr->limit);
341 #endif
342    } else {
343       limit[0] = 0;
344    }
345    if (type == VERT_LIST) {
346       if (jr->JobId == 0 && jr->Job[0] == 0) {
347          Mmsg(mdb->cmd,
348             "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level,"
349             "Job.ClientId,Client.Name as ClientName,JobStatus,SchedTime,"
350             "StartTime,EndTime,RealEndTime,JobTDate,"
351             "VolSessionId,VolSessionTime,JobFiles,JobErrors,"
352             "JobMissingFiles,Job.PoolId,Pool.Name as PooLname,PriorJobId,"
353             "Job.FileSetId,FileSet.FileSet "
354             "FROM Job,Client,Pool,FileSet WHERE "
355             "Client.ClientId=Job.ClientId AND Pool.PoolId=Job.PoolId "
356             "AND FileSet.FileSetId=Job.FileSetId  ORDER BY StartTime%s", limit);
357       } else {                           /* single record */
358          Mmsg(mdb->cmd,
359             "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level,"
360             "Job.ClientId,Client.Name,JobStatus,SchedTime,"
361             "StartTime,EndTime,RealEndTime,JobTDate,"
362             "VolSessionId,VolSessionTime,JobFiles,JobErrors,"
363             "JobMissingFiles,Job.PoolId,Pool.Name as PooLname,PriorJobId,"
364             "Job.FileSetId,FileSet.FileSet "
365             "FROM Job,Client,Pool,FileSet WHERE Job.JobId=%s AND "
366             "Client.ClientId=Job.ClientId AND Pool.PoolId=Job.PoolId "
367             "AND FileSet.FileSetId=Job.FileSetId",
368             edit_int64(jr->JobId, ed1));
369       }
370    } else {
371       if (jr->Name[0] != 0) {
372          Mmsg(mdb->cmd,
373             "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
374             "FROM Job WHERE Name='%s' ORDER BY StartTime,JobId ASC", jr->Name);
375       } else if (jr->Job[0] != 0) {
376          Mmsg(mdb->cmd,
377             "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
378             "FROM Job WHERE Job='%s' ORDER BY StartTime,JobId ASC", jr->Job);
379       } else if (jr->JobId != 0) {
380          Mmsg(mdb->cmd,
381             "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
382             "FROM Job WHERE JobId=%s", edit_int64(jr->JobId, ed1));
383       } else {                           /* all records */
384          Mmsg(mdb->cmd,
385            "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
386            "FROM Job ORDER BY StartTime,JobId ASC%s", limit);
387       }
388    }
389    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
390       db_unlock(mdb);
391       return;
392    }
393    list_result(jcr, mdb, sendit, ctx, type);
394
395    sql_free_result(mdb);
396    db_unlock(mdb);
397 }
398
399 /*
400  * List Job totals
401  *
402  */
403 void
404 db_list_job_totals(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
405 {
406    db_lock(mdb);
407
408    /* List by Job */
409    Mmsg(mdb->cmd, "SELECT  count(*) AS Jobs,sum(JobFiles) "
410       "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name");
411
412    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
413       db_unlock(mdb);
414       return;
415    }
416
417    list_result(jcr, mdb, sendit, ctx, HORZ_LIST);
418
419    sql_free_result(mdb);
420
421    /* Do Grand Total */
422    Mmsg(mdb->cmd, "SELECT count(*) AS Jobs,sum(JobFiles) "
423         "AS Files,sum(JobBytes) As Bytes FROM Job");
424
425    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
426       db_unlock(mdb);
427       return;
428    }
429
430    list_result(jcr, mdb, sendit, ctx, HORZ_LIST);
431
432    sql_free_result(mdb);
433    db_unlock(mdb);
434 }
435
436 void
437 db_list_files_for_job(JCR *jcr, B_DB *mdb, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
438 {
439    char ed1[50];
440    db_lock(mdb);
441
442    /*
443     * Stupid MySQL is NON-STANDARD !
444     */
445    if (db_type == SQL_TYPE_MYSQL) {
446       Mmsg(mdb->cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
447            "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s "
448                   "UNION ALL "
449                  "SELECT PathId, FilenameId "
450                    "FROM BaseFiles JOIN File "
451                          "ON (BaseFiles.FileId = File.FileId) "
452                   "WHERE BaseFiles.JobId = %s"
453            ") AS F, Filename,Path "
454            "WHERE Filename.FilenameId=F.FilenameId "
455            "AND Path.PathId=F.PathId",
456            edit_int64(jobid, ed1), ed1);
457    } else {
458       Mmsg(mdb->cmd, "SELECT Path.Path||Filename.Name AS Filename "
459            "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s "
460                   "UNION ALL "
461                  "SELECT PathId, FilenameId "
462                    "FROM BaseFiles JOIN File "
463                          "ON (BaseFiles.FileId = File.FileId) "
464                   "WHERE BaseFiles.JobId = %s"
465            ") AS F, Filename,Path "
466            "WHERE Filename.FilenameId=F.FilenameId "
467            "AND Path.PathId=F.PathId",
468            edit_int64(jobid, ed1), ed1);
469    }
470
471    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
472       db_unlock(mdb);
473       return;
474    }
475
476    list_result(jcr, mdb, sendit, ctx, HORZ_LIST);
477
478    sql_free_result(mdb);
479    db_unlock(mdb);
480 }
481
482 void
483 db_list_base_files_for_job(JCR *jcr, B_DB *mdb, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
484 {
485    char ed1[50];
486    db_lock(mdb);
487
488    /*
489     * Stupid MySQL is NON-STANDARD !
490     */
491    if (db_type == SQL_TYPE_MYSQL) {
492       Mmsg(mdb->cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
493            "FROM BaseFiles, File, Filename, Path "
494            "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
495            "AND BaseFiles.FileId = File.FileId "
496            "AND Filename.FilenameId=File.FilenameId "
497            "AND Path.PathId=File.PathId",
498          edit_int64(jobid, ed1));
499    } else {
500       Mmsg(mdb->cmd, "SELECT Path.Path||Filename.Name AS Filename "
501            "FROM BaseFiles, File, Filename, Path "
502            "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
503            "AND BaseFiles.FileId = File.FileId "
504            "AND Filename.FilenameId=File.FilenameId "
505            "AND Path.PathId=File.PathId",
506            edit_int64(jobid, ed1));
507    }
508
509    if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
510       db_unlock(mdb);
511       return;
512    }
513
514    list_result(jcr, mdb, sendit, ctx, HORZ_LIST);
515
516    sql_free_result(mdb);
517    db_unlock(mdb);
518 }
519
520
521 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES */