1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 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  */
bdb_list_sql_query(JCR * jcr,const char * query,DB_LIST_HANDLER * sendit,void * ctx,int verbose,e_list_type type)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 
bdb_list_pool_records(JCR * jcr,POOL_DBR * pdbr,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)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 
bdb_list_client_records(JCR * jcr,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)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  */
bdb_list_restore_objects(JCR * jcr,ROBJECT_DBR * rr,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)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  */
bdb_list_media_records(JCR * jcr,MEDIA_DBR * mdbr,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)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 
bdb_list_jobmedia_records(JCR * jcr,uint32_t JobId,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)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 
bdb_list_copies_records(JCR * jcr,uint32_t limit,char * JobIds,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)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 
bdb_list_joblog_records(JCR * jcr,uint32_t JobId,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)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  * List Job record(s) that match JOB_DBR
410  *
411  *  Currently, we return all jobs or if jr->JobId is set,
412  *  only the job with the specified id.
413  */
bdb_list_job_records(JCR * jcr,JOB_DBR * jr,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)414 alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
415                     void *ctx, e_list_type type)
416 {
417    char ed1[50];
418    char limit[50];
419    char esc[MAX_ESCAPE_NAME_LENGTH];
420    alist *list = NULL;
421    POOLMEM *where  = get_pool_memory(PM_MESSAGE);
422    POOLMEM *tmp    = get_pool_memory(PM_MESSAGE);
423    const char *order = "ASC";
424    *where = 0;
425 
426    bdb_lock();
427    if (jr->order == 1) {
428       order = "DESC";
429    }
430    if (jr->limit > 0) {
431       snprintf(limit, sizeof(limit), " LIMIT %d", jr->limit);
432    } else {
433       limit[0] = 0;
434    }
435    if (jr->Name[0]) {
436       bdb_escape_string(jcr, esc, jr->Name, strlen(jr->Name));
437       Mmsg(tmp, " Job.Name='%s' ", esc);
438       append_filter(where, tmp);
439 
440    } else if (jr->JobId != 0) {
441       Mmsg(tmp, " Job.JobId=%s ", edit_int64(jr->JobId, ed1));
442       append_filter(where, tmp);
443 
444    } else if (jr->Job[0] != 0) {
445       bdb_escape_string(jcr, esc, jr->Job, strlen(jr->Job));
446       Mmsg(tmp, " Job.Job='%s' ", esc);
447       append_filter(where, tmp);
448    }
449 
450    if (type == INCOMPLETE_JOBS && jr->JobStatus == JS_FatalError) {
451       Mmsg(tmp, " Job.JobStatus IN ('E', 'f') ");
452       append_filter(where, tmp);
453 
454    } else if (jr->JobStatus) {
455       Mmsg(tmp, " Job.JobStatus='%c' ", jr->JobStatus);
456       append_filter(where, tmp);
457    }
458 
459    if (jr->JobType) {
460       Mmsg(tmp, " Job.Type='%c' ", jr->JobType);
461       append_filter(where, tmp);
462    }
463 
464    if (jr->JobErrors > 0) {
465       Mmsg(tmp, " Job.JobErrors > 0 ");
466       append_filter(where, tmp);
467    }
468 
469    if (jr->ClientId > 0) {
470       Mmsg(tmp, " Job.ClientId=%s ", edit_int64(jr->ClientId, ed1));
471       append_filter(where, tmp);
472    }
473 
474    switch (type) {
475    case VERT_LIST:
476       Mmsg(cmd,
477            "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level,"
478            "Job.ClientId,Client.Name as ClientName,JobStatus,SchedTime,"
479            "StartTime,EndTime,RealEndTime,JobTDate,"
480            "VolSessionId,VolSessionTime,JobFiles,JobBytes,ReadBytes,JobErrors,"
481            "JobMissingFiles,Job.PoolId,Pool.Name as PoolName,PriorJobId,"
482            "Job.FileSetId,FileSet.FileSet,Job.HasBase,Job.HasCache,Job.Comment "
483            "FROM Job JOIN Client USING (ClientId) LEFT JOIN Pool USING (PoolId) "
484            "LEFT JOIN FileSet USING (FileSetId) %s "
485            "ORDER BY StartTime %s %s", where, order, limit);
486       break;
487    case HORZ_LIST:
488       Mmsg(cmd,
489            "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
490            "FROM Job %s ORDER BY StartTime %s,JobId %s %s", where, order, order, limit);
491       break;
492    case INCOMPLETE_JOBS:
493       Mmsg(cmd,
494            "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus "
495              "FROM Job %s ORDER BY StartTime %s,JobId %s %s",
496            where, order, order, limit);
497       break;
498    default:
499       break;
500    }
501 
502    free_pool_memory(tmp);
503    free_pool_memory(where);
504 
505    Dmsg1(100, "SQL: %s\n", cmd);
506    if (!QueryDB(jcr, cmd)) {
507       bdb_unlock();
508       return NULL;
509    }
510    if (type == INCOMPLETE_JOBS) {
511       SQL_ROW row;
512       list = New(alist(10));
513       sql_data_seek(0);
514       for (int i=0; (row=sql_fetch_row()) != NULL; i++) {
515          list->append(bstrdup(row[0]));
516       }
517    }
518    sql_data_seek(0);
519    list_result(jcr, this, sendit, ctx, type);
520    sql_free_result();
521    bdb_unlock();
522    return list;
523 }
524 
525 /*
526  * List Job totals
527  *
528  */
bdb_list_job_totals(JCR * jcr,JOB_DBR * jr,DB_LIST_HANDLER * sendit,void * ctx)529 void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
530 {
531    bdb_lock();
532 
533    /* List by Job */
534    Mmsg(cmd, "SELECT  count(*) AS Jobs,sum(JobFiles) "
535       "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name");
536 
537    if (!QueryDB(jcr, cmd)) {
538       bdb_unlock();
539       return;
540    }
541 
542    list_result(jcr, this, sendit, ctx, HORZ_LIST);
543 
544    sql_free_result();
545 
546    /* Do Grand Total */
547    Mmsg(cmd, "SELECT count(*) AS Jobs,sum(JobFiles) "
548         "AS Files,sum(JobBytes) As Bytes FROM Job");
549 
550    if (!QueryDB(jcr, cmd)) {
551       bdb_unlock();
552       return;
553    }
554 
555    list_result(jcr, this, sendit, ctx, HORZ_LIST);
556 
557    sql_free_result();
558    bdb_unlock();
559 }
560 
561 /* List all file records from a job
562  * "deleted" values are described just below
563  */
bdb_list_files_for_job(JCR * jcr,JobId_t jobid,int deleted,DB_LIST_HANDLER * sendit,void * ctx)564 void BDB::bdb_list_files_for_job(JCR *jcr, JobId_t jobid, int deleted, DB_LIST_HANDLER *sendit, void *ctx)
565 {
566    char ed1[50];
567    const char *opt;
568    LIST_CTX lctx(jcr, this, sendit, ctx, HORZ_LIST);
569 
570    switch (deleted) {
571    case 0:                      /* Show only actual files */
572       opt = " AND FileIndex > 0 ";
573       break;
574    case 1:                      /* Show only deleted files */
575       opt = " AND FileIndex <= 0 ";
576       break;
577    default:                     /* Show everything */
578       opt = "";
579       break;
580    }
581 
582    bdb_lock();
583 
584    /*
585     * MySQL is different with no || operator
586     */
587    if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
588       Mmsg(cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
589            "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s %s "
590                   "UNION ALL "
591                  "SELECT PathId, FilenameId "
592                    "FROM BaseFiles JOIN File "
593                          "ON (BaseFiles.FileId = File.FileId) "
594                   "WHERE BaseFiles.JobId = %s"
595            ") AS F, Filename,Path "
596            "WHERE Filename.FilenameId=F.FilenameId "
597            "AND Path.PathId=F.PathId",
598            edit_int64(jobid, ed1), opt, ed1);
599    } else {
600       Mmsg(cmd, "SELECT Path.Path||Filename.Name AS Filename "
601            "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s %s "
602                   "UNION ALL "
603                  "SELECT PathId, FilenameId "
604                    "FROM BaseFiles JOIN File "
605                          "ON (BaseFiles.FileId = File.FileId) "
606                   "WHERE BaseFiles.JobId = %s"
607            ") AS F, Filename,Path "
608            "WHERE Filename.FilenameId=F.FilenameId "
609            "AND Path.PathId=F.PathId",
610            edit_int64(jobid, ed1), opt, ed1);
611    }
612    Dmsg1(100, "q=%s\n", cmd);
613    if (!bdb_big_sql_query(cmd, list_result, &lctx)) {
614        bdb_unlock();
615        return;
616    }
617 
618    lctx.send_dashes();
619 
620    sql_free_result();
621    bdb_unlock();
622 }
623 
bdb_list_base_files_for_job(JCR * jcr,JobId_t jobid,DB_LIST_HANDLER * sendit,void * ctx)624 void BDB::bdb_list_base_files_for_job(JCR *jcr, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
625 {
626    char ed1[50];
627    LIST_CTX lctx(jcr, this, sendit, ctx, HORZ_LIST);
628 
629    bdb_lock();
630 
631    /*
632     * Stupid MySQL is NON-STANDARD !
633     */
634    if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
635       Mmsg(cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
636            "FROM BaseFiles, File, Filename, Path "
637            "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
638            "AND BaseFiles.FileId = File.FileId "
639            "AND Filename.FilenameId=File.FilenameId "
640            "AND Path.PathId=File.PathId",
641          edit_int64(jobid, ed1));
642    } else {
643       Mmsg(cmd, "SELECT Path.Path||Filename.Name AS Filename "
644            "FROM BaseFiles, File, Filename, Path "
645            "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
646            "AND BaseFiles.FileId = File.FileId "
647            "AND Filename.FilenameId=File.FilenameId "
648            "AND Path.PathId=File.PathId",
649            edit_int64(jobid, ed1));
650    }
651 
652    if (!bdb_big_sql_query(cmd, list_result, &lctx)) {
653        bdb_unlock();
654        return;
655    }
656 
657    lctx.send_dashes();
658 
659    sql_free_result();
660    bdb_unlock();
661 }
662 
bdb_list_snapshot_records(JCR * jcr,SNAPSHOT_DBR * sdbr,DB_LIST_HANDLER * sendit,void * ctx,e_list_type type)663 void BDB::bdb_list_snapshot_records(JCR *jcr, SNAPSHOT_DBR *sdbr,
664               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
665 {
666    POOLMEM *filter = get_pool_memory(PM_MESSAGE);
667    POOLMEM *tmp    = get_pool_memory(PM_MESSAGE);
668    POOLMEM *esc    = get_pool_memory(PM_MESSAGE);
669    char ed1[50];
670 
671    bdb_lock();
672    *filter = 0;
673 
674    if (sdbr->Name[0]) {
675       bdb_escape_string(jcr, esc, sdbr->Name, strlen(sdbr->Name));
676       Mmsg(tmp, "Name='%s'", esc);
677       append_filter(filter, tmp);
678    }
679    if (sdbr->SnapshotId > 0) {
680       Mmsg(tmp, "Snapshot.SnapshotId=%d", sdbr->SnapshotId);
681       append_filter(filter, tmp);
682    }
683    if (sdbr->ClientId > 0) {
684       Mmsg(tmp, "Snapshot.ClientId=%d", sdbr->ClientId);
685       append_filter(filter, tmp);
686    }
687    if (sdbr->JobId > 0) {
688       Mmsg(tmp, "Snapshot.JobId=%d", sdbr->JobId);
689       append_filter(filter, tmp);
690    }
691    if (*sdbr->Client) {
692       bdb_escape_string(jcr, esc, sdbr->Client, strlen(sdbr->Client));
693       Mmsg(tmp, "Client.Name='%s'", esc);
694       append_filter(filter, tmp);
695    }
696    if (sdbr->Device && *(sdbr->Device)) {
697       esc = check_pool_memory_size(esc, strlen(sdbr->Device) * 2 + 1);
698       bdb_escape_string(jcr, esc, sdbr->Device, strlen(sdbr->Device));
699       Mmsg(tmp, "Device='%s'", esc);
700       append_filter(filter, tmp);
701    }
702    if (*sdbr->Type) {
703       bdb_escape_string(jcr, esc, sdbr->Type, strlen(sdbr->Type));
704       Mmsg(tmp, "Type='%s'", esc);
705       append_filter(filter, tmp);
706    }
707    if (*sdbr->created_before) {
708       bdb_escape_string(jcr, esc, sdbr->created_before, strlen(sdbr->created_before));
709       Mmsg(tmp, "CreateDate <= '%s'", esc);
710       append_filter(filter, tmp);
711    }
712    if (*sdbr->created_after) {
713       bdb_escape_string(jcr, esc, sdbr->created_after, strlen(sdbr->created_after));
714       Mmsg(tmp, "CreateDate >= '%s'", esc);
715       append_filter(filter, tmp);
716    }
717    if (sdbr->expired) {
718       Mmsg(tmp, "CreateTDate < (%s - Retention)", edit_int64(time(NULL), ed1));
719       append_filter(filter, tmp);
720    }
721    if (*sdbr->CreateDate) {
722       bdb_escape_string(jcr, esc, sdbr->CreateDate, strlen(sdbr->CreateDate));
723       Mmsg(tmp, "CreateDate = '%s'", esc);
724       append_filter(filter, tmp);
725    }
726 
727    if (sdbr->sorted_client) {
728       pm_strcat(filter, " ORDER BY Client.Name, SnapshotId DESC");
729 
730    } else {
731       pm_strcat(filter, " ORDER BY SnapshotId DESC");
732    }
733 
734    if (type == VERT_LIST || type == ARG_LIST) {
735       Mmsg(cmd, "SELECT SnapshotId, Snapshot.Name, CreateDate, Client.Name AS Client, "
736            "FileSet.FileSet AS FileSet, JobId, Volume, Device, Type, Retention, Comment "
737            "FROM Snapshot JOIN Client USING (ClientId) LEFT JOIN FileSet USING (FileSetId) %s", filter);
738 
739    } else if (type == HORZ_LIST) {
740       Mmsg(cmd, "SELECT SnapshotId, Snapshot.Name, CreateDate, Client.Name AS Client, "
741            "Device, Type "
742            "FROM Snapshot JOIN Client USING (ClientId) %s", filter);
743    }
744 
745    if (!QueryDB(jcr, cmd)) {
746       goto bail_out;
747    }
748 
749    list_result(jcr, this, sendit, ctx, type);
750 
751 bail_out:
752    sql_free_result();
753    bdb_unlock();
754 
755    free_pool_memory(filter);
756    free_pool_memory(esc);
757    free_pool_memory(tmp);
758 }
759 
760 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */
761