2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula Catalog Database List records interface routines
22 * Written by Kern Sibbald, March 2000
28 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
32 /* -----------------------------------------------------------------------
34 * Generic Routines (or almost generic)
36 * -----------------------------------------------------------------------
39 #define append_filter(buf, sql) \
42 pm_strcat(buf, " AND ");\
44 pm_strcpy(buf, " WHERE ");\
46 pm_strcat(buf, sql); \
50 * Submit general SQL query
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)
56 if (!sql_query(query, QF_STORE_RESULT)) {
57 Mmsg(errmsg, _("Query failed: %s\n"), sql_strerror());
65 list_result(jcr,this, sendit, ctx, type);
71 void BDB::bdb_list_pool_records(JCR *jcr, POOL_DBR *pdbr,
72 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
74 char esc[MAX_ESCAPE_NAME_LENGTH];
77 bdb_escape_string(jcr, esc, pdbr->Name, strlen(pdbr->Name));
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);
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");
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);
98 Mmsg(cmd, "SELECT PoolId,Name,NumVols,MaxVols,MaxVolBytes,VolRetention,Enabled,PoolType,LabelFormat "
99 "FROM Pool ORDER BY PoolId");
103 if (!QueryDB(jcr, cmd)) {
108 list_result(jcr, this, sendit, ctx, type);
114 void BDB::bdb_list_client_records(JCR *jcr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
117 if (type == VERT_LIST) {
118 Mmsg(cmd, "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,"
120 "FROM Client ORDER BY ClientId");
122 Mmsg(cmd, "SELECT ClientId,Name,FileRetention,JobRetention "
123 "FROM Client ORDER BY ClientId");
126 if (!QueryDB(jcr, cmd)) {
131 list_result(jcr, this, sendit, ctx, type);
138 * List restore objects
140 * JobId | JobIds: List RestoreObjects for specific Job(s)
141 * It is possible to specify the ObjectType using FileType field.
143 void BDB::bdb_list_restore_objects(JCR *jcr, ROBJECT_DBR *rr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
149 if (rr->JobIds && is_a_number_list(rr->JobIds)) {
152 } else if (rr->JobId) {
153 jobid = edit_int64(rr->JobId, ed1);
159 if (rr->FileType > 0) {
160 Mmsg(filter, "AND ObjectType = %d ", rr->FileType);
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());
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());
178 if (!QueryDB(jcr, cmd)) {
183 list_result(jcr, this, sendit, ctx, type);
190 * If VolumeName is non-zero, list the record for that Volume
191 * otherwise, list the Volumes in the Pool specified by PoolId
193 void BDB::bdb_list_media_records(JCR *jcr, MEDIA_DBR *mdbr,
194 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
197 char esc[MAX_ESCAPE_NAME_LENGTH];
198 const char *expiresin = expires_in[bdb_get_type_index()];
201 bdb_escape_string(jcr, esc, mdbr->VolumeName, strlen(mdbr->VolumeName));
202 const char *join = "";
203 const char *where = "";
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",
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",
239 edit_int64(mdbr->PoolId, ed1),
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",
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",
261 edit_int64(mdbr->PoolId, ed1),
266 Dmsg1(DT_SQL|50, "q=%s\n", cmd);
267 if (!QueryDB(jcr, cmd)) {
272 list_result(jcr, this, sendit, ctx, type);
278 void BDB::bdb_list_jobmedia_records(JCR *jcr, uint32_t JobId,
279 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
284 const char *join = "";
285 const char *where = "";
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,"
292 "FROM JobMedia JOIN Media USING (MediaId) %s "
293 "WHERE JobMedia.JobId=%s %s",
295 edit_int64(JobId, ed1),
298 Mmsg(cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
299 "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
301 "FROM JobMedia JOIN Media USING (MediaId) %s %s",
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",
312 edit_int64(JobId, ed1),
315 Mmsg(cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
316 "FROM JobMedia JOIN Media USING (MediaId) %s %s",
321 Dmsg1(DT_SQL|50, "q=%s\n", cmd);
323 if (!QueryDB(jcr, cmd)) {
328 list_result(jcr, this, sendit, ctx, 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)
338 POOL_MEM str_limit(PM_MESSAGE);
339 POOL_MEM str_jobids(PM_MESSAGE);
342 Mmsg(str_limit, " LIMIT %d", limit);
345 if (JobIds && JobIds[0]) {
346 Mmsg(str_jobids, " AND (Job.PriorJobId IN (%s) OR Job.JobId IN (%s)) ",
352 "SELECT DISTINCT Job.PriorJobId AS JobId, Job.Job, "
353 "Job.JobId AS CopyJobId, Media.MediaType "
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());
360 if (!QueryDB(jcr, cmd)) {
364 if (sql_num_rows()) {
365 if (JobIds && JobIds[0]) {
366 sendit(ctx, _("These JobIds have copies as follows:\n"));
368 sendit(ctx, _("The catalog contains copies as follows:\n"));
371 list_result(jcr, this, sendit, ctx, type);
380 void BDB::bdb_list_joblog_records(JCR *jcr, uint32_t JobId,
381 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
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));
393 Mmsg(cmd, "SELECT LogText FROM Log "
394 "WHERE Log.JobId=%s ORDER BY LogId ASC", edit_int64(JobId, ed1));
396 if (!QueryDB(jcr, cmd)) {
400 list_result(jcr, this, sendit, ctx, type);
410 * List Job record(s) that match JOB_DBR
412 * Currently, we return all jobs or if jr->JobId is set,
413 * only the job with the specified id.
415 alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
416 void *ctx, e_list_type type)
420 char esc[MAX_ESCAPE_NAME_LENGTH];
422 POOLMEM *where = get_pool_memory(PM_MESSAGE);
423 POOLMEM *tmp = get_pool_memory(PM_MESSAGE);
424 const char *order = "ASC";
428 if (jr->order == 1) {
432 snprintf(limit, sizeof(limit), " LIMIT %d", jr->limit);
437 bdb_escape_string(jcr, esc, jr->Name, strlen(jr->Name));
438 Mmsg(tmp, " Job.Name='%s' ", esc);
439 append_filter(where, tmp);
441 } else if (jr->JobId != 0) {
442 Mmsg(tmp, " Job.JobId=%s ", edit_int64(jr->JobId, ed1));
443 append_filter(where, tmp);
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);
451 if (type == INCOMPLETE_JOBS && jr->JobStatus == JS_FatalError) {
452 Mmsg(tmp, " Job.JobStatus IN ('E', 'f') ");
453 append_filter(where, tmp);
455 } else if (jr->JobStatus) {
456 Mmsg(tmp, " Job.JobStatus='%c' ", jr->JobStatus);
457 append_filter(where, tmp);
461 Mmsg(tmp, " Job.Type='%c' ", jr->JobType);
462 append_filter(where, tmp);
465 if (jr->JobErrors > 0) {
466 Mmsg(tmp, " Job.JobErrors > 0 ");
467 append_filter(where, tmp);
470 if (jr->ClientId > 0) {
471 Mmsg(tmp, " Job.ClientId=%s ", edit_int64(jr->ClientId, ed1));
472 append_filter(where, tmp);
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);
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);
493 case INCOMPLETE_JOBS:
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);
503 free_pool_memory(tmp);
504 free_pool_memory(where);
506 Dmsg1(100, "SQL: %s\n", cmd);
507 if (!QueryDB(jcr, cmd)) {
511 if (type == INCOMPLETE_JOBS) {
513 list = New(alist(10));
515 for (int i=0; (row=sql_fetch_row()) != NULL; i++) {
516 list->append(bstrdup(row[0]));
520 list_result(jcr, this, sendit, ctx, type);
530 void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
535 Mmsg(cmd, "SELECT count(*) AS Jobs,sum(JobFiles) "
536 "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name");
538 if (!QueryDB(jcr, cmd)) {
543 list_result(jcr, this, sendit, ctx, HORZ_LIST);
548 Mmsg(cmd, "SELECT count(*) AS Jobs,sum(JobFiles) "
549 "AS Files,sum(JobBytes) As Bytes FROM Job");
551 if (!QueryDB(jcr, cmd)) {
556 list_result(jcr, this, sendit, ctx, HORZ_LIST);
562 /* List all file records from a job
563 * "deleted" values are described just below
565 void BDB::bdb_list_files_for_job(JCR *jcr, JobId_t jobid, int deleted, DB_LIST_HANDLER *sendit, void *ctx)
569 LIST_CTX lctx(jcr, this, sendit, ctx, HORZ_LIST);
572 case 0: /* Show only actual files */
573 opt = " AND FileIndex <> 0 ";
575 case 1: /* Show only deleted files */
576 opt = " AND FileIndex = 0 ";
578 default: /* Show everything */
586 * Stupid MySQL is NON-STANDARD !
588 if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
589 Mmsg(cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
590 "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s %s "
592 "SELECT PathId, FilenameId "
593 "FROM BaseFiles JOIN File "
594 "ON (BaseFiles.FileId = File.FileId) "
595 "WHERE BaseFiles.JobId = %s"
596 ") AS F, Filename,Path "
597 "WHERE Filename.FilenameId=F.FilenameId "
598 "AND Path.PathId=F.PathId",
599 edit_int64(jobid, ed1), opt, ed1);
601 Mmsg(cmd, "SELECT Path.Path||Filename.Name AS Filename "
602 "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s %s "
604 "SELECT PathId, FilenameId "
605 "FROM BaseFiles JOIN File "
606 "ON (BaseFiles.FileId = File.FileId) "
607 "WHERE BaseFiles.JobId = %s"
608 ") AS F, Filename,Path "
609 "WHERE Filename.FilenameId=F.FilenameId "
610 "AND Path.PathId=F.PathId",
611 edit_int64(jobid, ed1), opt, ed1);
613 Dmsg1(100, "q=%s\n", cmd);
614 if (!bdb_big_sql_query(cmd, list_result, &lctx)) {
625 void BDB::bdb_list_base_files_for_job(JCR *jcr, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
628 LIST_CTX lctx(jcr, this, sendit, ctx, HORZ_LIST);
633 * Stupid MySQL is NON-STANDARD !
635 if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
636 Mmsg(cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename "
637 "FROM BaseFiles, File, Filename, Path "
638 "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
639 "AND BaseFiles.FileId = File.FileId "
640 "AND Filename.FilenameId=File.FilenameId "
641 "AND Path.PathId=File.PathId",
642 edit_int64(jobid, ed1));
644 Mmsg(cmd, "SELECT Path.Path||Filename.Name AS Filename "
645 "FROM BaseFiles, File, Filename, Path "
646 "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
647 "AND BaseFiles.FileId = File.FileId "
648 "AND Filename.FilenameId=File.FilenameId "
649 "AND Path.PathId=File.PathId",
650 edit_int64(jobid, ed1));
653 if (!bdb_big_sql_query(cmd, list_result, &lctx)) {
664 void BDB::bdb_list_snapshot_records(JCR *jcr, SNAPSHOT_DBR *sdbr,
665 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
667 POOLMEM *filter = get_pool_memory(PM_MESSAGE);
668 POOLMEM *tmp = get_pool_memory(PM_MESSAGE);
669 POOLMEM *esc = get_pool_memory(PM_MESSAGE);
676 bdb_escape_string(jcr, esc, sdbr->Name, strlen(sdbr->Name));
677 Mmsg(tmp, "Name='%s'", esc);
678 append_filter(filter, tmp);
680 if (sdbr->SnapshotId > 0) {
681 Mmsg(tmp, "Snapshot.SnapshotId=%d", sdbr->SnapshotId);
682 append_filter(filter, tmp);
684 if (sdbr->ClientId > 0) {
685 Mmsg(tmp, "Snapshot.ClientId=%d", sdbr->ClientId);
686 append_filter(filter, tmp);
688 if (sdbr->JobId > 0) {
689 Mmsg(tmp, "Snapshot.JobId=%d", sdbr->JobId);
690 append_filter(filter, tmp);
693 bdb_escape_string(jcr, esc, sdbr->Client, strlen(sdbr->Client));
694 Mmsg(tmp, "Client.Name='%s'", esc);
695 append_filter(filter, tmp);
697 if (sdbr->Device && *(sdbr->Device)) {
698 esc = check_pool_memory_size(esc, strlen(sdbr->Device) * 2 + 1);
699 bdb_escape_string(jcr, esc, sdbr->Device, strlen(sdbr->Device));
700 Mmsg(tmp, "Device='%s'", esc);
701 append_filter(filter, tmp);
704 bdb_escape_string(jcr, esc, sdbr->Type, strlen(sdbr->Type));
705 Mmsg(tmp, "Type='%s'", esc);
706 append_filter(filter, tmp);
708 if (*sdbr->created_before) {
709 bdb_escape_string(jcr, esc, sdbr->created_before, strlen(sdbr->created_before));
710 Mmsg(tmp, "CreateDate <= '%s'", esc);
711 append_filter(filter, tmp);
713 if (*sdbr->created_after) {
714 bdb_escape_string(jcr, esc, sdbr->created_after, strlen(sdbr->created_after));
715 Mmsg(tmp, "CreateDate >= '%s'", esc);
716 append_filter(filter, tmp);
719 Mmsg(tmp, "CreateTDate < (%s - Retention)", edit_int64(time(NULL), ed1));
720 append_filter(filter, tmp);
722 if (*sdbr->CreateDate) {
723 bdb_escape_string(jcr, esc, sdbr->CreateDate, strlen(sdbr->CreateDate));
724 Mmsg(tmp, "CreateDate = '%s'", esc);
725 append_filter(filter, tmp);
728 if (sdbr->sorted_client) {
729 pm_strcat(filter, " ORDER BY Client.Name, SnapshotId DESC");
732 pm_strcat(filter, " ORDER BY SnapshotId DESC");
735 if (type == VERT_LIST || type == ARG_LIST) {
736 Mmsg(cmd, "SELECT SnapshotId, Snapshot.Name, CreateDate, Client.Name AS Client, "
737 "FileSet.FileSet AS FileSet, JobId, Volume, Device, Type, Retention, Comment "
738 "FROM Snapshot JOIN Client USING (ClientId) LEFT JOIN FileSet USING (FileSetId) %s", filter);
740 } else if (type == HORZ_LIST) {
741 Mmsg(cmd, "SELECT SnapshotId, Snapshot.Name, CreateDate, Client.Name AS Client, "
743 "FROM Snapshot JOIN Client USING (ClientId) %s", filter);
746 if (!QueryDB(jcr, cmd)) {
750 list_result(jcr, this, sendit, ctx, type);
756 free_pool_memory(filter);
757 free_pool_memory(esc);
758 free_pool_memory(tmp);
761 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */