2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula Catalog Database Get record interface routines
30 * Note, these routines generally get a record by id or
31 * by name. If more logic is involved, the routine
34 * Kern Sibbald, March 2000
40 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
46 /* -----------------------------------------------------------------------
48 * Generic Routines (or almost generic)
50 * -----------------------------------------------------------------------
53 /* Forward referenced functions */
54 static int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr);
55 static int db_get_filename_record(JCR *jcr, B_DB *mdb);
59 * Given a full filename (with path), look up the File record
60 * (with attributes) in the database.
62 * Returns: 0 on failure
63 * 1 on success with the File record in FILE_DBR
65 int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
68 Dmsg1(100, "db_get_file_att_record fname=%s \n", fname);
71 split_path_and_file(jcr, mdb, fname);
73 fdbr->FilenameId = db_get_filename_record(jcr, mdb);
75 fdbr->PathId = db_get_path_record(jcr, mdb);
77 stat = db_get_file_record(jcr, mdb, jr, fdbr);
87 * Returns: 0 on failure
90 * DO NOT use Jmsg in this routine.
92 * Note in this routine, we do not use Jmsg because it may be
93 * called to get attributes of a non-existent file, which is
94 * "normal" if a new file is found during Verify.
96 * The following is a bit of a kludge: because we always backup a
97 * directory entry, we can end up with two copies of the directory
98 * in the backup. One is when we encounter the directory and find
99 * we cannot recurse into it, and the other is when we find an
100 * explicit mention of the directory. This can also happen if the
101 * use includes the directory twice. In this case, Verify
102 * VolumeToCatalog fails because we have two copies in the catalog,
103 * and only the first one is marked (twice). So, when calling from Verify,
104 * VolumeToCatalog jr is not NULL and we know jr->FileIndex is the fileindex
105 * of the version of the directory/file we actually want and do
106 * a more explicit SQL search.
109 int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
113 char ed1[50], ed2[50], ed3[50];
116 if (jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG) {
118 "SELECT FileId, LStat, MD5 FROM File,Job WHERE "
119 "File.JobId=Job.JobId AND File.PathId=%s AND "
120 "File.FilenameId=%s AND Job.Type='B' AND Job.JobStatus IN ('T','W') AND "
121 "ClientId=%s ORDER BY StartTime DESC LIMIT 1",
122 edit_int64(fdbr->PathId, ed1),
123 edit_int64(fdbr->FilenameId, ed2),
124 edit_int64(jr->ClientId,ed3));
125 } else if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG) {
127 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
128 "File.FilenameId=%s AND File.FileIndex=%u",
129 edit_int64(fdbr->JobId, ed1),
130 edit_int64(fdbr->PathId, ed2),
131 edit_int64(fdbr->FilenameId,ed3),
135 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
136 "File.FilenameId=%s",
137 edit_int64(fdbr->JobId, ed1),
138 edit_int64(fdbr->PathId, ed2),
139 edit_int64(fdbr->FilenameId,ed3));
141 Dmsg3(450, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
142 fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
144 Dmsg1(100, "Query=%s\n", mdb->cmd);
146 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
147 num_rows = sql_num_rows(mdb);
148 Dmsg1(050, "get_file_record num_rows=%d\n", num_rows);
150 if ((row = sql_fetch_row(mdb)) == NULL) {
151 Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
153 fdbr->FileId = (FileId_t)str_to_int64(row[0]);
154 bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
155 bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
158 Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
160 edit_int64(fdbr->PathId, ed1),
161 edit_int64(fdbr->FilenameId, ed2));
162 Dmsg1(000, "=== Problem! %s", mdb->errmsg);
166 Mmsg2(mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"),
167 edit_int64(fdbr->PathId, ed1),
168 edit_int64(fdbr->FilenameId, ed2));
170 sql_free_result(mdb);
172 Mmsg(mdb->errmsg, _("File record not found in Catalog.\n"));
179 * Get Filename record
180 * Returns: 0 on failure
181 * FilenameId on success
183 * DO NOT use Jmsg in this routine (see notes for get_file_record)
185 static int db_get_filename_record(JCR *jcr, B_DB *mdb)
191 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
192 db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
194 Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
195 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
197 num_rows = sql_num_rows(mdb);
199 Mmsg2(mdb->errmsg, _("More than one Filename!: %s for file: %s\n"),
200 edit_uint64(num_rows, ed1), mdb->fname);
201 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
204 if ((row = sql_fetch_row(mdb)) == NULL) {
205 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
207 FilenameId = str_to_int64(row[0]);
208 if (FilenameId <= 0) {
209 Mmsg2(mdb->errmsg, _("Get DB Filename record %s found bad record: %d\n"),
210 mdb->cmd, FilenameId);
215 Mmsg1(mdb->errmsg, _("Filename record: %s not found.\n"), mdb->fname);
217 sql_free_result(mdb);
219 Mmsg(mdb->errmsg, _("Filename record: %s not found in Catalog.\n"), mdb->fname);
226 * Returns: 0 on failure
229 * DO NOT use Jmsg in this routine (see notes for get_file_record)
231 int db_get_path_record(JCR *jcr, B_DB *mdb)
237 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
238 db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
240 if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
241 strcmp(mdb->cached_path, mdb->path) == 0) {
242 return mdb->cached_path_id;
245 Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
247 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
249 num_rows = sql_num_rows(mdb);
251 Mmsg2(mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
252 edit_uint64(num_rows, ed1), mdb->path);
253 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
255 /* Even if there are multiple paths, take the first one */
257 if ((row = sql_fetch_row(mdb)) == NULL) {
258 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
260 PathId = str_to_int64(row[0]);
262 Mmsg2(mdb->errmsg, _("Get DB path record %s found bad record: %s\n"),
263 mdb->cmd, edit_int64(PathId, ed1));
267 if (PathId != mdb->cached_path_id) {
268 mdb->cached_path_id = PathId;
269 mdb->cached_path_len = mdb->pnl;
270 pm_strcpy(mdb->cached_path, mdb->path);
275 Mmsg1(mdb->errmsg, _("Path record: %s not found.\n"), mdb->path);
277 sql_free_result(mdb);
279 Mmsg(mdb->errmsg, _("Path record: %s not found in Catalog.\n"), mdb->path);
286 * Get Job record for given JobId or Job name
287 * Returns: false on failure
290 bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
294 char esc[MAX_ESCAPE_NAME_LENGTH];
297 if (jr->JobId == 0) {
298 mdb->db_escape_string(jcr, esc, jr->Job, strlen(jr->Job));
299 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
300 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
301 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
302 "SchedTime,RealEndTime,ReadBytes,HasBase,PurgedFiles "
303 "FROM Job WHERE Job='%s'", esc);
305 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
306 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
307 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
308 "SchedTime,RealEndTime,ReadBytes,HasBase,PurgedFiles "
309 "FROM Job WHERE JobId=%s",
310 edit_int64(jr->JobId, ed1));
313 if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
315 return false; /* failed */
317 if ((row = sql_fetch_row(mdb)) == NULL) {
318 Mmsg1(mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1));
319 sql_free_result(mdb);
321 return false; /* failed */
324 jr->VolSessionId = str_to_uint64(row[0]);
325 jr->VolSessionTime = str_to_uint64(row[1]);
326 jr->PoolId = str_to_int64(row[2]);
327 bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime));
328 bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime));
329 jr->JobFiles = str_to_int64(row[5]);
330 jr->JobBytes = str_to_int64(row[6]);
331 jr->JobTDate = str_to_int64(row[7]);
332 bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job));
333 jr->JobStatus = row[9]!=NULL?(int)*row[9]:JS_FatalError;
334 jr->JobType = row[10]!=NULL?(int)*row[10]:JT_BACKUP;
335 jr->JobLevel = row[11]!=NULL?(int)*row[11]:L_NONE;
336 jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)"");
337 bstrncpy(jr->Name, row[13]!=NULL?row[13]:"", sizeof(jr->Name));
338 jr->PriorJobId = str_to_uint64(row[14]!=NULL?row[14]:(char *)"");
339 bstrncpy(jr->cRealEndTime, row[15]!=NULL?row[15]:"", sizeof(jr->cRealEndTime));
340 if (jr->JobId == 0) {
341 jr->JobId = str_to_int64(row[16]);
343 jr->FileSetId = str_to_int64(row[17]);
344 bstrncpy(jr->cSchedTime, row[3]!=NULL?row[18]:"", sizeof(jr->cSchedTime));
345 bstrncpy(jr->cRealEndTime, row[3]!=NULL?row[19]:"", sizeof(jr->cRealEndTime));
346 jr->ReadBytes = str_to_int64(row[20]);
347 jr->StartTime = str_to_utime(jr->cStartTime);
348 jr->SchedTime = str_to_utime(jr->cSchedTime);
349 jr->EndTime = str_to_utime(jr->cEndTime);
350 jr->RealEndTime = str_to_utime(jr->cRealEndTime);
351 jr->HasBase = str_to_int64(row[21]);
352 jr->PurgedFiles = str_to_int64(row[22]);
353 sql_free_result(mdb);
360 * Find VolumeNames for a given JobId
361 * Returns: 0 on error or no Volumes found
362 * number of volumes on success
363 * Volumes are concatenated in VolumeNames
364 * separated by a vertical bar (|) in the order
365 * that they were written.
367 * Returns: number of volumes on success
369 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **VolumeNames)
378 /* Get one entry per VolumeName, but "sort" by VolIndex */
380 "SELECT VolumeName,MAX(VolIndex) FROM JobMedia,Media WHERE "
381 "JobMedia.JobId=%s AND JobMedia.MediaId=Media.MediaId "
382 "GROUP BY VolumeName "
383 "ORDER BY 2 ASC", edit_int64(JobId,ed1));
385 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
387 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
388 num_rows = sql_num_rows(mdb);
389 Dmsg1(130, "Num rows=%d\n", num_rows);
391 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
395 for (i=0; i < stat; i++) {
396 if ((row = sql_fetch_row(mdb)) == NULL) {
397 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
398 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
402 if (*VolumeNames[0] != 0) {
403 pm_strcat(VolumeNames, "|");
405 pm_strcat(VolumeNames, row[0]);
409 sql_free_result(mdb);
411 Mmsg(mdb->errmsg, _("No Volume for JobId %d found in Catalog.\n"), JobId);
418 * Find Volume parameters for a give JobId
419 * Returns: 0 on error or no Volumes found
420 * number of volumes on success
421 * List of Volumes and start/end file/blocks (malloced structure!)
423 * Returns: number of volumes on success
425 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS **VolParams)
431 VOL_PARAMS *Vols = NULL;
436 "SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile,"
437 "JobMedia.EndFile,StartBlock,JobMedia.EndBlock,"
438 "Slot,StorageId,InChanger"
439 " FROM JobMedia,Media WHERE JobMedia.JobId=%s"
440 " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId",
441 edit_int64(JobId, ed1));
443 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
444 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
445 num_rows = sql_num_rows(mdb);
446 Dmsg1(200, "Num rows=%d\n", num_rows);
448 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
454 *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
455 SId = (DBId_t *)malloc(stat * sizeof(DBId_t));
457 for (i=0; i < stat; i++) {
458 if ((row = sql_fetch_row(mdb)) == NULL) {
459 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
460 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
465 uint32_t StartBlock, EndBlock, StartFile, EndFile;
466 bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH);
467 bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH);
468 Vols[i].FirstIndex = str_to_uint64(row[2]);
469 Vols[i].LastIndex = str_to_uint64(row[3]);
470 StartFile = str_to_uint64(row[4]);
471 EndFile = str_to_uint64(row[5]);
472 StartBlock = str_to_uint64(row[6]);
473 EndBlock = str_to_uint64(row[7]);
474 Vols[i].StartAddr = (((uint64_t)StartFile)<<32) | StartBlock;
475 Vols[i].EndAddr = (((uint64_t)EndFile)<<32) | EndBlock;
476 Vols[i].Slot = str_to_uint64(row[8]);
477 StorageId = str_to_uint64(row[9]);
478 Vols[i].InChanger = str_to_uint64(row[10]);
479 Vols[i].Storage[0] = 0;
483 for (i=0; i < stat; i++) {
485 Mmsg(mdb->cmd, "SELECT Name from Storage WHERE StorageId=%s",
486 edit_int64(SId[i], ed1));
487 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
488 if ((row = sql_fetch_row(mdb)) && row[0]) {
489 bstrncpy(Vols[i].Storage, row[0], MAX_NAME_LENGTH);
498 sql_free_result(mdb);
507 * Get the number of pool records
509 * Returns: -1 on failure
512 int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
517 Mmsg(mdb->cmd, "SELECT count(*) from Pool");
518 stat = get_sql_record_max(jcr, mdb);
524 * This function returns a list of all the Pool record ids.
525 * The caller must free ids if non-NULL.
527 * Returns 0: on failure
530 int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
539 Mmsg(mdb->cmd, "SELECT PoolId FROM Pool");
540 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
541 *num_ids = sql_num_rows(mdb);
543 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
544 while ((row = sql_fetch_row(mdb)) != NULL) {
545 id[i++] = str_to_uint64(row[0]);
549 sql_free_result(mdb);
552 Mmsg(mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
553 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
561 * This function returns a list of all the Client record ids.
562 * The caller must free ids if non-NULL.
564 * Returns 0: on failure
567 int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
576 Mmsg(mdb->cmd, "SELECT ClientId FROM Client ORDER BY Name");
577 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
578 *num_ids = sql_num_rows(mdb);
580 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
581 while ((row = sql_fetch_row(mdb)) != NULL) {
582 id[i++] = str_to_uint64(row[0]);
586 sql_free_result(mdb);
589 Mmsg(mdb->errmsg, _("Client id select failed: ERR=%s\n"), sql_strerror(mdb));
590 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
601 * If the PoolId is non-zero, we get its record,
602 * otherwise, we search on the PoolName
604 * Returns: false on failure
607 bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
613 char esc[MAX_ESCAPE_NAME_LENGTH];
616 if (pdbr->PoolId != 0) { /* find by id */
618 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
619 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
620 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
621 "ActionOnPurge FROM Pool WHERE Pool.PoolId=%s",
622 edit_int64(pdbr->PoolId, ed1));
623 } else { /* find by name */
624 mdb->db_escape_string(jcr, esc, pdbr->Name, strlen(pdbr->Name));
626 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
627 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
628 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
629 "ActionOnPurge FROM Pool WHERE Pool.Name='%s'", esc);
631 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
632 num_rows = sql_num_rows(mdb);
635 Mmsg1(mdb->errmsg, _("More than one Pool!: %s\n"),
636 edit_uint64(num_rows, ed1));
637 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
638 } else if (num_rows == 1) {
639 if ((row = sql_fetch_row(mdb)) == NULL) {
640 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
641 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
643 pdbr->PoolId = str_to_int64(row[0]);
644 bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name));
645 pdbr->NumVols = str_to_int64(row[2]);
646 pdbr->MaxVols = str_to_int64(row[3]);
647 pdbr->UseOnce = str_to_int64(row[4]);
648 pdbr->UseCatalog = str_to_int64(row[5]);
649 pdbr->AcceptAnyVolume = str_to_int64(row[6]);
650 pdbr->AutoPrune = str_to_int64(row[7]);
651 pdbr->Recycle = str_to_int64(row[8]);
652 pdbr->VolRetention = str_to_int64(row[9]);
653 pdbr->VolUseDuration = str_to_int64(row[10]);
654 pdbr->MaxVolJobs = str_to_int64(row[11]);
655 pdbr->MaxVolFiles = str_to_int64(row[12]);
656 pdbr->MaxVolBytes = str_to_uint64(row[13]);
657 bstrncpy(pdbr->PoolType, row[14]!=NULL?row[14]:"", sizeof(pdbr->PoolType));
658 pdbr->LabelType = str_to_int64(row[15]);
659 bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat));
660 pdbr->RecyclePoolId = str_to_int64(row[17]);
661 pdbr->ScratchPoolId = str_to_int64(row[18]);
662 pdbr->ActionOnPurge = str_to_int32(row[19]);
666 sql_free_result(mdb);
670 Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
671 edit_int64(pdbr->PoolId, ed1));
672 NumVols = get_sql_record_max(jcr, mdb);
673 Dmsg2(400, "Actual NumVols=%d Pool NumVols=%d\n", NumVols, pdbr->NumVols);
674 if (NumVols != pdbr->NumVols) {
675 pdbr->NumVols = NumVols;
676 db_update_pool_record(jcr, mdb, pdbr);
679 Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n"));
687 * If the ClientId is non-zero, we get its record,
688 * otherwise, we search on the Client Name
690 * Returns: 0 on failure
693 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
699 char esc[MAX_ESCAPE_NAME_LENGTH];
702 if (cdbr->ClientId != 0) { /* find by id */
704 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
705 "FROM Client WHERE Client.ClientId=%s",
706 edit_int64(cdbr->ClientId, ed1));
707 } else { /* find by name */
708 mdb->db_escape_string(jcr, esc, cdbr->Name, strlen(cdbr->Name));
710 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
711 "FROM Client WHERE Client.Name='%s'", esc);
714 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
715 num_rows = sql_num_rows(mdb);
717 Mmsg1(mdb->errmsg, _("More than one Client!: %s\n"),
718 edit_uint64(num_rows, ed1));
719 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
720 } else if (num_rows == 1) {
721 if ((row = sql_fetch_row(mdb)) == NULL) {
722 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
723 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
725 cdbr->ClientId = str_to_int64(row[0]);
726 bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name));
727 bstrncpy(cdbr->Uname, row[2]!=NULL?row[2]:"", sizeof(cdbr->Uname));
728 cdbr->AutoPrune = str_to_int64(row[3]);
729 cdbr->FileRetention = str_to_int64(row[4]);
730 cdbr->JobRetention = str_to_int64(row[5]);
734 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
736 sql_free_result(mdb);
738 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
747 * Returns: 0 on failure
750 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
754 char esc[MAX_ESCAPE_NAME_LENGTH];
757 mdb->db_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
759 Mmsg(mdb->cmd, select_counter_values[mdb->db_get_type_index()], esc);
760 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
761 num_rows = sql_num_rows(mdb);
763 /* If more than one, report error, but return first row */
765 Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), num_rows);
766 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
769 if ((row = sql_fetch_row(mdb)) == NULL) {
770 Mmsg1(mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb));
771 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
772 sql_free_result(mdb);
776 cr->MinValue = str_to_int64(row[0]);
777 cr->MaxValue = str_to_int64(row[1]);
778 cr->CurrentValue = str_to_int64(row[2]);
780 bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter));
782 cr->WrapCounter[0] = 0;
784 sql_free_result(mdb);
788 sql_free_result(mdb);
790 Mmsg(mdb->errmsg, _("Counter record: %s not found in Catalog.\n"), cr->Counter);
799 * If the FileSetId is non-zero, we get its record,
800 * otherwise, we search on the name
802 * Returns: 0 on failure
805 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
811 char esc[MAX_ESCAPE_NAME_LENGTH];
814 if (fsr->FileSetId != 0) { /* find by id */
816 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
817 "WHERE FileSetId=%s",
818 edit_int64(fsr->FileSetId, ed1));
819 } else { /* find by name */
820 mdb->db_escape_string(jcr, esc, fsr->FileSet, strlen(fsr->FileSet));
822 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
823 "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", esc);
826 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
827 num_rows = sql_num_rows(mdb);
830 Mmsg1(mdb->errmsg, _("Error got %s FileSets but expected only one!\n"),
831 edit_uint64(num_rows, ed1));
832 sql_data_seek(mdb, num_rows-1);
834 if ((row = sql_fetch_row(mdb)) == NULL) {
835 Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
837 fsr->FileSetId = str_to_int64(row[0]);
838 bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
839 bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
840 bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime));
841 stat = fsr->FileSetId;
843 sql_free_result(mdb);
845 Mmsg(mdb->errmsg, _("FileSet record not found in Catalog.\n"));
853 * Get the number of Media records
855 * Returns: -1 on failure
858 int db_get_num_media_records(JCR *jcr, B_DB *mdb)
863 Mmsg(mdb->cmd, "SELECT count(*) from Media");
864 stat = get_sql_record_max(jcr, mdb);
870 * This function returns a list of all the Media record ids for
871 * the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
872 * VolumeName if specified
873 * The caller must free ids if non-NULL.
875 * Returns false: on failure
878 bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, int *num_ids, uint32_t *ids[])
885 char buf[MAX_NAME_LENGTH*3]; /* Can contain MAX_NAME_LENGTH*2+1 + AND ....='' */
886 char esc[MAX_NAME_LENGTH*2+1];
891 Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE Recycle=%d AND Enabled=%d ",
892 mr->Recycle, mr->Enabled);
894 if (*mr->MediaType) {
895 db_escape_string(jcr, mdb, esc, mr->MediaType, strlen(mr->MediaType));
896 bsnprintf(buf, sizeof(buf), "AND MediaType='%s' ", esc);
897 pm_strcat(mdb->cmd, buf);
901 bsnprintf(buf, sizeof(buf), "AND StorageId=%s ", edit_uint64(mr->StorageId, ed1));
902 pm_strcat(mdb->cmd, buf);
906 bsnprintf(buf, sizeof(buf), "AND PoolId=%s ", edit_uint64(mr->PoolId, ed1));
907 pm_strcat(mdb->cmd, buf);
911 bsnprintf(buf, sizeof(buf), "AND VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
912 pm_strcat(mdb->cmd, buf);
915 if (*mr->VolumeName) {
916 db_escape_string(jcr, mdb, esc, mr->VolumeName, strlen(mr->VolumeName));
917 bsnprintf(buf, sizeof(buf), "AND VolumeName = '%s' ", esc);
918 pm_strcat(mdb->cmd, buf);
921 if (*mr->VolStatus) {
922 db_escape_string(jcr, mdb, esc, mr->VolStatus, strlen(mr->VolStatus));
923 bsnprintf(buf, sizeof(buf), "AND VolStatus = '%s' ", esc);
924 pm_strcat(mdb->cmd, buf);
927 Dmsg1(100, "q=%s\n", mdb->cmd);
929 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
930 *num_ids = sql_num_rows(mdb);
932 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
933 while ((row = sql_fetch_row(mdb)) != NULL) {
934 id[i++] = str_to_uint64(row[0]);
938 sql_free_result(mdb);
941 Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
942 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
951 * This function returns a list of all the DBIds that are returned
954 * Returns false: on failure
957 bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids)
965 if (QUERY_DB(jcr, mdb, query.c_str())) {
966 ids.num_ids = sql_num_rows(mdb);
967 if (ids.num_ids > 0) {
968 if (ids.max_ids < ids.num_ids) {
970 ids.DBId = (DBId_t *)malloc(ids.num_ids * sizeof(DBId_t));
972 while ((row = sql_fetch_row(mdb)) != NULL) {
973 ids.DBId[i++] = str_to_uint64(row[0]);
976 sql_free_result(mdb);
979 Mmsg(mdb->errmsg, _("query dbids failed: ERR=%s\n"), sql_strerror(mdb));
980 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
990 * Returns: false: on failure
993 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
999 char esc[MAX_ESCAPE_NAME_LENGTH];
1002 if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
1003 Mmsg(mdb->cmd, "SELECT count(*) from Media");
1004 mr->MediaId = get_sql_record_max(jcr, mdb);
1008 if (mr->MediaId != 0) { /* find by id */
1009 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
1010 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
1011 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
1012 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
1013 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
1014 "Enabled,LocationId,RecycleCount,InitialWrite,"
1015 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
1016 "FROM Media WHERE MediaId=%s",
1017 edit_int64(mr->MediaId, ed1));
1018 } else { /* find by name */
1019 mdb->db_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
1020 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
1021 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
1022 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
1023 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
1024 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
1025 "Enabled,LocationId,RecycleCount,InitialWrite,"
1026 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
1027 "FROM Media WHERE VolumeName='%s'", esc);
1030 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1032 num_rows = sql_num_rows(mdb);
1034 Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
1035 edit_uint64(num_rows, ed1));
1036 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1037 } else if (num_rows == 1) {
1038 if ((row = sql_fetch_row(mdb)) == NULL) {
1039 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
1040 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1043 mr->MediaId = str_to_int64(row[0]);
1044 bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
1045 mr->VolJobs = str_to_int64(row[2]);
1046 mr->VolFiles = str_to_int64(row[3]);
1047 mr->VolBlocks = str_to_int64(row[4]);
1048 mr->VolBytes = str_to_uint64(row[5]);
1049 mr->VolMounts = str_to_int64(row[6]);
1050 mr->VolErrors = str_to_int64(row[7]);
1051 mr->VolWrites = str_to_int64(row[8]);
1052 mr->MaxVolBytes = str_to_uint64(row[9]);
1053 mr->VolCapacityBytes = str_to_uint64(row[10]);
1054 bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
1055 bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
1056 mr->PoolId = str_to_int64(row[13]);
1057 mr->VolRetention = str_to_uint64(row[14]);
1058 mr->VolUseDuration = str_to_uint64(row[15]);
1059 mr->MaxVolJobs = str_to_int64(row[16]);
1060 mr->MaxVolFiles = str_to_int64(row[17]);
1061 mr->Recycle = str_to_int64(row[18]);
1062 mr->Slot = str_to_int64(row[19]);
1063 bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
1064 mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
1065 bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
1066 mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
1067 mr->InChanger = str_to_uint64(row[22]);
1068 mr->EndFile = str_to_uint64(row[23]);
1069 mr->EndBlock = str_to_uint64(row[24]);
1070 mr->VolParts = str_to_int64(row[25]);
1071 mr->LabelType = str_to_int64(row[26]);
1072 bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
1073 mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
1074 mr->StorageId = str_to_int64(row[28]);
1075 mr->Enabled = str_to_int64(row[29]);
1076 mr->LocationId = str_to_int64(row[30]);
1077 mr->RecycleCount = str_to_int64(row[31]);
1078 bstrncpy(mr->cInitialWrite, row[32]!=NULL?row[32]:"", sizeof(mr->cInitialWrite));
1079 mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
1080 mr->ScratchPoolId = str_to_int64(row[33]);
1081 mr->RecyclePoolId = str_to_int64(row[34]);
1082 mr->VolReadTime = str_to_int64(row[35]);
1083 mr->VolWriteTime = str_to_int64(row[36]);
1084 mr->ActionOnPurge = str_to_int32(row[37]);
1089 if (mr->MediaId != 0) {
1090 Mmsg1(mdb->errmsg, _("Media record MediaId=%s not found.\n"),
1091 edit_int64(mr->MediaId, ed1));
1093 Mmsg1(mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"),
1097 sql_free_result(mdb);
1099 if (mr->MediaId != 0) {
1100 Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"),
1103 Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"),
1110 /* Remove all MD5 from a query (can save lot of memory with many files) */
1111 static void strip_md5(char *q)
1114 while ((p = strstr(p, ", MD5"))) {
1115 memset(p, ' ', 5 * sizeof(char));
1120 * Find the last "accurate" backup state (that can take deleted files in
1122 * 1) Get all files with jobid in list (F subquery)
1123 * Get all files in BaseFiles with jobid in list
1124 * 2) Take only the last version of each file (Temp subquery) => accurate list
1126 * 3) Join the result to file table to get fileindex, jobid and lstat information
1128 * TODO: See if we can do the SORT only if needed (as an argument)
1130 bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
1131 bool use_md5, bool use_delta,
1132 DB_RESULT_HANDLER *result_handler, void *ctx)
1136 Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
1140 POOL_MEM buf(PM_MESSAGE);
1141 POOL_MEM buf2(PM_MESSAGE);
1143 Mmsg(buf2, select_recent_version_with_basejob_and_delta[db_get_type_index(mdb)],
1144 jobids, jobids, jobids, jobids);
1147 Mmsg(buf2, select_recent_version_with_basejob[db_get_type_index(mdb)],
1148 jobids, jobids, jobids, jobids);
1151 /* bsr code is optimized for JobId sorted, with Delta, we need to get
1152 * them ordered by date. JobTDate and JobId can be mixed if using Copy
1156 "SELECT Path.Path, Filename.Name, T1.FileIndex, T1.JobId, LStat, DeltaSeq, MD5 "
1157 "FROM ( %s ) AS T1 "
1158 "JOIN Filename ON (Filename.FilenameId = T1.FilenameId) "
1159 "JOIN Path ON (Path.PathId = T1.PathId) "
1160 "WHERE FileIndex > 0 "
1161 "ORDER BY T1.JobTDate, FileIndex ASC",/* Return sorted by JobTDate */
1162 /* FileIndex for restore code */
1166 strip_md5(buf.c_str());
1169 Dmsg1(100, "q=%s\n", buf.c_str());
1171 return db_big_sql_query(mdb, buf.c_str(), result_handler, ctx);
1175 * This procedure gets the base jobid list used by jobids,
1177 bool db_get_used_base_jobids(JCR *jcr, B_DB *mdb,
1178 POOLMEM *jobids, db_list_ctx *result)
1182 "SELECT DISTINCT BaseJobId "
1183 " FROM Job JOIN BaseFiles USING (JobId) "
1184 " WHERE Job.HasBase = 1 "
1185 " AND Job.JobId IN (%s) ", jobids);
1186 return db_sql_query(mdb, buf.c_str(), db_list_handler, result);
1190 * The decision do change an incr/diff was done before
1192 * Differential : get the last full id
1193 * Incremental : get the last full + last diff + last incr(s) ids
1195 * If you specify jr->StartTime, it will be used to limit the search
1196 * in the time. (usually now)
1198 * TODO: look and merge from ua_restore.c
1200 bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
1201 JOB_DBR *jr, db_list_ctx *jobids)
1204 char clientid[50], jobid[50], filesetid[50];
1205 char date[MAX_TIME_LENGTH];
1206 POOL_MEM query(PM_FNAME);
1208 /* Take the current time as upper limit if nothing else specified */
1209 utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1211 bstrutime(date, sizeof(date), StartTime + 1);
1214 /* First, find the last good Full backup for this job/client/fileset */
1215 Mmsg(query, create_temp_accurate_jobids[db_get_type_index(mdb)],
1216 edit_uint64(jcr->JobId, jobid),
1217 edit_uint64(jr->ClientId, clientid),
1219 edit_uint64(jr->FileSetId, filesetid));
1221 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1225 if (jr->JobLevel == L_INCREMENTAL || jr->JobLevel == L_VIRTUAL_FULL) {
1226 /* Now, find the last differential backup after the last full */
1228 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1229 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1230 "FROM Job JOIN FileSet USING (FileSetId) "
1231 "WHERE ClientId = %s "
1232 "AND Level='D' AND JobStatus IN ('T','W') AND Type='B' "
1233 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1234 "AND StartTime < '%s' "
1235 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1236 "ORDER BY Job.JobTDate DESC LIMIT 1 ",
1243 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1247 /* We just have to take all incremental after the last Full/Diff */
1249 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1250 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1251 "FROM Job JOIN FileSet USING (FileSetId) "
1252 "WHERE ClientId = %s "
1253 "AND Level='I' AND JobStatus IN ('T','W') AND Type='B' "
1254 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1255 "AND StartTime < '%s' "
1256 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1257 "ORDER BY Job.JobTDate DESC ",
1263 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1268 /* build a jobid list ie: 1,2,3,4 */
1269 Mmsg(query, "SELECT JobId FROM btemp3%s ORDER by JobTDate", jobid);
1270 db_sql_query(mdb, query.c_str(), db_list_handler, jobids);
1271 Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids->list);
1275 Mmsg(query, "DROP TABLE btemp3%s", jobid);
1276 db_sql_query(mdb, query.c_str(), NULL, NULL);
1281 bool db_get_base_file_list(JCR *jcr, B_DB *mdb, bool use_md5,
1282 DB_RESULT_HANDLER *result_handler, void *ctx)
1284 POOL_MEM buf(PM_MESSAGE);
1287 "SELECT Path, Name, FileIndex, JobId, LStat, 0 As DeltaSeq, MD5 "
1288 "FROM new_basefile%lld ORDER BY JobId, FileIndex ASC",
1289 (uint64_t) jcr->JobId);
1292 strip_md5(buf.c_str());
1294 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1297 bool db_get_base_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr, JobId_t *jobid)
1299 POOL_MEM query(PM_FNAME);
1302 char date[MAX_TIME_LENGTH];
1303 char esc[MAX_ESCAPE_NAME_LENGTH];
1305 // char clientid[50], filesetid[50];
1310 StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1311 bstrutime(date, sizeof(date), StartTime + 1);
1312 mdb->db_escape_string(jcr, esc, jr->Name, strlen(jr->Name));
1314 /* we can take also client name, fileset, etc... */
1317 "SELECT JobId, Job, StartTime, EndTime, JobTDate, PurgedFiles "
1319 // "JOIN FileSet USING (FileSetId) JOIN Client USING (ClientId) "
1320 "WHERE Job.Name = '%s' "
1321 "AND Level='B' AND JobStatus IN ('T','W') AND Type='B' "
1322 // "AND FileSet.FileSet= '%s' "
1323 // "AND Client.Name = '%s' "
1324 "AND StartTime<'%s' "
1325 "ORDER BY Job.JobTDate DESC LIMIT 1",
1327 // edit_uint64(jr->ClientId, clientid),
1328 // edit_uint64(jr->FileSetId, filesetid));
1331 Dmsg1(10, "db_get_base_jobid q=%s\n", query.c_str());
1332 if (!db_sql_query(mdb, query.c_str(), db_int64_handler, &lctx)) {
1335 *jobid = (JobId_t) lctx.value;
1337 Dmsg1(10, "db_get_base_jobid=%lld\n", *jobid);
1344 /* Get JobIds associated with a volume */
1345 bool db_get_volume_jobids(JCR *jcr, B_DB *mdb,
1346 MEDIA_DBR *mr, db_list_ctx *lst)
1352 Mmsg(mdb->cmd, "SELECT DISTINCT JobId FROM JobMedia WHERE MediaId=%s",
1353 edit_int64(mr->MediaId, ed1));
1354 ret = db_sql_query(mdb, mdb->cmd, db_list_handler, lst);
1359 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */