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