]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_list.c
fbba97a1fb4d7abe88e0d83b9274c6d4588be383
[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
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 "
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 "
91             " FROM Pool ORDER BY PoolId");
92       }
93    } else {
94       if (pdbr->Name[0] != 0) {
95          Mmsg(cmd, "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat "
96            "FROM Pool WHERE Name='%s'", esc);
97       } else {
98          Mmsg(cmd, "SELECT PoolId,Name,NumVols,MaxVols,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
203    if (type == VERT_LIST) {
204       if (mdbr->VolumeName[0] != 0) {
205          Mmsg(cmd, "SELECT MediaId,VolumeName,Slot,PoolId,"
206             "MediaType,MediaTypeId,FirstWritten,LastWritten,LabelDate,VolJobs,"
207             "VolFiles,VolBlocks,VolMounts,VolBytes,VolABytes,VolAPadding,"
208             "VolHoleBytes,VolHoles,VolErrors,VolWrites,"
209             "VolCapacityBytes,VolStatus,Enabled,Recycle,VolRetention,"
210             "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
211             "EndFile,EndBlock,VolParts,LabelType,StorageId,DeviceId,"
212             "MediaAddressing,VolReadTime,VolWriteTime,"
213             "LocationId,RecycleCount,InitialWrite,ScratchPoolId,RecyclePoolId, "
214             "ActionOnPurge,%s AS ExpiresIn, Comment"
215             " FROM Media WHERE Media.VolumeName='%s'", expiresin, esc);
216       } else {
217          Mmsg(cmd, "SELECT MediaId,VolumeName,Slot,PoolId,"
218             "MediaType,MediaTypeId,FirstWritten,LastWritten,LabelDate,VolJobs,"
219             "VolFiles,VolBlocks,VolMounts,VolBytes,VolABytes,VolAPadding,"
220             "VolHoleBytes,VolHoles,VolErrors,VolWrites,"
221             "VolCapacityBytes,VolStatus,Enabled,Recycle,VolRetention,"
222             "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
223             "EndFile,EndBlock,VolParts,LabelType,StorageId,DeviceId,"
224             "MediaAddressing,VolReadTime,VolWriteTime,"
225             "LocationId,RecycleCount,InitialWrite,ScratchPoolId,RecyclePoolId, "
226             "ActionOnPurge,%s AS ExpiresIn, Comment"
227             " FROM Media WHERE Media.PoolId=%s ORDER BY MediaId",
228               expiresin, edit_int64(mdbr->PoolId, ed1));
229       }
230    } else {
231       if (mdbr->VolumeName[0] != 0) {
232          Mmsg(cmd, "SELECT MediaId,VolumeName,VolStatus,Enabled,"
233             "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten,%s AS ExpiresIn "
234               "FROM Media WHERE Media.VolumeName='%s'", expiresin, esc);
235       } else {
236          Mmsg(cmd, "SELECT MediaId,VolumeName,VolStatus,Enabled,"
237             "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten,%s AS ExpiresIn "
238             "FROM Media WHERE Media.PoolId=%s ORDER BY MediaId",
239               expiresin, edit_int64(mdbr->PoolId, ed1));
240       }
241    }
242
243    if (!QueryDB(jcr, cmd)) {
244       bdb_unlock();
245       return;
246    }
247
248    list_result(jcr, this, sendit, ctx, type);
249
250    sql_free_result();
251    bdb_unlock();
252 }
253
254 void BDB::bdb_list_jobmedia_records(JCR *jcr, uint32_t JobId,
255                               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
256 {
257    char ed1[50];
258
259    bdb_lock();
260    if (type == VERT_LIST) {
261       if (JobId > 0) {                   /* do by JobId */
262          Mmsg(cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
263             "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
264             "JobMedia.EndBlock "
265             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
266             "AND JobMedia.JobId=%s", edit_int64(JobId, ed1));
267       } else {
268          Mmsg(cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
269             "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
270             "JobMedia.EndBlock "
271             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId");
272       }
273
274    } else {
275       if (JobId > 0) {                   /* do by JobId */
276          Mmsg(cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
277             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
278             "AND JobMedia.JobId=%s", edit_int64(JobId, ed1));
279       } else {
280          Mmsg(cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
281             "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId");
282       }
283    }
284    if (!QueryDB(jcr, cmd)) {
285       bdb_unlock();
286       return;
287    }
288
289    list_result(jcr, this, sendit, ctx, type);
290
291    sql_free_result();
292    bdb_unlock();
293 }
294
295
296 void BDB::bdb_list_copies_records(JCR *jcr, uint32_t limit, char *JobIds,
297                             DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
298 {
299    POOL_MEM str_limit(PM_MESSAGE);
300    POOL_MEM str_jobids(PM_MESSAGE);
301
302    if (limit > 0) {
303       Mmsg(str_limit, " LIMIT %d", limit);
304    }
305
306    if (JobIds && JobIds[0]) {
307       Mmsg(str_jobids, " AND (Job.PriorJobId IN (%s) OR Job.JobId IN (%s)) ",
308            JobIds, JobIds);
309    }
310
311    bdb_lock();
312    Mmsg(cmd,
313    "SELECT DISTINCT Job.PriorJobId AS JobId, Job.Job, "
314                    "Job.JobId AS CopyJobId, Media.MediaType "
315      "FROM Job "
316      "JOIN JobMedia USING (JobId) "
317      "JOIN Media    USING (MediaId) "
318     "WHERE Job.Type = '%c' %s ORDER BY Job.PriorJobId DESC %s",
319         (char) JT_JOB_COPY, str_jobids.c_str(), str_limit.c_str());
320
321    if (!QueryDB(jcr, cmd)) {
322       goto bail_out;
323    }
324
325    if (sql_num_rows()) {
326       if (JobIds && JobIds[0]) {
327          sendit(ctx, _("These JobIds have copies as follows:\n"));
328       } else {
329          sendit(ctx, _("The catalog contains copies as follows:\n"));
330       }
331
332       list_result(jcr, this, sendit, ctx, type);
333    }
334
335    sql_free_result();
336
337 bail_out:
338    bdb_unlock();
339 }
340
341 void BDB::bdb_list_joblog_records(JCR *jcr, uint32_t JobId,
342                               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
343 {
344    char ed1[50];
345  
346    if (JobId <= 0) {
347       return;
348    }
349    bdb_lock();
350    if (type == VERT_LIST) {
351       Mmsg(cmd, "SELECT Time,LogText FROM Log "
352            "WHERE Log.JobId=%s ORDER BY LogId ASC", edit_int64(JobId, ed1));
353    } else {
354       Mmsg(cmd, "SELECT LogText FROM Log "
355            "WHERE Log.JobId=%s ORDER BY LogId ASC", edit_int64(JobId, ed1));
356    }
357    if (!QueryDB(jcr, cmd)) {
358       goto bail_out;
359    }
360
361    list_result(jcr, this, sendit, ctx, type);
362
363    sql_free_result();
364
365 bail_out:
366    bdb_unlock();
367 }
368
369
370 /*
371  * List Job record(s) that match JOB_DBR
372  *
373  *  Currently, we return all jobs or if jr->JobId is set,
374  *  only the job with the specified id.
375  */
376 alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
377                     void *ctx, e_list_type type)
378 {
379    char ed1[50];
380    char limit[50];
381    char esc[MAX_ESCAPE_NAME_LENGTH];
382    alist *list = NULL;
383    POOLMEM *where  = get_pool_memory(PM_MESSAGE);
384    POOLMEM *tmp    = get_pool_memory(PM_MESSAGE);
385    const char *order = "ASC";
386    *where = 0;
387
388    bdb_lock();
389    if (jr->order == 1) {
390       order = "DESC";
391    }
392    if (jr->limit > 0) {
393       snprintf(limit, sizeof(limit), " LIMIT %d", jr->limit);
394    } else {
395       limit[0] = 0;
396    }
397    if (jr->Name[0]) {
398       bdb_escape_string(jcr, esc, jr->Name, strlen(jr->Name));
399       Mmsg(tmp, " Name='%s' ", esc);
400       append_filter(where, tmp);
401
402    } else if (jr->JobId != 0) {
403       Mmsg(tmp, " JobId=%s ", edit_int64(jr->JobId, ed1));
404       append_filter(where, tmp);
405
406    } else if (jr->Job[0] != 0) {
407       bdb_escape_string(jcr, esc, jr->Job, strlen(jr->Job));
408       Mmsg(tmp, " Job='%s' ", esc);
409       append_filter(where, tmp);
410    }
411
412    if (type == INCOMPLETE_JOBS && jr->JobStatus == JS_FatalError) {
413       Mmsg(tmp, " JobStatus IN ('E', 'f') ");
414       append_filter(where, tmp);
415
416    } else if (jr->JobStatus) {
417       Mmsg(tmp, " JobStatus='%c' ", jr->JobStatus);
418       append_filter(where, tmp);
419    }
420
421    if (jr->JobType) {
422       Mmsg(tmp, " Type='%c' ", jr->JobType);
423       append_filter(where, tmp);
424    }
425
426    if (jr->JobErrors > 0) {
427       Mmsg(tmp, " JobErrors > 0 ");
428       append_filter(where, tmp);
429    }
430
431    if (jr->ClientId > 0) {
432       Mmsg(tmp, " ClientId=%s ", edit_int64(jr->ClientId, ed1));
433       append_filter(where, tmp);
434    }
435
436    switch (type) {
437    case VERT_LIST:
438       Mmsg(cmd,
439            "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level,"
440            "Job.ClientId,Client.Name as ClientName,JobStatus,SchedTime,"
441            "StartTime,EndTime,RealEndTime,JobTDate,"
442            "VolSessionId,VolSessionTime,JobFiles,JobBytes,ReadBytes,JobErrors,"
443            "JobMissingFiles,Job.PoolId,Pool.Name as PooLname,PriorJobId,"
444            "Job.FileSetId,FileSet.FileSet,Job.HasBase,Job.HasCache,Job.Comment "
445            "FROM Job JOIN Client USING (ClientId) LEFT JOIN Pool USING (PoolId) "
446            "LEFT JOIN FileSet USING (FileSetId) %s "
447            "ORDER BY StartTime %s %s", where, order, limit);
448       break;
449    case HORZ_LIST:
450       Mmsg(cmd,
451            "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
452            "FROM Job %s ORDER BY StartTime %s,JobId %s %s", where, order, order, limit);
453       break;
454    case INCOMPLETE_JOBS:
455       Mmsg(cmd,
456            "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
457              "FROM Job %s ORDER BY StartTime %s,JobId %s %s",
458            where, order, order, limit);
459       break;
460    default:
461       break;
462    }
463    Dmsg1(100, "SQL: %s\n", cmd);
464
465    free_pool_memory(tmp);
466    free_pool_memory(where);
467
468    Dmsg1(000, "cmd: %s\n", cmd);
469    if (!QueryDB(jcr, cmd)) {
470       bdb_unlock();
471       return NULL;
472    }
473    if (type == INCOMPLETE_JOBS) {
474       SQL_ROW row;
475       list = New(alist(10));
476       sql_data_seek(0);
477       for (int i=0; (row=sql_fetch_row()) != NULL; i++) {
478          list->append(bstrdup(row[0]));
479       }
480    }
481    sql_data_seek(0);
482    list_result(jcr, this, sendit, ctx, type);
483    sql_free_result();
484    bdb_unlock();
485    return list;
486 }
487
488 /*
489  * List Job totals
490  *
491  */
492 void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
493 {
494    bdb_lock();
495
496    /* List by Job */
497    Mmsg(cmd, "SELECT  count(*) AS Jobs,sum(JobFiles) "
498       "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name");
499
500    if (!QueryDB(jcr, cmd)) {
501       bdb_unlock();
502       return;
503    }
504
505    list_result(jcr, this, sendit, ctx, HORZ_LIST);
506
507    sql_free_result();
508
509    /* Do Grand Total */
510    Mmsg(cmd, "SELECT count(*) AS Jobs,sum(JobFiles) "
511         "AS Files,sum(JobBytes) As Bytes FROM Job");
512
513    if (!QueryDB(jcr, cmd)) {
514       bdb_unlock();
515       return;
516    }
517
518    list_result(jcr, this, sendit, ctx, HORZ_LIST);
519
520    sql_free_result();
521    bdb_unlock();
522 }
523
524 void BDB::bdb_list_files_for_job(JCR *jcr, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
525 {
526    char ed1[50];
527    LIST_CTX lctx(jcr, this, sendit, ctx, HORZ_LIST);
528
529    bdb_lock();
530
531    /*
532     * Stupid MySQL is NON-STANDARD !
533     */
534    if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
535       Mmsg(cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
536            "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s "
537                   "UNION ALL "
538                  "SELECT PathId, FilenameId "
539                    "FROM BaseFiles JOIN File "
540                          "ON (BaseFiles.FileId = File.FileId) "
541                   "WHERE BaseFiles.JobId = %s"
542            ") AS F, Filename,Path "
543            "WHERE Filename.FilenameId=F.FilenameId "
544            "AND Path.PathId=F.PathId",
545            edit_int64(jobid, ed1), ed1);
546    } else {
547       Mmsg(cmd, "SELECT Path.Path||Filename.Name AS Filename "
548            "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s "
549                   "UNION ALL "
550                  "SELECT PathId, FilenameId "
551                    "FROM BaseFiles JOIN File "
552                          "ON (BaseFiles.FileId = File.FileId) "
553                   "WHERE BaseFiles.JobId = %s"
554            ") AS F, Filename,Path "
555            "WHERE Filename.FilenameId=F.FilenameId "
556            "AND Path.PathId=F.PathId",
557            edit_int64(jobid, ed1), ed1);
558    }
559
560    if (!bdb_big_sql_query(cmd, list_result, &lctx)) {
561        bdb_unlock();
562        return;
563    }
564
565    lctx.send_dashes();
566
567    sql_free_result();
568    bdb_unlock();
569 }
570
571 void BDB::bdb_list_base_files_for_job(JCR *jcr, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
572 {
573    char ed1[50];
574    LIST_CTX lctx(jcr, this, sendit, ctx, HORZ_LIST);
575
576    bdb_lock();
577
578    /*
579     * Stupid MySQL is NON-STANDARD !
580     */
581    if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
582       Mmsg(cmd, "SELECT CONCAT(Path.Path,File.Filename) AS Filename "
583            "FROM BaseFiles, File, Path "
584            "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
585            "AND BaseFiles.FileId = File.FileId "
586            "AND Path.PathId=File.PathId",
587          edit_int64(jobid, ed1));
588    } else {
589       Mmsg(cmd, "SELECT Path.Path||File.Filename AS Filename "
590            "FROM BaseFiles, File, Path "
591            "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
592            "AND BaseFiles.FileId = File.FileId "
593            "AND Path.PathId=File.PathId",
594            edit_int64(jobid, ed1));
595    }
596
597    if (!bdb_big_sql_query(cmd, list_result, &lctx)) {
598        bdb_unlock();
599        return;
600    }
601
602    lctx.send_dashes();
603
604    sql_free_result();
605    bdb_unlock();
606 }
607
608 void BDB::bdb_list_snapshot_records(JCR *jcr, SNAPSHOT_DBR *sdbr,
609               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
610 {
611    POOLMEM *filter = get_pool_memory(PM_MESSAGE);
612    POOLMEM *tmp    = get_pool_memory(PM_MESSAGE);
613    POOLMEM *esc    = get_pool_memory(PM_MESSAGE);
614    char ed1[50];
615
616    bdb_lock();
617    *filter = 0;
618
619    if (sdbr->Name[0]) {
620       bdb_escape_string(jcr, esc, sdbr->Name, strlen(sdbr->Name));
621       Mmsg(tmp, "Name='%s'", esc);
622       append_filter(filter, tmp);
623    }
624    if (sdbr->SnapshotId > 0) {
625       Mmsg(tmp, "Snapshot.SnapshotId=%d", sdbr->SnapshotId);
626       append_filter(filter, tmp);
627    }
628    if (sdbr->ClientId > 0) {
629       Mmsg(tmp, "Snapshot.ClientId=%d", sdbr->ClientId);
630       append_filter(filter, tmp);
631    }
632    if (sdbr->JobId > 0) {
633       Mmsg(tmp, "Snapshot.JobId=%d", sdbr->JobId);
634       append_filter(filter, tmp);
635    }
636    if (*sdbr->Client) {
637       bdb_escape_string(jcr, esc, sdbr->Client, strlen(sdbr->Client));
638       Mmsg(tmp, "Client.Name='%s'", esc);
639       append_filter(filter, tmp);
640    }
641    if (sdbr->Device && *(sdbr->Device)) {
642       esc = check_pool_memory_size(esc, strlen(sdbr->Device) * 2 + 1);
643       bdb_escape_string(jcr, esc, sdbr->Device, strlen(sdbr->Device));
644       Mmsg(tmp, "Device='%s'", esc);
645       append_filter(filter, tmp);
646    }
647    if (*sdbr->Type) {
648       bdb_escape_string(jcr, esc, sdbr->Type, strlen(sdbr->Type));
649       Mmsg(tmp, "Type='%s'", esc);
650       append_filter(filter, tmp);
651    }
652    if (*sdbr->created_before) {
653       bdb_escape_string(jcr, esc, sdbr->created_before, strlen(sdbr->created_before));
654       Mmsg(tmp, "CreateDate <= '%s'", esc);
655       append_filter(filter, tmp);
656    }
657    if (*sdbr->created_after) {
658       bdb_escape_string(jcr, esc, sdbr->created_after, strlen(sdbr->created_after));
659       Mmsg(tmp, "CreateDate >= '%s'", esc);
660       append_filter(filter, tmp);
661    }
662    if (sdbr->expired) {
663       Mmsg(tmp, "CreateTDate < (%s - Retention)", edit_int64(time(NULL), ed1));
664       append_filter(filter, tmp);
665    }
666    if (*sdbr->CreateDate) {
667       bdb_escape_string(jcr, esc, sdbr->CreateDate, strlen(sdbr->CreateDate));
668       Mmsg(tmp, "CreateDate = '%s'", esc);
669       append_filter(filter, tmp);
670    }
671
672    if (sdbr->sorted_client) {
673       pm_strcat(filter, " ORDER BY Client.Name, SnapshotId DESC");
674
675    } else {
676       pm_strcat(filter, " ORDER BY SnapshotId DESC");
677    }
678
679    if (type == VERT_LIST || type == ARG_LIST) {
680       Mmsg(cmd, "SELECT SnapshotId, Snapshot.Name, CreateDate, Client.Name AS Client, "
681            "FileSet.FileSet AS FileSet, JobId, Volume, Device, Type, Retention, Comment "
682            "FROM Snapshot JOIN Client USING (ClientId) LEFT JOIN FileSet USING (FileSetId) %s", filter);
683
684    } else if (type == HORZ_LIST) {
685       Mmsg(cmd, "SELECT SnapshotId, Snapshot.Name, CreateDate, Client.Name AS Client, "
686            "Device, Type "
687            "FROM Snapshot JOIN Client USING (ClientId) %s", filter);
688    }
689
690    if (!QueryDB(jcr, cmd)) {
691       goto bail_out;
692    }
693
694    list_result(jcr, this, sendit, ctx, type);
695
696 bail_out:
697    sql_free_result();
698    bdb_unlock();
699
700    free_pool_memory(filter);
701    free_pool_memory(esc);
702    free_pool_memory(tmp);
703 }
704
705 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */