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