2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 * The following is necessary so that we do not include
41 * the dummy external definition of DB.
43 #define __SQL_C /* indicate that this is sql.c */
48 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
50 /* -----------------------------------------------------------------------
52 * Generic Routines (or almost generic)
54 * -----------------------------------------------------------------------
57 /* Forward referenced functions */
58 static int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr);
59 static int db_get_filename_record(JCR *jcr, B_DB *mdb);
63 * Given a full filename (with path), look up the File record
64 * (with attributes) in the database.
66 * Returns: 0 on failure
67 * 1 on success with the File record in FILE_DBR
69 int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
72 Dmsg1(100, "db_get_file_att_record fname=%s \n", fname);
75 split_path_and_file(jcr, mdb, fname);
77 fdbr->FilenameId = db_get_filename_record(jcr, mdb);
79 fdbr->PathId = db_get_path_record(jcr, mdb);
81 stat = db_get_file_record(jcr, mdb, jr, fdbr);
91 * Returns: 0 on failure
94 * DO NOT use Jmsg in this routine.
96 * Note in this routine, we do not use Jmsg because it may be
97 * called to get attributes of a non-existent file, which is
98 * "normal" if a new file is found during Verify.
100 * The following is a bit of a kludge: because we always backup a
101 * directory entry, we can end up with two copies of the directory
102 * in the backup. One is when we encounter the directory and find
103 * we cannot recurse into it, and the other is when we find an
104 * explicit mention of the directory. This can also happen if the
105 * use includes the directory twice. In this case, Verify
106 * VolumeToCatalog fails because we have two copies in the catalog,
107 * and only the first one is marked (twice). So, when calling from Verify,
108 * VolumeToCatalog jr is not NULL and we know jr->FileIndex is the fileindex
109 * of the version of the directory/file we actually want and do
110 * a more explicit SQL search.
113 int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
117 char ed1[50], ed2[50], ed3[50];
119 if (jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG) {
121 "SELECT FileId, LStat, MD5 FROM File,Job WHERE "
122 "File.JobId=Job.JobId AND File.PathId=%s AND "
123 "File.FilenameId=%s AND Job.Type='B' AND Job.JobStatus IN ('T','W') AND "
124 "ClientId=%s ORDER BY StartTime DESC LIMIT 1",
125 edit_int64(fdbr->PathId, ed1),
126 edit_int64(fdbr->FilenameId, ed2),
127 edit_int64(jr->ClientId,ed3));
128 } else if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG) {
130 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
131 "File.FilenameId=%s AND File.FileIndex=%u",
132 edit_int64(fdbr->JobId, ed1),
133 edit_int64(fdbr->PathId, ed2),
134 edit_int64(fdbr->FilenameId,ed3),
138 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
139 "File.FilenameId=%s",
140 edit_int64(fdbr->JobId, ed1),
141 edit_int64(fdbr->PathId, ed2),
142 edit_int64(fdbr->FilenameId,ed3));
144 Dmsg3(450, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
145 fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
147 Dmsg1(100, "Query=%s\n", mdb->cmd);
149 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
150 mdb->num_rows = sql_num_rows(mdb);
151 Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows);
152 if (mdb->num_rows >= 1) {
153 if ((row = sql_fetch_row(mdb)) == NULL) {
154 Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
156 fdbr->FileId = (FileId_t)str_to_int64(row[0]);
157 bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
158 bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
160 if (mdb->num_rows > 1) {
161 Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
163 edit_int64(fdbr->PathId, ed1),
164 edit_int64(fdbr->FilenameId, ed2));
165 Dmsg1(000, "=== Problem! %s", mdb->errmsg);
169 Mmsg2(mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"),
170 edit_int64(fdbr->PathId, ed1),
171 edit_int64(fdbr->FilenameId, ed2));
173 sql_free_result(mdb);
175 Mmsg(mdb->errmsg, _("File record not found in Catalog.\n"));
182 * Get Filename record
183 * Returns: 0 on failure
184 * FilenameId on success
186 * DO NOT use Jmsg in this routine (see notes for get_file_record)
188 static int db_get_filename_record(JCR *jcr, B_DB *mdb)
193 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
194 db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
196 Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
197 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
199 mdb->num_rows = sql_num_rows(mdb);
200 if (mdb->num_rows > 1) {
201 Mmsg2(mdb->errmsg, _("More than one Filename!: %s for file: %s\n"),
202 edit_uint64(mdb->num_rows, ed1), mdb->fname);
203 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
205 if (mdb->num_rows >= 1) {
206 if ((row = sql_fetch_row(mdb)) == NULL) {
207 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
209 FilenameId = str_to_int64(row[0]);
210 if (FilenameId <= 0) {
211 Mmsg2(mdb->errmsg, _("Get DB Filename record %s found bad record: %d\n"),
212 mdb->cmd, FilenameId);
217 Mmsg1(mdb->errmsg, _("Filename record: %s not found.\n"), mdb->fname);
219 sql_free_result(mdb);
221 Mmsg(mdb->errmsg, _("Filename record: %s not found in Catalog.\n"), mdb->fname);
228 * Returns: 0 on failure
231 * DO NOT use Jmsg in this routine (see notes for get_file_record)
233 int db_get_path_record(JCR *jcr, B_DB *mdb)
238 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
239 db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
241 if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
242 strcmp(mdb->cached_path, mdb->path) == 0) {
243 return mdb->cached_path_id;
246 Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
248 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
250 mdb->num_rows = sql_num_rows(mdb);
251 if (mdb->num_rows > 1) {
252 Mmsg2(mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
253 edit_uint64(mdb->num_rows, ed1), mdb->path);
254 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
256 /* Even if there are multiple paths, take the first one */
257 if (mdb->num_rows >= 1) {
258 if ((row = sql_fetch_row(mdb)) == NULL) {
259 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
261 PathId = str_to_int64(row[0]);
263 Mmsg2(mdb->errmsg, _("Get DB path record %s found bad record: %s\n"),
264 mdb->cmd, edit_int64(PathId, ed1));
268 if (PathId != mdb->cached_path_id) {
269 mdb->cached_path_id = PathId;
270 mdb->cached_path_len = mdb->pnl;
271 pm_strcpy(mdb->cached_path, mdb->path);
276 Mmsg1(mdb->errmsg, _("Path record: %s not found.\n"), mdb->path);
278 sql_free_result(mdb);
280 Mmsg(mdb->errmsg, _("Path record: %s not found in Catalog.\n"), mdb->path);
287 * Get Job record for given JobId or Job name
288 * Returns: false on failure
291 bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
297 if (jr->JobId == 0) {
298 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
299 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
300 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
301 "SchedTime,RealEndTime,ReadBytes,HasBase,PurgedFiles "
302 "FROM Job WHERE Job='%s'", jr->Job);
304 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
305 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
306 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
307 "SchedTime,RealEndTime,ReadBytes,HasBase,PurgedFiles "
308 "FROM Job WHERE JobId=%s",
309 edit_int64(jr->JobId, ed1));
312 if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
314 return false; /* failed */
316 if ((row = sql_fetch_row(mdb)) == NULL) {
317 Mmsg1(mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1));
318 sql_free_result(mdb);
320 return false; /* failed */
323 jr->VolSessionId = str_to_uint64(row[0]);
324 jr->VolSessionTime = str_to_uint64(row[1]);
325 jr->PoolId = str_to_int64(row[2]);
326 bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime));
327 bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime));
328 jr->JobFiles = str_to_int64(row[5]);
329 jr->JobBytes = str_to_int64(row[6]);
330 jr->JobTDate = str_to_int64(row[7]);
331 bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job));
332 jr->JobStatus = row[9]!=NULL?(int)*row[9]:JS_FatalError;
333 jr->JobType = row[10]!=NULL?(int)*row[10]:JT_BACKUP;
334 jr->JobLevel = row[11]!=NULL?(int)*row[11]:L_NONE;
335 jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)"");
336 bstrncpy(jr->Name, row[13]!=NULL?row[13]:"", sizeof(jr->Name));
337 jr->PriorJobId = str_to_uint64(row[14]!=NULL?row[14]:(char *)"");
338 bstrncpy(jr->cRealEndTime, row[15]!=NULL?row[15]:"", sizeof(jr->cRealEndTime));
339 if (jr->JobId == 0) {
340 jr->JobId = str_to_int64(row[16]);
342 jr->FileSetId = str_to_int64(row[17]);
343 bstrncpy(jr->cSchedTime, row[3]!=NULL?row[18]:"", sizeof(jr->cSchedTime));
344 bstrncpy(jr->cRealEndTime, row[3]!=NULL?row[19]:"", sizeof(jr->cRealEndTime));
345 jr->ReadBytes = str_to_int64(row[20]);
346 jr->StartTime = str_to_utime(jr->cStartTime);
347 jr->SchedTime = str_to_utime(jr->cSchedTime);
348 jr->EndTime = str_to_utime(jr->cEndTime);
349 jr->RealEndTime = str_to_utime(jr->cRealEndTime);
350 jr->HasBase = str_to_int64(row[21]);
351 jr->PurgedFiles = str_to_int64(row[22]);
352 sql_free_result(mdb);
359 * Find VolumeNames for a given JobId
360 * Returns: 0 on error or no Volumes found
361 * number of volumes on success
362 * Volumes are concatenated in VolumeNames
363 * separated by a vertical bar (|) in the order
364 * that they were written.
366 * Returns: number of volumes on success
368 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **VolumeNames)
376 /* Get one entry per VolumeName, but "sort" by VolIndex */
378 "SELECT VolumeName,MAX(VolIndex) FROM JobMedia,Media WHERE "
379 "JobMedia.JobId=%s AND JobMedia.MediaId=Media.MediaId "
380 "GROUP BY VolumeName "
381 "ORDER BY 2 ASC", edit_int64(JobId,ed1));
383 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
385 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
386 mdb->num_rows = sql_num_rows(mdb);
387 Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
388 if (mdb->num_rows <= 0) {
389 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
392 stat = mdb->num_rows;
393 for (i=0; i < stat; i++) {
394 if ((row = sql_fetch_row(mdb)) == NULL) {
395 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
396 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
400 if (*VolumeNames[0] != 0) {
401 pm_strcat(VolumeNames, "|");
403 pm_strcat(VolumeNames, row[0]);
407 sql_free_result(mdb);
409 Mmsg(mdb->errmsg, _("No Volume for JobId %d found in Catalog.\n"), JobId);
416 * Find Volume parameters for a give JobId
417 * Returns: 0 on error or no Volumes found
418 * number of volumes on success
419 * List of Volumes and start/end file/blocks (malloced structure!)
421 * Returns: number of volumes on success
423 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS **VolParams)
429 VOL_PARAMS *Vols = NULL;
433 "SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile,"
434 "JobMedia.EndFile,StartBlock,JobMedia.EndBlock,"
435 "Slot,StorageId,InChanger"
436 " FROM JobMedia,Media WHERE JobMedia.JobId=%s"
437 " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId",
438 edit_int64(JobId, ed1));
440 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
441 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
442 mdb->num_rows = sql_num_rows(mdb);
443 Dmsg1(200, "Num rows=%d\n", mdb->num_rows);
444 if (mdb->num_rows <= 0) {
445 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
448 stat = mdb->num_rows;
451 *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
452 SId = (DBId_t *)malloc(stat * sizeof(DBId_t));
454 for (i=0; i < stat; i++) {
455 if ((row = sql_fetch_row(mdb)) == NULL) {
456 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
457 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
462 uint32_t StartBlock, EndBlock, StartFile, EndFile;
463 bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH);
464 bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH);
465 Vols[i].FirstIndex = str_to_uint64(row[2]);
466 Vols[i].LastIndex = str_to_uint64(row[3]);
467 StartFile = str_to_uint64(row[4]);
468 EndFile = str_to_uint64(row[5]);
469 StartBlock = str_to_uint64(row[6]);
470 EndBlock = str_to_uint64(row[7]);
471 Vols[i].StartAddr = (((uint64_t)StartFile)<<32) | StartBlock;
472 Vols[i].EndAddr = (((uint64_t)EndFile)<<32) | EndBlock;
473 Vols[i].Slot = str_to_uint64(row[8]);
474 StorageId = str_to_uint64(row[9]);
475 Vols[i].InChanger = str_to_uint64(row[10]);
476 Vols[i].Storage[0] = 0;
480 for (i=0; i < stat; i++) {
482 Mmsg(mdb->cmd, "SELECT Name from Storage WHERE StorageId=%s",
483 edit_int64(SId[i], ed1));
484 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
485 if ((row = sql_fetch_row(mdb)) && row[0]) {
486 bstrncpy(Vols[i].Storage, row[0], MAX_NAME_LENGTH);
495 sql_free_result(mdb);
504 * Get the number of pool records
506 * Returns: -1 on failure
509 int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
514 Mmsg(mdb->cmd, "SELECT count(*) from Pool");
515 stat = get_sql_record_max(jcr, mdb);
521 * This function returns a list of all the Pool record ids.
522 * The caller must free ids if non-NULL.
524 * Returns 0: on failure
527 int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
536 Mmsg(mdb->cmd, "SELECT PoolId FROM Pool");
537 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
538 *num_ids = sql_num_rows(mdb);
540 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
541 while ((row = sql_fetch_row(mdb)) != NULL) {
542 id[i++] = str_to_uint64(row[0]);
546 sql_free_result(mdb);
549 Mmsg(mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
550 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
558 * This function returns a list of all the Client record ids.
559 * The caller must free ids if non-NULL.
561 * Returns 0: on failure
564 int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
573 Mmsg(mdb->cmd, "SELECT ClientId FROM Client ORDER BY Name");
574 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
575 *num_ids = sql_num_rows(mdb);
577 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
578 while ((row = sql_fetch_row(mdb)) != NULL) {
579 id[i++] = str_to_uint64(row[0]);
583 sql_free_result(mdb);
586 Mmsg(mdb->errmsg, _("Client id select failed: ERR=%s\n"), sql_strerror(mdb));
587 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
598 * If the PoolId is non-zero, we get its record,
599 * otherwise, we search on the PoolName
601 * Returns: false on failure
604 bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
611 if (pdbr->PoolId != 0) { /* find by id */
613 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
614 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
615 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
616 "ActionOnPurge FROM Pool WHERE Pool.PoolId=%s",
617 edit_int64(pdbr->PoolId, ed1));
618 } else { /* find by name */
620 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
621 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
622 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
623 "ActionOnPurge FROM Pool WHERE Pool.Name='%s'",
626 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
627 mdb->num_rows = sql_num_rows(mdb);
628 if (mdb->num_rows > 1) {
630 Mmsg1(mdb->errmsg, _("More than one Pool!: %s\n"),
631 edit_uint64(mdb->num_rows, ed1));
632 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
633 } else if (mdb->num_rows == 1) {
634 if ((row = sql_fetch_row(mdb)) == NULL) {
635 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
636 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
638 pdbr->PoolId = str_to_int64(row[0]);
639 bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name));
640 pdbr->NumVols = str_to_int64(row[2]);
641 pdbr->MaxVols = str_to_int64(row[3]);
642 pdbr->UseOnce = str_to_int64(row[4]);
643 pdbr->UseCatalog = str_to_int64(row[5]);
644 pdbr->AcceptAnyVolume = str_to_int64(row[6]);
645 pdbr->AutoPrune = str_to_int64(row[7]);
646 pdbr->Recycle = str_to_int64(row[8]);
647 pdbr->VolRetention = str_to_int64(row[9]);
648 pdbr->VolUseDuration = str_to_int64(row[10]);
649 pdbr->MaxVolJobs = str_to_int64(row[11]);
650 pdbr->MaxVolFiles = str_to_int64(row[12]);
651 pdbr->MaxVolBytes = str_to_uint64(row[13]);
652 bstrncpy(pdbr->PoolType, row[14]!=NULL?row[14]:"", sizeof(pdbr->PoolType));
653 pdbr->LabelType = str_to_int64(row[15]);
654 bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat));
655 pdbr->RecyclePoolId = str_to_int64(row[17]);
656 pdbr->ScratchPoolId = str_to_int64(row[18]);
657 pdbr->ActionOnPurge = str_to_int32(row[19]);
661 sql_free_result(mdb);
665 Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
666 edit_int64(pdbr->PoolId, ed1));
667 NumVols = get_sql_record_max(jcr, mdb);
668 Dmsg2(400, "Actual NumVols=%d Pool NumVols=%d\n", NumVols, pdbr->NumVols);
669 if (NumVols != pdbr->NumVols) {
670 pdbr->NumVols = NumVols;
671 db_update_pool_record(jcr, mdb, pdbr);
674 Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n"));
682 * If the ClientId is non-zero, we get its record,
683 * otherwise, we search on the Client Name
685 * Returns: 0 on failure
688 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
695 if (cdbr->ClientId != 0) { /* find by id */
697 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
698 "FROM Client WHERE Client.ClientId=%s",
699 edit_int64(cdbr->ClientId, ed1));
700 } else { /* find by name */
702 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
703 "FROM Client WHERE Client.Name='%s'", cdbr->Name);
706 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
707 mdb->num_rows = sql_num_rows(mdb);
708 if (mdb->num_rows > 1) {
709 Mmsg1(mdb->errmsg, _("More than one Client!: %s\n"),
710 edit_uint64(mdb->num_rows, ed1));
711 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
712 } else if (mdb->num_rows == 1) {
713 if ((row = sql_fetch_row(mdb)) == NULL) {
714 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
715 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
717 cdbr->ClientId = str_to_int64(row[0]);
718 bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name));
719 bstrncpy(cdbr->Uname, row[2]!=NULL?row[2]:"", sizeof(cdbr->Uname));
720 cdbr->AutoPrune = str_to_int64(row[3]);
721 cdbr->FileRetention = str_to_int64(row[4]);
722 cdbr->JobRetention = str_to_int64(row[5]);
726 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
728 sql_free_result(mdb);
730 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
739 * Returns: 0 on failure
742 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
747 Mmsg(mdb->cmd, "SELECT \"MinValue\",\"MaxValue\",CurrentValue,WrapCounter "
748 "FROM Counters WHERE Counter='%s'", cr->Counter);
750 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
751 mdb->num_rows = sql_num_rows(mdb);
753 /* If more than one, report error, but return first row */
754 if (mdb->num_rows > 1) {
755 Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), (int)(mdb->num_rows));
756 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
758 if (mdb->num_rows >= 1) {
759 if ((row = sql_fetch_row(mdb)) == NULL) {
760 Mmsg1(mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb));
761 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
762 sql_free_result(mdb);
766 cr->MinValue = str_to_int64(row[0]);
767 cr->MaxValue = str_to_int64(row[1]);
768 cr->CurrentValue = str_to_int64(row[2]);
770 bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter));
772 cr->WrapCounter[0] = 0;
774 sql_free_result(mdb);
778 sql_free_result(mdb);
780 Mmsg(mdb->errmsg, _("Counter record: %s not found in Catalog.\n"), cr->Counter);
789 * If the FileSetId is non-zero, we get its record,
790 * otherwise, we search on the name
792 * Returns: 0 on failure
795 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
802 if (fsr->FileSetId != 0) { /* find by id */
804 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
805 "WHERE FileSetId=%s",
806 edit_int64(fsr->FileSetId, ed1));
807 } else { /* find by name */
809 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
810 "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", fsr->FileSet);
813 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
814 mdb->num_rows = sql_num_rows(mdb);
815 if (mdb->num_rows > 1) {
817 Mmsg1(mdb->errmsg, _("Error got %s FileSets but expected only one!\n"),
818 edit_uint64(mdb->num_rows, ed1));
819 sql_data_seek(mdb, mdb->num_rows-1);
821 if ((row = sql_fetch_row(mdb)) == NULL) {
822 Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
824 fsr->FileSetId = str_to_int64(row[0]);
825 bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
826 bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
827 bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime));
828 stat = fsr->FileSetId;
830 sql_free_result(mdb);
832 Mmsg(mdb->errmsg, _("FileSet record not found in Catalog.\n"));
840 * Get the number of Media records
842 * Returns: -1 on failure
845 int db_get_num_media_records(JCR *jcr, B_DB *mdb)
850 Mmsg(mdb->cmd, "SELECT count(*) from Media");
851 stat = get_sql_record_max(jcr, mdb);
857 * This function returns a list of all the Media record ids for
858 * the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
859 * VolumeName if specified
860 * The caller must free ids if non-NULL.
862 * Returns false: on failure
865 bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, int *num_ids, uint32_t *ids[])
872 char buf[MAX_NAME_LENGTH*3]; /* Can contain MAX_NAME_LENGTH*2+1 + AND ....='' */
873 char esc[MAX_NAME_LENGTH*2+1];
878 Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE Recycle=%d AND Enabled=%d ",
879 mr->Recycle, mr->Enabled);
881 if (*mr->MediaType) {
882 db_escape_string(jcr, mdb, esc, mr->MediaType, strlen(mr->MediaType));
883 bsnprintf(buf, sizeof(buf), "AND MediaType='%s' ", esc);
884 pm_strcat(mdb->cmd, buf);
888 bsnprintf(buf, sizeof(buf), "AND StorageId=%s ", edit_uint64(mr->StorageId, ed1));
889 pm_strcat(mdb->cmd, buf);
893 bsnprintf(buf, sizeof(buf), "AND PoolId=%s ", edit_uint64(mr->PoolId, ed1));
894 pm_strcat(mdb->cmd, buf);
898 bsnprintf(buf, sizeof(buf), "AND VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
899 pm_strcat(mdb->cmd, buf);
902 if (*mr->VolumeName) {
903 db_escape_string(jcr, mdb, esc, mr->VolumeName, strlen(mr->VolumeName));
904 bsnprintf(buf, sizeof(buf), "AND VolumeName = '%s' ", esc);
905 pm_strcat(mdb->cmd, buf);
908 if (*mr->VolStatus) {
909 db_escape_string(jcr, mdb, esc, mr->VolStatus, strlen(mr->VolStatus));
910 bsnprintf(buf, sizeof(buf), "AND VolStatus = '%s' ", esc);
911 pm_strcat(mdb->cmd, buf);
914 Dmsg1(100, "q=%s\n", mdb->cmd);
916 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
917 *num_ids = sql_num_rows(mdb);
919 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
920 while ((row = sql_fetch_row(mdb)) != NULL) {
921 id[i++] = str_to_uint64(row[0]);
925 sql_free_result(mdb);
928 Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
929 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
938 * This function returns a list of all the DBIds that are returned
941 * Returns false: on failure
944 bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids)
952 if (QUERY_DB(jcr, mdb, query.c_str())) {
953 ids.num_ids = sql_num_rows(mdb);
954 if (ids.num_ids > 0) {
955 if (ids.max_ids < ids.num_ids) {
957 ids.DBId = (DBId_t *)malloc(ids.num_ids * sizeof(DBId_t));
959 while ((row = sql_fetch_row(mdb)) != NULL) {
960 ids.DBId[i++] = str_to_uint64(row[0]);
963 sql_free_result(mdb);
966 Mmsg(mdb->errmsg, _("query dbids failed: ERR=%s\n"), sql_strerror(mdb));
967 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
977 * Returns: false: on failure
980 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
987 if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
988 Mmsg(mdb->cmd, "SELECT count(*) from Media");
989 mr->MediaId = get_sql_record_max(jcr, mdb);
993 if (mr->MediaId != 0) { /* find by id */
994 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
995 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
996 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
997 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
998 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
999 "Enabled,LocationId,RecycleCount,InitialWrite,"
1000 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
1001 "FROM Media WHERE MediaId=%s",
1002 edit_int64(mr->MediaId, ed1));
1003 } else { /* find by name */
1004 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
1005 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
1006 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
1007 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
1008 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
1009 "Enabled,LocationId,RecycleCount,InitialWrite,"
1010 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
1011 "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
1014 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1016 mdb->num_rows = sql_num_rows(mdb);
1017 if (mdb->num_rows > 1) {
1018 Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
1019 edit_uint64(mdb->num_rows, ed1));
1020 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1021 } else if (mdb->num_rows == 1) {
1022 if ((row = sql_fetch_row(mdb)) == NULL) {
1023 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
1024 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1027 mr->MediaId = str_to_int64(row[0]);
1028 bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
1029 mr->VolJobs = str_to_int64(row[2]);
1030 mr->VolFiles = str_to_int64(row[3]);
1031 mr->VolBlocks = str_to_int64(row[4]);
1032 mr->VolBytes = str_to_uint64(row[5]);
1033 mr->VolMounts = str_to_int64(row[6]);
1034 mr->VolErrors = str_to_int64(row[7]);
1035 mr->VolWrites = str_to_int64(row[8]);
1036 mr->MaxVolBytes = str_to_uint64(row[9]);
1037 mr->VolCapacityBytes = str_to_uint64(row[10]);
1038 bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
1039 bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
1040 mr->PoolId = str_to_int64(row[13]);
1041 mr->VolRetention = str_to_uint64(row[14]);
1042 mr->VolUseDuration = str_to_uint64(row[15]);
1043 mr->MaxVolJobs = str_to_int64(row[16]);
1044 mr->MaxVolFiles = str_to_int64(row[17]);
1045 mr->Recycle = str_to_int64(row[18]);
1046 mr->Slot = str_to_int64(row[19]);
1047 bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
1048 mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
1049 bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
1050 mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
1051 mr->InChanger = str_to_uint64(row[22]);
1052 mr->EndFile = str_to_uint64(row[23]);
1053 mr->EndBlock = str_to_uint64(row[24]);
1054 mr->VolParts = str_to_int64(row[25]);
1055 mr->LabelType = str_to_int64(row[26]);
1056 bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
1057 mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
1058 mr->StorageId = str_to_int64(row[28]);
1059 mr->Enabled = str_to_int64(row[29]);
1060 mr->LocationId = str_to_int64(row[30]);
1061 mr->RecycleCount = str_to_int64(row[31]);
1062 bstrncpy(mr->cInitialWrite, row[32]!=NULL?row[32]:"", sizeof(mr->cInitialWrite));
1063 mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
1064 mr->ScratchPoolId = str_to_int64(row[33]);
1065 mr->RecyclePoolId = str_to_int64(row[34]);
1066 mr->VolReadTime = str_to_int64(row[35]);
1067 mr->VolWriteTime = str_to_int64(row[36]);
1068 mr->ActionOnPurge = str_to_int32(row[37]);
1073 if (mr->MediaId != 0) {
1074 Mmsg1(mdb->errmsg, _("Media record MediaId=%s not found.\n"),
1075 edit_int64(mr->MediaId, ed1));
1077 Mmsg1(mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"),
1081 sql_free_result(mdb);
1083 if (mr->MediaId != 0) {
1084 Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"),
1087 Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"),
1094 /* Remove all MD5 from a query (can save lot of memory with many files) */
1095 static void strip_md5(char *q)
1098 while ((p = strstr(p, ", MD5"))) {
1099 memset(p, ' ', 5 * sizeof(char));
1104 * Find the last "accurate" backup state (that can take deleted files in
1106 * 1) Get all files with jobid in list (F subquery)
1107 * Get all files in BaseFiles with jobid in list
1108 * 2) Take only the last version of each file (Temp subquery) => accurate list
1110 * 3) Join the result to file table to get fileindex, jobid and lstat information
1112 * TODO: See if we can do the SORT only if needed (as an argument)
1114 bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
1115 bool use_md5, bool use_delta,
1116 DB_RESULT_HANDLER *result_handler, void *ctx)
1120 Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
1124 POOL_MEM buf(PM_MESSAGE);
1125 POOL_MEM buf2(PM_MESSAGE);
1127 Mmsg(buf2, select_recent_version_with_basejob_and_delta[db_type],
1128 jobids, jobids, jobids, jobids);
1131 Mmsg(buf2, select_recent_version_with_basejob[db_type],
1132 jobids, jobids, jobids, jobids);
1135 /* bsr code is optimized for JobId sorted, with Delta, we need to get
1136 * them ordered by date. JobTDate and JobId can be mixed if using Copy
1140 "SELECT Path.Path, Filename.Name, T1.FileIndex, T1.JobId, LStat, MarkId, MD5 "
1141 "FROM ( %s ) AS T1 "
1142 "JOIN Filename ON (Filename.FilenameId = T1.FilenameId) "
1143 "JOIN Path ON (Path.PathId = T1.PathId) "
1144 "WHERE FileIndex > 0 "
1145 "ORDER BY T1.JobTDate, FileIndex ASC",/* Return sorted by JobTDate */
1146 /* FileIndex for restore code */
1150 strip_md5(buf.c_str());
1153 Dmsg1(100, "q=%s\n", buf.c_str());
1155 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1159 * This procedure gets the base jobid list used by jobids,
1161 bool db_get_used_base_jobids(JCR *jcr, B_DB *mdb,
1162 POOLMEM *jobids, db_list_ctx *result)
1166 "SELECT DISTINCT BaseJobId "
1167 " FROM Job JOIN BaseFiles USING (JobId) "
1168 " WHERE Job.HasBase = 1 "
1169 " AND Job.JobId IN (%s) ", jobids);
1170 return db_sql_query(mdb, buf.c_str(), db_list_handler, result);
1174 * The decision do change an incr/diff was done before
1176 * Differential : get the last full id
1177 * Incremental : get the last full + last diff + last incr(s) ids
1179 * If you specify jr->StartTime, it will be used to limit the search
1180 * in the time. (usually now)
1182 * TODO: look and merge from ua_restore.c
1184 bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
1185 JOB_DBR *jr, db_list_ctx *jobids)
1188 char clientid[50], jobid[50], filesetid[50];
1189 char date[MAX_TIME_LENGTH];
1190 POOL_MEM query(PM_FNAME);
1192 /* Take the current time as upper limit if nothing else specified */
1193 utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1195 bstrutime(date, sizeof(date), StartTime + 1);
1198 /* First, find the last good Full backup for this job/client/fileset */
1199 Mmsg(query, create_temp_accurate_jobids[db_type],
1200 edit_uint64(jcr->JobId, jobid),
1201 edit_uint64(jr->ClientId, clientid),
1203 edit_uint64(jr->FileSetId, filesetid));
1205 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1209 if (jr->JobLevel == L_INCREMENTAL || jr->JobLevel == L_VIRTUAL_FULL) {
1210 /* Now, find the last differential backup after the last full */
1212 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1213 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1214 "FROM Job JOIN FileSet USING (FileSetId) "
1215 "WHERE ClientId = %s "
1216 "AND Level='D' AND JobStatus IN ('T','W') AND Type='B' "
1217 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1218 "AND StartTime < '%s' "
1219 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1220 "ORDER BY Job.JobTDate DESC LIMIT 1 ",
1227 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1231 /* We just have to take all incremental after the last Full/Diff */
1233 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1234 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1235 "FROM Job JOIN FileSet USING (FileSetId) "
1236 "WHERE ClientId = %s "
1237 "AND Level='I' AND JobStatus IN ('T','W') AND Type='B' "
1238 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1239 "AND StartTime < '%s' "
1240 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1241 "ORDER BY Job.JobTDate DESC ",
1247 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1252 /* build a jobid list ie: 1,2,3,4 */
1253 Mmsg(query, "SELECT JobId FROM btemp3%s ORDER by JobTDate", jobid);
1254 db_sql_query(mdb, query.c_str(), db_list_handler, jobids);
1255 Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids->list);
1259 Mmsg(query, "DROP TABLE btemp3%s", jobid);
1260 db_sql_query(mdb, query.c_str(), NULL, NULL);
1265 bool db_get_base_file_list(JCR *jcr, B_DB *mdb, bool use_md5,
1266 DB_RESULT_HANDLER *result_handler, void *ctx)
1268 POOL_MEM buf(PM_MESSAGE);
1271 "SELECT Path, Name, FileIndex, JobId, LStat, 0 As MarkId, MD5 "
1272 "FROM new_basefile%lld ORDER BY JobId, FileIndex ASC",
1273 (uint64_t) jcr->JobId);
1276 strip_md5(buf.c_str());
1278 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1281 bool db_get_base_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr, JobId_t *jobid)
1283 POOL_MEM query(PM_FNAME);
1286 char date[MAX_TIME_LENGTH];
1288 // char clientid[50], filesetid[50];
1293 StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1294 bstrutime(date, sizeof(date), StartTime + 1);
1296 /* we can take also client name, fileset, etc... */
1299 "SELECT JobId, Job, StartTime, EndTime, JobTDate, PurgedFiles "
1301 // "JOIN FileSet USING (FileSetId) JOIN Client USING (ClientId) "
1302 "WHERE Job.Name = '%s' "
1303 "AND Level='B' AND JobStatus IN ('T','W') AND Type='B' "
1304 // "AND FileSet.FileSet= '%s' "
1305 // "AND Client.Name = '%s' "
1306 "AND StartTime<'%s' "
1307 "ORDER BY Job.JobTDate DESC LIMIT 1",
1309 // edit_uint64(jr->ClientId, clientid),
1310 // edit_uint64(jr->FileSetId, filesetid));
1313 Dmsg1(10, "db_get_base_jobid q=%s\n", query.c_str());
1314 if (!db_sql_query(mdb, query.c_str(), db_int64_handler, &lctx)) {
1317 *jobid = (JobId_t) lctx.value;
1319 Dmsg1(10, "db_get_base_jobid=%lld\n", *jobid);
1326 /* Get JobIds associated with a volume */
1327 bool db_get_volume_jobids(JCR *jcr, B_DB *mdb,
1328 MEDIA_DBR *mr, db_list_ctx *lst)
1334 Mmsg(mdb->cmd, "SELECT DISTINCT JobId FROM JobMedia WHERE MediaId=%s",
1335 edit_int64(mr->MediaId, ed1));
1336 ret = db_sql_query(mdb, mdb->cmd, db_list_handler, lst);
1341 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */