]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_list.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / cats / sql_list.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many 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    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Bacula Catalog Database List records interface routines
21  *
22  *    Written by Kern Sibbald, March 2000
23  *
24  */
25
26 #include  "bacula.h"
27
28 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
29
30 #include  "cats.h"
31
32 /* -----------------------------------------------------------------------
33  *
34  *   Generic Routines (or almost generic)
35  *
36  * -----------------------------------------------------------------------
37  */
38
39 #define append_filter(buf, sql)  \
40    do {                          \
41       if (*buf) {                \
42          pm_strcat(buf, " AND ");\
43       } else {                   \
44          pm_strcpy(buf, " WHERE ");\
45       }                          \
46       pm_strcat(buf, sql);       \
47    } while (0)
48
49 /*
50  * Submit general SQL query
51  */
52 int BDB::bdb_list_sql_query(JCR *jcr, const char *query, DB_LIST_HANDLER *sendit,
53                       void *ctx, int verbose, e_list_type type)
54 {
55    bdb_lock();
56    if (!sql_query(query, QF_STORE_RESULT)) {
57       Mmsg(errmsg, _("Query failed: %s\n"), sql_strerror());
58       if (verbose) {
59          sendit(ctx, errmsg);
60       }
61       bdb_unlock();
62       return 0;
63    }
64
65    list_result(jcr,this, sendit, ctx, type);
66    sql_free_result();
67    bdb_unlock();
68    return 1;
69 }
70
71 void BDB::bdb_list_pool_records(JCR *jcr, POOL_DBR *pdbr,
72                      DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
73 {
74    char esc[MAX_ESCAPE_NAME_LENGTH];
75
76    bdb_lock();
77    bdb_escape_string(jcr, esc, pdbr->Name, strlen(pdbr->Name));
78
79    if (type == VERT_LIST) {
80       if (pdbr->Name[0] != 0) {
81          Mmsg(cmd, "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,"
82             "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes,"
83             "AutoPrune,Recycle,PoolType,LabelFormat,Enabled,ScratchPoolId,"
84             "RecyclePoolId,LabelType,ActionOnPurge,CacheRetention "
85             " FROM Pool WHERE Name='%s'", esc);
86       } else {
87          Mmsg(cmd, "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,"
88             "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes,"
89             "AutoPrune,Recycle,PoolType,LabelFormat,Enabled,ScratchPoolId,"
90             "RecyclePoolId,LabelType,ActionOnPurge,CacheRetention "
91             " FROM Pool ORDER BY PoolId");
92       }
93    } else {
94       if (pdbr->Name[0] != 0) {
95          Mmsg(cmd, "SELECT PoolId,Name,NumVols,MaxVols,MaxVolBytes,VolRetention,Enabled,PoolType,LabelFormat "
96            "FROM Pool WHERE Name='%s'", esc);
97       } else {
98          Mmsg(cmd, "SELECT PoolId,Name,NumVols,MaxVols,MaxVolBytes,VolRetention,Enabled,PoolType,LabelFormat "
99            "FROM Pool ORDER BY PoolId");
100       }
101    }
102
103    if (!QueryDB(jcr, cmd)) {
104       bdb_unlock();
105       return;
106    }
107
108    list_result(jcr, this, sendit, ctx, type);
109
110    sql_free_result();
111    bdb_unlock();
112 }
113
114 void BDB::bdb_list_client_records(JCR *jcr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
115 {
116    bdb_lock();
117    if (type == VERT_LIST) {
118       Mmsg(cmd, "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,"
119          "JobRetention "
120          "FROM Client ORDER BY ClientId");
121    } else {
122       Mmsg(cmd, "SELECT ClientId,Name,FileRetention,JobRetention "
123          "FROM Client ORDER BY ClientId");
124    }
125
126    if (!QueryDB(jcr, cmd)) {
127       bdb_unlock();
128       return;
129    }
130
131    list_result(jcr, this, sendit, ctx, type);
132
133    sql_free_result();
134    bdb_unlock();
135 }
136
137 /*
138  * List restore objects
139  *
140  * JobId | JobIds: List RestoreObjects for specific Job(s)
141  * It is possible to specify the ObjectType using FileType field.
142  */
143 void BDB::bdb_list_restore_objects(JCR *jcr, ROBJECT_DBR *rr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
144 {
145    POOL_MEM filter;
146    char  ed1[50];
147    char *jobid;
148
149    if (rr->JobIds && is_a_number_list(rr->JobIds)) {
150       jobid = rr->JobIds;
151
152    } else if (rr->JobId) {
153       jobid = edit_int64(rr->JobId, ed1);
154
155    } else {
156       return;
157    }
158
159    if (rr->FileType > 0) {
160       Mmsg(filter, "AND ObjectType = %d ", rr->FileType);
161    }
162
163    bdb_lock();
164    if (type == VERT_LIST) {
165       Mmsg(cmd, "SELECT JobId, RestoreObjectId, ObjectName, "
166            "PluginName, ObjectType "
167            "FROM RestoreObject JOIN Job USING (JobId) WHERE JobId IN (%s) %s "
168            "ORDER BY JobTDate ASC, RestoreObjectId",
169            jobid, filter.c_str());
170    } else {
171       Mmsg(cmd, "SELECT JobId, RestoreObjectId, ObjectName, "
172            "PluginName, ObjectType, ObjectLength "
173            "FROM RestoreObject JOIN Job USING (JobId) WHERE JobId IN (%s) %s "
174            "ORDER BY JobTDate ASC, RestoreObjectId",
175            jobid, filter.c_str());
176    }
177
178    if (!QueryDB(jcr, cmd)) {
179       bdb_unlock();
180       return;
181    }
182
183    list_result(jcr, this, sendit, ctx, type);
184
185    sql_free_result();
186    bdb_unlock();
187 }
188
189 /*
190  * If VolumeName is non-zero, list the record for that Volume
191  *   otherwise, list the Volumes in the Pool specified by PoolId
192  */
193 void BDB::bdb_list_media_records(JCR *jcr, MEDIA_DBR *mdbr,
194                       DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
195 {
196    char ed1[50];
197    char esc[MAX_ESCAPE_NAME_LENGTH];
198    const char *expiresin = expires_in[bdb_get_type_index()];
199
200    bdb_lock();
201    bdb_escape_string(jcr, esc, mdbr->VolumeName, strlen(mdbr->VolumeName));
202    const char *join = "";
203    const char *where = "";
204
205    if (type == VERT_LIST) {
206       if (mdbr->VolumeName[0] != 0) {
207          Mmsg(cmd, "SELECT MediaId,VolumeName,Slot,PoolId,"
208             "MediaType,MediaTypeId,FirstWritten,LastWritten,LabelDate,VolJobs,"
209             "VolFiles,VolBlocks,VolParts,VolCloudParts,Media.CacheRetention,VolMounts,VolBytes,"
210             "VolABytes,VolAPadding,"
211             "VolHoleBytes,VolHoles,LastPartBytes,VolErrors,VolWrites,"
212             "VolCapacityBytes,VolStatus,Media.Enabled,Media.Recycle,Media.VolRetention,"
213             "Media.VolUseDuration,Media.MaxVolJobs,Media.MaxVolFiles,Media.MaxVolBytes,InChanger,"
214             "EndFile,EndBlock,VolType,Media.LabelType,StorageId,DeviceId,"
215             "MediaAddressing,VolReadTime,VolWriteTime,"
216             "LocationId,RecycleCount,InitialWrite,Media.ScratchPoolId,Media.RecyclePoolId, "
217             "Media.ActionOnPurge,%s AS ExpiresIn, Comment"
218            " FROM Media %s WHERE Media.VolumeName='%s' %s",
219               expiresin,
220               join,
221               esc,
222               where
223             );
224       } else {
225          Mmsg(cmd, "SELECT MediaId,VolumeName,Slot,PoolId,"
226             "MediaType,MediaTypeId,FirstWritten,LastWritten,LabelDate,VolJobs,"
227             "VolFiles,VolBlocks,VolParts,VolCloudParts,Media.CacheRetention,VolMounts,VolBytes,"
228             "VolABytes,VolAPadding,"
229             "VolHoleBytes,VolHoles,LastPartBytes,VolErrors,VolWrites,"
230             "VolCapacityBytes,VolStatus,Media.Enabled,Media.Recycle,Media.VolRetention,"
231             "Media.VolUseDuration,Media.MaxVolJobs,Media.MaxVolFiles,Media.MaxVolBytes,InChanger,"
232             "EndFile,EndBlock,VolType,Media.LabelType,StorageId,DeviceId,"
233             "MediaAddressing,VolReadTime,VolWriteTime,"
234             "LocationId,RecycleCount,InitialWrite,Media.ScratchPoolId,Media.RecyclePoolId, "
235             "Media.ActionOnPurge,%s AS ExpiresIn, Comment"
236             " FROM Media %s WHERE Media.PoolId=%s %s ORDER BY MediaId",
237               expiresin,
238               join,
239               edit_int64(mdbr->PoolId, ed1),
240               where
241             );
242       }
243    } else {
244       if (mdbr->VolumeName[0] != 0) {
245          Mmsg(cmd, "SELECT MediaId,VolumeName,VolStatus,Media.Enabled,"
246             "VolBytes,VolFiles,Media.VolRetention,Media.Recycle,Slot,InChanger,MediaType,VolType,"
247               "VolParts,%s AS ExpiresIn "
248               "FROM Media %s WHERE Media.VolumeName='%s' %s",
249               expiresin,
250               join,
251               esc,
252               where
253             );
254       } else {
255          Mmsg(cmd, "SELECT MediaId,VolumeName,VolStatus,Media.Enabled,"
256             "VolBytes,VolFiles,Media.VolRetention,Media.Recycle,Slot,InChanger,MediaType,VolType,"
257             "VolParts,LastWritten,%s AS ExpiresIn "
258             "FROM Media %s WHERE Media.PoolId=%s %s ORDER BY MediaId",
259               expiresin,
260               join,
261               edit_int64(mdbr->PoolId, ed1),
262               where
263             );
264       }
265    }
266    Dmsg1(DT_SQL|50, "q=%s\n", cmd);
267    if (!QueryDB(jcr, cmd)) {
268       bdb_unlock();
269       return;
270    }
271
272    list_result(jcr, this, sendit, ctx, type);
273
274    sql_free_result();
275    bdb_unlock();
276 }
277
278 void BDB::bdb_list_jobmedia_records(JCR *jcr, uint32_t JobId,
279                               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
280 {
281    char ed1[50];
282
283    bdb_lock();
284    const char *join = "";
285    const char *where = "";
286
287    if (type == VERT_LIST) {
288       if (JobId > 0) {                   /* do by JobId */
289          Mmsg(cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
290             "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
291             "JobMedia.EndBlock "
292             "FROM JobMedia JOIN Media USING (MediaId) %s "
293             "WHERE JobMedia.JobId=%s %s",
294               join,
295               edit_int64(JobId, ed1),
296               where);
297       } else {
298          Mmsg(cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
299             "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
300             "JobMedia.EndBlock "
301             "FROM JobMedia JOIN Media USING (MediaId) %s %s",
302               join,
303               where);
304       }
305
306    } else {
307       if (JobId > 0) {                   /* do by JobId */
308          Mmsg(cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
309             "FROM JobMedia JOIN Media USING (MediaId) %s WHERE "
310             "JobMedia.JobId=%s %s",
311               join,
312               edit_int64(JobId, ed1),
313               where);
314       } else {
315          Mmsg(cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
316               "FROM JobMedia JOIN Media USING (MediaId) %s %s",
317               join,
318               where);
319       }
320    }
321    Dmsg1(DT_SQL|50, "q=%s\n", cmd);
322
323    if (!QueryDB(jcr, cmd)) {
324       bdb_unlock();
325       return;
326    }
327
328    list_result(jcr, this, sendit, ctx, type);
329
330    sql_free_result();
331    bdb_unlock();
332 }
333
334
335 void BDB::bdb_list_copies_records(JCR *jcr, uint32_t limit, char *JobIds,
336                             DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
337 {
338    POOL_MEM str_limit(PM_MESSAGE);
339    POOL_MEM str_jobids(PM_MESSAGE);
340
341    if (limit > 0) {
342       Mmsg(str_limit, " LIMIT %d", limit);
343    }
344
345    if (JobIds && JobIds[0]) {
346       Mmsg(str_jobids, " AND (Job.PriorJobId IN (%s) OR Job.JobId IN (%s)) ",
347            JobIds, JobIds);
348    }
349
350    bdb_lock();
351    Mmsg(cmd,
352    "SELECT DISTINCT Job.PriorJobId AS JobId, Job.Job, "
353                    "Job.JobId AS CopyJobId, Media.MediaType "
354      "FROM Job "
355      "JOIN JobMedia USING (JobId) "
356      "JOIN Media    USING (MediaId) "
357     "WHERE Job.Type = '%c' %s ORDER BY Job.PriorJobId DESC %s",
358         (char) JT_JOB_COPY, str_jobids.c_str(), str_limit.c_str());
359
360    if (!QueryDB(jcr, cmd)) {
361       goto bail_out;
362    }
363
364    if (sql_num_rows()) {
365       if (JobIds && JobIds[0]) {
366          sendit(ctx, _("These JobIds have copies as follows:\n"));
367       } else {
368          sendit(ctx, _("The catalog contains copies as follows:\n"));
369       }
370
371       list_result(jcr, this, sendit, ctx, type);
372    }
373
374    sql_free_result();
375
376 bail_out:
377    bdb_unlock();
378 }
379
380 void BDB::bdb_list_joblog_records(JCR *jcr, uint32_t JobId,
381                               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
382 {
383    char ed1[50];
384  
385    if (JobId <= 0) {
386       return;
387    }
388    bdb_lock();
389    if (type == VERT_LIST) {
390       Mmsg(cmd, "SELECT Time,LogText FROM Log "
391            "WHERE Log.JobId=%s ORDER BY LogId ASC", edit_int64(JobId, ed1));
392    } else {
393       Mmsg(cmd, "SELECT LogText FROM Log "
394            "WHERE Log.JobId=%s ORDER BY LogId ASC", edit_int64(JobId, ed1));
395    }
396    if (!QueryDB(jcr, cmd)) {
397       goto bail_out;
398    }
399
400    list_result(jcr, this, sendit, ctx, type);
401
402    sql_free_result();
403
404 bail_out:
405    bdb_unlock();
406 }
407
408
409 /*
410  * List Job record(s) that match JOB_DBR
411  *
412  *  Currently, we return all jobs or if jr->JobId is set,
413  *  only the job with the specified id.
414  */
415 alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
416                     void *ctx, e_list_type type)
417 {
418    char ed1[50];
419    char limit[50];
420    char esc[MAX_ESCAPE_NAME_LENGTH];
421    alist *list = NULL;
422    POOLMEM *where  = get_pool_memory(PM_MESSAGE);
423    POOLMEM *tmp    = get_pool_memory(PM_MESSAGE);
424    const char *order = "ASC";
425    *where = 0;
426
427    bdb_lock();
428    if (jr->order == 1) {
429       order = "DESC";
430    }
431    if (jr->limit > 0) {
432       snprintf(limit, sizeof(limit), " LIMIT %d", jr->limit);
433    } else {
434       limit[0] = 0;
435    }
436    if (jr->Name[0]) {
437       bdb_escape_string(jcr, esc, jr->Name, strlen(jr->Name));
438       Mmsg(tmp, " Job.Name='%s' ", esc);
439       append_filter(where, tmp);
440
441    } else if (jr->JobId != 0) {
442       Mmsg(tmp, " Job.JobId=%s ", edit_int64(jr->JobId, ed1));
443       append_filter(where, tmp);
444
445    } else if (jr->Job[0] != 0) {
446       bdb_escape_string(jcr, esc, jr->Job, strlen(jr->Job));
447       Mmsg(tmp, " Job.Job='%s' ", esc);
448       append_filter(where, tmp);
449    }
450
451    if (type == INCOMPLETE_JOBS && jr->JobStatus == JS_FatalError) {
452       Mmsg(tmp, " Job.JobStatus IN ('E', 'f') ");
453       append_filter(where, tmp);
454
455    } else if (jr->JobStatus) {
456       Mmsg(tmp, " Job.JobStatus='%c' ", jr->JobStatus);
457       append_filter(where, tmp);
458    }
459
460    if (jr->JobType) {
461       Mmsg(tmp, " Job.Type='%c' ", jr->JobType);
462       append_filter(where, tmp);
463    }
464
465    if (jr->JobErrors > 0) {
466       Mmsg(tmp, " Job.JobErrors > 0 ");
467       append_filter(where, tmp);
468    }
469
470    if (jr->ClientId > 0) {
471       Mmsg(tmp, " Job.ClientId=%s ", edit_int64(jr->ClientId, ed1));
472       append_filter(where, tmp);
473    }
474
475    switch (type) {
476    case VERT_LIST:
477       Mmsg(cmd,
478            "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level,"
479            "Job.ClientId,Client.Name as ClientName,JobStatus,SchedTime,"
480            "StartTime,EndTime,RealEndTime,JobTDate,"
481            "VolSessionId,VolSessionTime,JobFiles,JobBytes,ReadBytes,JobErrors,"
482            "JobMissingFiles,Job.PoolId,Pool.Name as PoolName,PriorJobId,"
483            "Job.FileSetId,FileSet.FileSet,Job.HasBase,Job.HasCache,Job.Comment "
484            "FROM Job JOIN Client USING (ClientId) LEFT JOIN Pool USING (PoolId) "
485            "LEFT JOIN FileSet USING (FileSetId) %s "
486            "ORDER BY StartTime %s %s", where, order, limit);
487       break;
488    case HORZ_LIST:
489       Mmsg(cmd,
490            "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
491            "FROM Job %s ORDER BY StartTime %s,JobId %s %s", where, order, order, limit);
492       break;
493    case INCOMPLETE_JOBS:
494       Mmsg(cmd,
495            "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
496              "FROM Job %s ORDER BY StartTime %s,JobId %s %s",
497            where, order, order, limit);
498       break;
499    default:
500       break;
501    }
502    Dmsg1(100, "SQL: %s\n", cmd);
503
504    free_pool_memory(tmp);
505    free_pool_memory(where);
506
507    Dmsg1(000, "cmd: %s\n", cmd);
508    if (!QueryDB(jcr, cmd)) {
509       bdb_unlock();
510       return NULL;
511    }
512    if (type == INCOMPLETE_JOBS) {
513       SQL_ROW row;
514       list = New(alist(10));
515       sql_data_seek(0);
516       for (int i=0; (row=sql_fetch_row()) != NULL; i++) {
517          list->append(bstrdup(row[0]));
518       }
519    }
520    sql_data_seek(0);
521    list_result(jcr, this, sendit, ctx, type);
522    sql_free_result();
523    bdb_unlock();
524    return list;
525 }
526
527 /*
528  * List Job totals
529  *
530  */
531 void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
532 {
533    bdb_lock();
534
535    /* List by Job */
536    Mmsg(cmd, "SELECT  count(*) AS Jobs,sum(JobFiles) "
537       "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name");
538
539    if (!QueryDB(jcr, cmd)) {
540       bdb_unlock();
541       return;
542    }
543
544    list_result(jcr, this, sendit, ctx, HORZ_LIST);
545
546    sql_free_result();
547
548    /* Do Grand Total */
549    Mmsg(cmd, "SELECT count(*) AS Jobs,sum(JobFiles) "
550         "AS Files,sum(JobBytes) As Bytes FROM Job");
551
552    if (!QueryDB(jcr, cmd)) {
553       bdb_unlock();
554       return;
555    }
556
557    list_result(jcr, this, sendit, ctx, HORZ_LIST);
558
559    sql_free_result();
560    bdb_unlock();
561 }
562
563 /* List all file records from a job
564  * "deleted" values are described just below
565  */
566 void BDB::bdb_list_files_for_job(JCR *jcr, JobId_t jobid, int deleted, DB_LIST_HANDLER *sendit, void *ctx)
567 {
568    char ed1[50];
569    const char *opt;
570    LIST_CTX lctx(jcr, this, sendit, ctx, HORZ_LIST);
571
572    switch (deleted) {
573    case 0:                      /* Show only actual files */
574       opt = " AND FileIndex <> 0 ";
575       break;
576    case 1:                      /* Show only deleted files */
577       opt = " AND FileIndex = 0 ";
578       break;
579    default:                     /* Show everything */
580       opt = "";
581       break;
582    }
583
584    bdb_lock();
585
586    /*
587     * Stupid MySQL is NON-STANDARD !
588     */
589    if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
590       Mmsg(cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
591            "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s %s "
592                   "UNION ALL "
593                  "SELECT PathId, FilenameId "
594                    "FROM BaseFiles JOIN File "
595                          "ON (BaseFiles.FileId = File.FileId) "
596                   "WHERE BaseFiles.JobId = %s"
597            ") AS F, Filename,Path "
598            "WHERE Filename.FilenameId=F.FilenameId "
599            "AND Path.PathId=F.PathId",
600            edit_int64(jobid, ed1), opt, ed1);
601    } else {
602       Mmsg(cmd, "SELECT Path.Path||Filename.Name AS Filename "
603            "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s %s "
604                   "UNION ALL "
605                  "SELECT PathId, FilenameId "
606                    "FROM BaseFiles JOIN File "
607                          "ON (BaseFiles.FileId = File.FileId) "
608                   "WHERE BaseFiles.JobId = %s"
609            ") AS F, Filename,Path "
610            "WHERE Filename.FilenameId=F.FilenameId "
611            "AND Path.PathId=F.PathId",
612            edit_int64(jobid, ed1), opt, ed1);
613    }
614    Dmsg1(100, "q=%s\n", cmd);
615    if (!bdb_big_sql_query(cmd, list_result, &lctx)) {
616        bdb_unlock();
617        return;
618    }
619
620    lctx.send_dashes();
621
622    sql_free_result();
623    bdb_unlock();
624 }
625
626 void BDB::bdb_list_base_files_for_job(JCR *jcr, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
627 {
628    char ed1[50];
629    LIST_CTX lctx(jcr, this, sendit, ctx, HORZ_LIST);
630
631    bdb_lock();
632
633    /*
634     * Stupid MySQL is NON-STANDARD !
635     */
636    if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
637       Mmsg(cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
638            "FROM BaseFiles, File, Filename, Path "
639            "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
640            "AND BaseFiles.FileId = File.FileId "
641            "AND Filename.FilenameId=File.FilenameId "
642            "AND Path.PathId=File.PathId",
643          edit_int64(jobid, ed1));
644    } else {
645       Mmsg(cmd, "SELECT Path.Path||Filename.Name AS Filename "
646            "FROM BaseFiles, File, Filename, Path "
647            "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
648            "AND BaseFiles.FileId = File.FileId "
649            "AND Filename.FilenameId=File.FilenameId "
650            "AND Path.PathId=File.PathId",
651            edit_int64(jobid, ed1));
652    }
653
654    if (!bdb_big_sql_query(cmd, list_result, &lctx)) {
655        bdb_unlock();
656        return;
657    }
658
659    lctx.send_dashes();
660
661    sql_free_result();
662    bdb_unlock();
663 }
664
665 void BDB::bdb_list_snapshot_records(JCR *jcr, SNAPSHOT_DBR *sdbr,
666               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
667 {
668    POOLMEM *filter = get_pool_memory(PM_MESSAGE);
669    POOLMEM *tmp    = get_pool_memory(PM_MESSAGE);
670    POOLMEM *esc    = get_pool_memory(PM_MESSAGE);
671    char ed1[50];
672
673    bdb_lock();
674    *filter = 0;
675
676    if (sdbr->Name[0]) {
677       bdb_escape_string(jcr, esc, sdbr->Name, strlen(sdbr->Name));
678       Mmsg(tmp, "Name='%s'", esc);
679       append_filter(filter, tmp);
680    }
681    if (sdbr->SnapshotId > 0) {
682       Mmsg(tmp, "Snapshot.SnapshotId=%d", sdbr->SnapshotId);
683       append_filter(filter, tmp);
684    }
685    if (sdbr->ClientId > 0) {
686       Mmsg(tmp, "Snapshot.ClientId=%d", sdbr->ClientId);
687       append_filter(filter, tmp);
688    }
689    if (sdbr->JobId > 0) {
690       Mmsg(tmp, "Snapshot.JobId=%d", sdbr->JobId);
691       append_filter(filter, tmp);
692    }
693    if (*sdbr->Client) {
694       bdb_escape_string(jcr, esc, sdbr->Client, strlen(sdbr->Client));
695       Mmsg(tmp, "Client.Name='%s'", esc);
696       append_filter(filter, tmp);
697    }
698    if (sdbr->Device && *(sdbr->Device)) {
699       esc = check_pool_memory_size(esc, strlen(sdbr->Device) * 2 + 1);
700       bdb_escape_string(jcr, esc, sdbr->Device, strlen(sdbr->Device));
701       Mmsg(tmp, "Device='%s'", esc);
702       append_filter(filter, tmp);
703    }
704    if (*sdbr->Type) {
705       bdb_escape_string(jcr, esc, sdbr->Type, strlen(sdbr->Type));
706       Mmsg(tmp, "Type='%s'", esc);
707       append_filter(filter, tmp);
708    }
709    if (*sdbr->created_before) {
710       bdb_escape_string(jcr, esc, sdbr->created_before, strlen(sdbr->created_before));
711       Mmsg(tmp, "CreateDate <= '%s'", esc);
712       append_filter(filter, tmp);
713    }
714    if (*sdbr->created_after) {
715       bdb_escape_string(jcr, esc, sdbr->created_after, strlen(sdbr->created_after));
716       Mmsg(tmp, "CreateDate >= '%s'", esc);
717       append_filter(filter, tmp);
718    }
719    if (sdbr->expired) {
720       Mmsg(tmp, "CreateTDate < (%s - Retention)", edit_int64(time(NULL), ed1));
721       append_filter(filter, tmp);
722    }
723    if (*sdbr->CreateDate) {
724       bdb_escape_string(jcr, esc, sdbr->CreateDate, strlen(sdbr->CreateDate));
725       Mmsg(tmp, "CreateDate = '%s'", esc);
726       append_filter(filter, tmp);
727    }
728
729    if (sdbr->sorted_client) {
730       pm_strcat(filter, " ORDER BY Client.Name, SnapshotId DESC");
731
732    } else {
733       pm_strcat(filter, " ORDER BY SnapshotId DESC");
734    }
735
736    if (type == VERT_LIST || type == ARG_LIST) {
737       Mmsg(cmd, "SELECT SnapshotId, Snapshot.Name, CreateDate, Client.Name AS Client, "
738            "FileSet.FileSet AS FileSet, JobId, Volume, Device, Type, Retention, Comment "
739            "FROM Snapshot JOIN Client USING (ClientId) LEFT JOIN FileSet USING (FileSetId) %s", filter);
740
741    } else if (type == HORZ_LIST) {
742       Mmsg(cmd, "SELECT SnapshotId, Snapshot.Name, CreateDate, Client.Name AS Client, "
743            "Device, Type "
744            "FROM Snapshot JOIN Client USING (ClientId) %s", filter);
745    }
746
747    if (!QueryDB(jcr, cmd)) {
748       goto bail_out;
749    }
750
751    list_result(jcr, this, sendit, ctx, type);
752
753 bail_out:
754    sql_free_result();
755    bdb_unlock();
756
757    free_pool_memory(filter);
758    free_pool_memory(esc);
759    free_pool_memory(tmp);
760 }
761
762 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */