2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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 two of the GNU 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 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
39 /* The following is necessary so that we do not include
40 * the dummy external definition of DB.
42 #define __SQL_C /* indicate that this is sql.c */
47 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
49 /* -----------------------------------------------------------------------
51 * Generic Routines (or almost generic)
53 * -----------------------------------------------------------------------
56 /* Forward referenced functions */
57 static int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr);
58 static int db_get_filename_record(JCR *jcr, B_DB *mdb);
62 * Given a full filename (with path), look up the File record
63 * (with attributes) in the database.
65 * Returns: 0 on failure
66 * 1 on success with the File record in FILE_DBR
68 int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
71 Dmsg1(100, "db_get_file_att_record fname=%s \n", fname);
74 split_path_and_file(jcr, mdb, fname);
76 fdbr->FilenameId = db_get_filename_record(jcr, mdb);
78 fdbr->PathId = db_get_path_record(jcr, mdb);
80 stat = db_get_file_record(jcr, mdb, jr, fdbr);
90 * Returns: 0 on failure
93 * DO NOT use Jmsg in this routine.
95 * Note in this routine, we do not use Jmsg because it may be
96 * called to get attributes of a non-existent file, which is
97 * "normal" if a new file is found during Verify.
99 * The following is a bit of a kludge: because we always backup a
100 * directory entry, we can end up with two copies of the directory
101 * in the backup. One is when we encounter the directory and find
102 * we cannot recurse into it, and the other is when we find an
103 * explicit mention of the directory. This can also happen if the
104 * use includes the directory twice. In this case, Verify
105 * VolumeToCatalog fails because we have two copies in the catalog,
106 * and only the first one is marked (twice). So, when calling from Verify,
107 * jr is not NULL and we know jr->FileIndex is the fileindex
108 * of the version of the directory/file we actually want and do
109 * a more explicit SQL search.
112 int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
116 char ed1[50], ed2[50], ed3[50];
118 if (jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG) {
120 "SELECT FileId, LStat, MD5 FROM File,Job WHERE "
121 "File.JobId=Job.JobId AND File.PathId=%s AND "
122 "File.FilenameId=%s AND Job.Type='B' AND Job.JobStatus IN ('T','W') AND "
123 "ClientId=%s ORDER BY StartTime DESC LIMIT 1",
124 edit_int64(fdbr->PathId, ed1),
125 edit_int64(fdbr->FilenameId, ed2),
126 edit_int64(jr->ClientId,ed3));
128 } else if (jr != NULL) {
129 /* Called from Verify so jr->FileIndex is valid */
131 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
132 "File.FilenameId=%s AND FileIndex=%u",
133 edit_int64(fdbr->JobId, ed1),
134 edit_int64(fdbr->PathId, ed2),
135 edit_int64(fdbr->FilenameId,ed3),
139 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
140 "File.FilenameId=%s",
141 edit_int64(fdbr->JobId, ed1),
142 edit_int64(fdbr->PathId, ed2),
143 edit_int64(fdbr->FilenameId,ed3));
145 Dmsg3(450, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
146 fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
148 Dmsg1(100, "Query=%s\n", mdb->cmd);
150 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
151 mdb->num_rows = sql_num_rows(mdb);
152 Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows);
153 if (mdb->num_rows >= 1) {
154 if ((row = sql_fetch_row(mdb)) == NULL) {
155 Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
157 fdbr->FileId = (FileId_t)str_to_int64(row[0]);
158 bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
159 bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
161 if (mdb->num_rows > 1) {
162 Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
164 edit_int64(fdbr->PathId, ed1),
165 edit_int64(fdbr->FilenameId, ed2));
166 Dmsg1(000, "=== Problem! %s", mdb->errmsg);
170 Mmsg2(mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"),
171 edit_int64(fdbr->PathId, ed1),
172 edit_int64(fdbr->FilenameId, ed2));
174 sql_free_result(mdb);
176 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);
227 * Returns: 0 on failure
230 * DO NOT use Jmsg in this routine (see notes for get_file_record)
232 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 mdb->num_rows = sql_num_rows(mdb);
250 if (mdb->num_rows > 1) {
251 Mmsg2(mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
252 edit_uint64(mdb->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 */
256 if (mdb->num_rows >= 1) {
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)
296 if (jr->JobId == 0) {
297 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
298 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
299 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
300 "SchedTime,RealEndTime,ReadBytes,HasBase "
301 "FROM Job WHERE Job='%s'", jr->Job);
303 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
304 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
305 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
306 "SchedTime,RealEndTime,ReadBytes,HasBase "
307 "FROM Job WHERE JobId=%s",
308 edit_int64(jr->JobId, ed1));
311 if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
313 return false; /* failed */
315 if ((row = sql_fetch_row(mdb)) == NULL) {
316 Mmsg1(mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1));
317 sql_free_result(mdb);
319 return false; /* failed */
322 jr->VolSessionId = str_to_uint64(row[0]);
323 jr->VolSessionTime = str_to_uint64(row[1]);
324 jr->PoolId = str_to_int64(row[2]);
325 bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime));
326 bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime));
327 jr->JobFiles = str_to_int64(row[5]);
328 jr->JobBytes = str_to_int64(row[6]);
329 jr->JobTDate = str_to_int64(row[7]);
330 bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job));
331 jr->JobStatus = row[9]!=NULL?(int)*row[9]:JS_FatalError;
332 jr->JobType = row[10]!=NULL?(int)*row[10]:JT_BACKUP;
333 jr->JobLevel = row[11]!=NULL?(int)*row[11]:L_NONE;
334 jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)"");
335 bstrncpy(jr->Name, row[13]!=NULL?row[13]:"", sizeof(jr->Name));
336 jr->PriorJobId = str_to_uint64(row[14]!=NULL?row[14]:(char *)"");
337 bstrncpy(jr->cRealEndTime, row[15]!=NULL?row[15]:"", sizeof(jr->cRealEndTime));
338 if (jr->JobId == 0) {
339 jr->JobId = str_to_int64(row[16]);
341 jr->FileSetId = str_to_int64(row[17]);
342 bstrncpy(jr->cSchedTime, row[3]!=NULL?row[18]:"", sizeof(jr->cSchedTime));
343 bstrncpy(jr->cRealEndTime, row[3]!=NULL?row[19]:"", sizeof(jr->cRealEndTime));
344 jr->ReadBytes = str_to_int64(row[20]);
345 jr->StartTime = str_to_utime(jr->cStartTime);
346 jr->SchedTime = str_to_utime(jr->cSchedTime);
347 jr->EndTime = str_to_utime(jr->cEndTime);
348 jr->RealEndTime = str_to_utime(jr->cRealEndTime);
349 jr->HasBase = str_to_int64(row[21]);
350 sql_free_result(mdb);
357 * Find VolumeNames for a given JobId
358 * Returns: 0 on error or no Volumes found
359 * number of volumes on success
360 * Volumes are concatenated in VolumeNames
361 * separated by a vertical bar (|) in the order
362 * that they were written.
364 * Returns: number of volumes on success
366 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **VolumeNames)
374 /* Get one entry per VolumeName, but "sort" by VolIndex */
376 "SELECT VolumeName,MAX(VolIndex) FROM JobMedia,Media WHERE "
377 "JobMedia.JobId=%s AND JobMedia.MediaId=Media.MediaId "
378 "GROUP BY VolumeName "
379 "ORDER BY 2 ASC", edit_int64(JobId,ed1));
381 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
383 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
384 mdb->num_rows = sql_num_rows(mdb);
385 Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
386 if (mdb->num_rows <= 0) {
387 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
390 stat = mdb->num_rows;
391 for (i=0; i < stat; i++) {
392 if ((row = sql_fetch_row(mdb)) == NULL) {
393 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
394 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
398 if (*VolumeNames[0] != 0) {
399 pm_strcat(VolumeNames, "|");
401 pm_strcat(VolumeNames, row[0]);
405 sql_free_result(mdb);
407 Mmsg(mdb->errmsg, _("No Volume for JobId %d found in Catalog.\n"), JobId);
414 * Find Volume parameters for a give JobId
415 * Returns: 0 on error or no Volumes found
416 * number of volumes on success
417 * List of Volumes and start/end file/blocks (malloced structure!)
419 * Returns: number of volumes on success
421 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS **VolParams)
427 VOL_PARAMS *Vols = NULL;
431 "SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile,"
432 "JobMedia.EndFile,StartBlock,JobMedia.EndBlock,"
433 "Slot,StorageId,InChanger"
434 " FROM JobMedia,Media WHERE JobMedia.JobId=%s"
435 " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId",
436 edit_int64(JobId, ed1));
438 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
439 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
440 mdb->num_rows = sql_num_rows(mdb);
441 Dmsg1(200, "Num rows=%d\n", mdb->num_rows);
442 if (mdb->num_rows <= 0) {
443 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
446 stat = mdb->num_rows;
449 *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
450 SId = (DBId_t *)malloc(stat * sizeof(DBId_t));
452 for (i=0; i < stat; i++) {
453 if ((row = sql_fetch_row(mdb)) == NULL) {
454 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
455 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
460 uint32_t StartBlock, EndBlock, StartFile, EndFile;
461 bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH);
462 bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH);
463 Vols[i].FirstIndex = str_to_uint64(row[2]);
464 Vols[i].LastIndex = str_to_uint64(row[3]);
465 StartFile = str_to_uint64(row[4]);
466 EndFile = str_to_uint64(row[5]);
467 StartBlock = str_to_uint64(row[6]);
468 EndBlock = str_to_uint64(row[7]);
469 Vols[i].StartAddr = (((uint64_t)StartFile)<<32) | StartBlock;
470 Vols[i].EndAddr = (((uint64_t)EndFile)<<32) | EndBlock;
471 Vols[i].Slot = str_to_uint64(row[8]);
472 StorageId = str_to_uint64(row[9]);
473 Vols[i].InChanger = str_to_uint64(row[10]);
474 Vols[i].Storage[0] = 0;
478 for (i=0; i < stat; i++) {
480 Mmsg(mdb->cmd, "SELECT Name from Storage WHERE StorageId=%s",
481 edit_int64(SId[i], ed1));
482 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
483 if ((row = sql_fetch_row(mdb)) && row[0]) {
484 bstrncpy(Vols[i].Storage, row[0], MAX_NAME_LENGTH);
493 sql_free_result(mdb);
502 * Get the number of pool records
504 * Returns: -1 on failure
507 int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
512 Mmsg(mdb->cmd, "SELECT count(*) from Pool");
513 stat = get_sql_record_max(jcr, mdb);
519 * This function returns a list of all the Pool record ids.
520 * The caller must free ids if non-NULL.
522 * Returns 0: on failure
525 int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
534 Mmsg(mdb->cmd, "SELECT PoolId FROM Pool");
535 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
536 *num_ids = sql_num_rows(mdb);
538 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
539 while ((row = sql_fetch_row(mdb)) != NULL) {
540 id[i++] = str_to_uint64(row[0]);
544 sql_free_result(mdb);
547 Mmsg(mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
548 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
556 * This function returns a list of all the Client record ids.
557 * The caller must free ids if non-NULL.
559 * Returns 0: on failure
562 int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
571 Mmsg(mdb->cmd, "SELECT ClientId FROM Client ORDER BY Name");
572 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
573 *num_ids = sql_num_rows(mdb);
575 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
576 while ((row = sql_fetch_row(mdb)) != NULL) {
577 id[i++] = str_to_uint64(row[0]);
581 sql_free_result(mdb);
584 Mmsg(mdb->errmsg, _("Client id select failed: ERR=%s\n"), sql_strerror(mdb));
585 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
595 * If the PoolId is non-zero, we get its record,
596 * otherwise, we search on the PoolName
598 * Returns: false on failure
601 bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
608 if (pdbr->PoolId != 0) { /* find by id */
610 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
611 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
612 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
613 "ActionOnPurge FROM Pool WHERE Pool.PoolId=%s",
614 edit_int64(pdbr->PoolId, ed1));
615 } else { /* find by name */
617 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
618 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
619 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
620 "ActionOnPurge FROM Pool WHERE Pool.Name='%s'",
623 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
624 mdb->num_rows = sql_num_rows(mdb);
625 if (mdb->num_rows > 1) {
627 Mmsg1(mdb->errmsg, _("More than one Pool!: %s\n"),
628 edit_uint64(mdb->num_rows, ed1));
629 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
630 } else if (mdb->num_rows == 1) {
631 if ((row = sql_fetch_row(mdb)) == NULL) {
632 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
633 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
635 pdbr->PoolId = str_to_int64(row[0]);
636 bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name));
637 pdbr->NumVols = str_to_int64(row[2]);
638 pdbr->MaxVols = str_to_int64(row[3]);
639 pdbr->UseOnce = str_to_int64(row[4]);
640 pdbr->UseCatalog = str_to_int64(row[5]);
641 pdbr->AcceptAnyVolume = str_to_int64(row[6]);
642 pdbr->AutoPrune = str_to_int64(row[7]);
643 pdbr->Recycle = str_to_int64(row[8]);
644 pdbr->VolRetention = str_to_int64(row[9]);
645 pdbr->VolUseDuration = str_to_int64(row[10]);
646 pdbr->MaxVolJobs = str_to_int64(row[11]);
647 pdbr->MaxVolFiles = str_to_int64(row[12]);
648 pdbr->MaxVolBytes = str_to_uint64(row[13]);
649 bstrncpy(pdbr->PoolType, row[14]!=NULL?row[14]:"", sizeof(pdbr->PoolType));
650 pdbr->LabelType = str_to_int64(row[15]);
651 bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat));
652 pdbr->RecyclePoolId = str_to_int64(row[17]);
653 pdbr->ScratchPoolId = str_to_int64(row[18]);
654 pdbr->ActionOnPurge = str_to_int32(row[19]);
658 sql_free_result(mdb);
662 Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
663 edit_int64(pdbr->PoolId, ed1));
664 NumVols = get_sql_record_max(jcr, mdb);
665 Dmsg2(400, "Actual NumVols=%d Pool NumVols=%d\n", NumVols, pdbr->NumVols);
666 if (NumVols != pdbr->NumVols) {
667 pdbr->NumVols = NumVols;
668 db_update_pool_record(jcr, mdb, pdbr);
671 Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n"));
678 * If the ClientId is non-zero, we get its record,
679 * otherwise, we search on the Client Name
681 * Returns: 0 on failure
684 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
691 if (cdbr->ClientId != 0) { /* find by id */
693 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
694 "FROM Client WHERE Client.ClientId=%s",
695 edit_int64(cdbr->ClientId, ed1));
696 } else { /* find by name */
698 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
699 "FROM Client WHERE Client.Name='%s'", cdbr->Name);
702 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
703 mdb->num_rows = sql_num_rows(mdb);
704 if (mdb->num_rows > 1) {
705 Mmsg1(mdb->errmsg, _("More than one Client!: %s\n"),
706 edit_uint64(mdb->num_rows, ed1));
707 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
708 } else if (mdb->num_rows == 1) {
709 if ((row = sql_fetch_row(mdb)) == NULL) {
710 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
711 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
713 cdbr->ClientId = str_to_int64(row[0]);
714 bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name));
715 bstrncpy(cdbr->Uname, row[2]!=NULL?row[2]:"", sizeof(cdbr->Uname));
716 cdbr->AutoPrune = str_to_int64(row[3]);
717 cdbr->FileRetention = str_to_int64(row[4]);
718 cdbr->JobRetention = str_to_int64(row[5]);
722 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
724 sql_free_result(mdb);
726 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
735 * Returns: 0 on failure
738 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
743 Mmsg(mdb->cmd, "SELECT MinValue,MaxValue,CurrentValue,WrapCounter "
744 "FROM Counters WHERE Counter='%s'", cr->Counter);
746 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
747 mdb->num_rows = sql_num_rows(mdb);
749 /* If more than one, report error, but return first row */
750 if (mdb->num_rows > 1) {
751 Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), (int)(mdb->num_rows));
752 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
754 if (mdb->num_rows >= 1) {
755 if ((row = sql_fetch_row(mdb)) == NULL) {
756 Mmsg1(mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb));
757 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
758 sql_free_result(mdb);
762 cr->MinValue = str_to_int64(row[0]);
763 cr->MaxValue = str_to_int64(row[1]);
764 cr->CurrentValue = str_to_int64(row[2]);
766 bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter));
768 cr->WrapCounter[0] = 0;
770 sql_free_result(mdb);
774 sql_free_result(mdb);
776 Mmsg(mdb->errmsg, _("Counter record: %s not found in Catalog.\n"), cr->Counter);
783 /* Get FileSet Record
784 * If the FileSetId is non-zero, we get its record,
785 * otherwise, we search on the name
787 * Returns: 0 on failure
790 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
797 if (fsr->FileSetId != 0) { /* find by id */
799 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
800 "WHERE FileSetId=%s",
801 edit_int64(fsr->FileSetId, ed1));
802 } else { /* find by name */
804 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
805 "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", fsr->FileSet);
808 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
809 mdb->num_rows = sql_num_rows(mdb);
810 if (mdb->num_rows > 1) {
812 Mmsg1(mdb->errmsg, _("Error got %s FileSets but expected only one!\n"),
813 edit_uint64(mdb->num_rows, ed1));
814 sql_data_seek(mdb, mdb->num_rows-1);
816 if ((row = sql_fetch_row(mdb)) == NULL) {
817 Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
819 fsr->FileSetId = str_to_int64(row[0]);
820 bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
821 bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
822 bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime));
823 stat = fsr->FileSetId;
825 sql_free_result(mdb);
827 Mmsg(mdb->errmsg, _("FileSet record not found in Catalog.\n"));
835 * Get the number of Media records
837 * Returns: -1 on failure
840 int db_get_num_media_records(JCR *jcr, B_DB *mdb)
845 Mmsg(mdb->cmd, "SELECT count(*) from Media");
846 stat = get_sql_record_max(jcr, mdb);
852 * This function returns a list of all the Media record ids for
853 * the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
854 * VolumeName if specified
855 * The caller must free ids if non-NULL.
857 * Returns false: on failure
860 bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, int *num_ids, uint32_t *ids[])
867 char buf[MAX_NAME_LENGTH*3]; /* Can contain MAX_NAME_LENGTH*2+1 + AND ....='' */
868 char esc[MAX_NAME_LENGTH*2+1];
873 Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE Recycle=%d AND Enabled=%d ",
874 mr->Recycle, mr->Enabled);
876 if (*mr->MediaType) {
877 db_escape_string(jcr, mdb, esc, mr->MediaType, strlen(mr->MediaType));
878 bsnprintf(buf, sizeof(buf), "AND MediaType='%s' ", esc);
879 pm_strcat(mdb->cmd, buf);
883 bsnprintf(buf, sizeof(buf), "AND StorageId=%s ", edit_uint64(mr->StorageId, ed1));
884 pm_strcat(mdb->cmd, buf);
888 bsnprintf(buf, sizeof(buf), "AND PoolId=%s ", edit_uint64(mr->PoolId, ed1));
889 pm_strcat(mdb->cmd, buf);
893 bsnprintf(buf, sizeof(buf), "AND VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
894 pm_strcat(mdb->cmd, buf);
897 if (*mr->VolumeName) {
898 db_escape_string(jcr, mdb, esc, mr->VolumeName, strlen(mr->VolumeName));
899 bsnprintf(buf, sizeof(buf), "AND VolumeName = '%s' ", esc);
900 pm_strcat(mdb->cmd, buf);
903 if (*mr->VolStatus) {
904 db_escape_string(jcr, mdb, esc, mr->VolStatus, strlen(mr->VolStatus));
905 bsnprintf(buf, sizeof(buf), "AND VolStatus = '%s' ", esc);
906 pm_strcat(mdb->cmd, buf);
909 Dmsg1(100, "q=%s\n", mdb->cmd);
911 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
912 *num_ids = sql_num_rows(mdb);
914 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
915 while ((row = sql_fetch_row(mdb)) != NULL) {
916 id[i++] = str_to_uint64(row[0]);
920 sql_free_result(mdb);
923 Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
924 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
933 * This function returns a list of all the DBIds that are returned
936 * Returns false: on failure
939 bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids)
947 if (QUERY_DB(jcr, mdb, query.c_str())) {
948 ids.num_ids = sql_num_rows(mdb);
949 if (ids.num_ids > 0) {
950 if (ids.max_ids < ids.num_ids) {
952 ids.DBId = (DBId_t *)malloc(ids.num_ids * sizeof(DBId_t));
954 while ((row = sql_fetch_row(mdb)) != NULL) {
955 ids.DBId[i++] = str_to_uint64(row[0]);
958 sql_free_result(mdb);
961 Mmsg(mdb->errmsg, _("query dbids failed: ERR=%s\n"), sql_strerror(mdb));
962 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
971 * Returns: false: on failure
974 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
981 if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
982 Mmsg(mdb->cmd, "SELECT count(*) from Media");
983 mr->MediaId = get_sql_record_max(jcr, mdb);
987 if (mr->MediaId != 0) { /* find by id */
988 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
989 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
990 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
991 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
992 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
993 "Enabled,LocationId,RecycleCount,InitialWrite,"
994 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
995 "FROM Media WHERE MediaId=%s",
996 edit_int64(mr->MediaId, ed1));
997 } else { /* find by name */
998 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
999 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
1000 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
1001 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
1002 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
1003 "Enabled,LocationId,RecycleCount,InitialWrite,"
1004 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
1005 "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
1008 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1010 mdb->num_rows = sql_num_rows(mdb);
1011 if (mdb->num_rows > 1) {
1012 Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
1013 edit_uint64(mdb->num_rows, ed1));
1014 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1015 } else if (mdb->num_rows == 1) {
1016 if ((row = sql_fetch_row(mdb)) == NULL) {
1017 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
1018 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1021 mr->MediaId = str_to_int64(row[0]);
1022 bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
1023 mr->VolJobs = str_to_int64(row[2]);
1024 mr->VolFiles = str_to_int64(row[3]);
1025 mr->VolBlocks = str_to_int64(row[4]);
1026 mr->VolBytes = str_to_uint64(row[5]);
1027 mr->VolMounts = str_to_int64(row[6]);
1028 mr->VolErrors = str_to_int64(row[7]);
1029 mr->VolWrites = str_to_int64(row[8]);
1030 mr->MaxVolBytes = str_to_uint64(row[9]);
1031 mr->VolCapacityBytes = str_to_uint64(row[10]);
1032 bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
1033 bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
1034 mr->PoolId = str_to_int64(row[13]);
1035 mr->VolRetention = str_to_uint64(row[14]);
1036 mr->VolUseDuration = str_to_uint64(row[15]);
1037 mr->MaxVolJobs = str_to_int64(row[16]);
1038 mr->MaxVolFiles = str_to_int64(row[17]);
1039 mr->Recycle = str_to_int64(row[18]);
1040 mr->Slot = str_to_int64(row[19]);
1041 bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
1042 mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
1043 bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
1044 mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
1045 mr->InChanger = str_to_uint64(row[22]);
1046 mr->EndFile = str_to_uint64(row[23]);
1047 mr->EndBlock = str_to_uint64(row[24]);
1048 mr->VolParts = str_to_int64(row[25]);
1049 mr->LabelType = str_to_int64(row[26]);
1050 bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
1051 mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
1052 mr->StorageId = str_to_int64(row[28]);
1053 mr->Enabled = str_to_int64(row[29]);
1054 mr->LocationId = str_to_int64(row[30]);
1055 mr->RecycleCount = str_to_int64(row[31]);
1056 bstrncpy(mr->cInitialWrite, row[32]!=NULL?row[32]:"", sizeof(mr->cInitialWrite));
1057 mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
1058 mr->ScratchPoolId = str_to_int64(row[33]);
1059 mr->RecyclePoolId = str_to_int64(row[34]);
1060 mr->VolReadTime = str_to_int64(row[35]);
1061 mr->VolWriteTime = str_to_int64(row[36]);
1062 mr->ActionOnPurge = str_to_int32(row[37]);
1067 if (mr->MediaId != 0) {
1068 Mmsg1(mdb->errmsg, _("Media record MediaId=%s not found.\n"),
1069 edit_int64(mr->MediaId, ed1));
1071 Mmsg1(mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"),
1075 sql_free_result(mdb);
1077 if (mr->MediaId != 0) {
1078 Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"),
1081 Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"),
1089 * Find the last "accurate" backup state (that can take deleted files in
1091 * 1) Get all files with jobid in list (F subquery)
1092 * Get all files in BaseFiles with jobid in list
1093 * 2) Take only the last version of each file (Temp subquery) => accurate list
1095 * 3) Join the result to file table to get fileindex, jobid and lstat information
1097 * TODO: See if we can do the SORT only if needed (as an argument)
1099 bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
1100 DB_RESULT_HANDLER *result_handler, void *ctx)
1104 Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
1108 POOL_MEM buf(PM_MESSAGE);
1110 #define new_db_get_file_list
1111 #ifdef new_db_get_file_list
1112 POOL_MEM buf2(PM_MESSAGE);
1113 Mmsg(buf2, select_recent_version_with_basejob[db_type],
1114 jobids, jobids, jobids, jobids);
1116 "SELECT Path.Path, Filename.Name, Temp.FileIndex, Temp.JobId, LStat, MD5 "
1117 "FROM ( %s ) AS Temp "
1118 "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
1119 "JOIN Path ON (Path.PathId = Temp.PathId) "
1120 "WHERE FileIndex > 0 "
1121 "ORDER BY Temp.JobId, FileIndex ASC",/* Return sorted by JobId, */
1122 /* FileIndex for restore code */
1126 * I am not sure that this works the same as the code in ua_restore.c but it
1127 * is very similar. The accurate-test fails in a restore. Bad file count.
1129 Mmsg(buf, uar_sel_files, jobids);
1132 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1136 * This procedure gets the base jobid list used by jobids,
1138 bool db_get_used_base_jobids(JCR *jcr, B_DB *mdb,
1139 POOLMEM *jobids, db_list_ctx *result)
1143 "SELECT DISTINCT BaseJobId "
1144 " FROM Job JOIN BaseFiles USING (JobId) "
1145 " WHERE Job.HasBase = 1 "
1146 " AND Job.JobId IN (%s) ", jobids);
1147 return db_sql_query(mdb, buf.c_str(), db_list_handler, result);
1150 /* The decision do change an incr/diff was done before
1152 * Differential : get the last full id
1153 * Incremental : get the last full + last diff + last incr(s) ids
1155 * If you specify jr->StartTime, it will be used to limit the search
1156 * in the time. (usually now)
1158 * TODO: look and merge from ua_restore.c
1160 bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
1161 JOB_DBR *jr, db_list_ctx *jobids)
1164 char clientid[50], jobid[50], filesetid[50];
1165 char date[MAX_TIME_LENGTH];
1166 POOL_MEM query(PM_FNAME);
1168 /* Take the current time as upper limit if nothing else specified */
1169 utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1171 bstrutime(date, sizeof(date), StartTime + 1);
1172 jobids->list[0] = 0;
1175 /* First, find the last good Full backup for this job/client/fileset */
1177 "CREATE TABLE btemp3%s AS "
1178 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1179 "FROM Job JOIN FileSet USING (FileSetId) "
1180 "WHERE ClientId = %s "
1181 "AND Level='F' AND JobStatus IN ('T','W') AND Type='B' "
1182 "AND StartTime<'%s' "
1183 "AND FileSet.FileSet=(SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1184 "ORDER BY Job.JobTDate DESC LIMIT 1",
1185 edit_uint64(jcr->JobId, jobid),
1186 edit_uint64(jr->ClientId, clientid),
1188 edit_uint64(jr->FileSetId, filesetid));
1190 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1194 if (jr->JobLevel == L_INCREMENTAL || jr->JobLevel == L_VIRTUAL_FULL) {
1195 /* Now, find the last differential backup after the last full */
1197 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1198 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1199 "FROM Job JOIN FileSet USING (FileSetId) "
1200 "WHERE ClientId = %s "
1201 "AND Level='D' AND JobStatus IN ('T','W') AND Type='B' "
1202 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1203 "AND StartTime < '%s' "
1204 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1205 "ORDER BY Job.JobTDate DESC LIMIT 1 ",
1212 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1216 /* We just have to take all incremental after the last Full/Diff */
1218 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1219 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1220 "FROM Job JOIN FileSet USING (FileSetId) "
1221 "WHERE ClientId = %s "
1222 "AND Level='I' AND JobStatus IN ('T','W') AND Type='B' "
1223 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1224 "AND StartTime < '%s' "
1225 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1226 "ORDER BY Job.JobTDate DESC ",
1232 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1237 /* build a jobid list ie: 1,2,3,4 */
1238 Mmsg(query, "SELECT JobId FROM btemp3%s ORDER by JobTDate", jobid);
1239 db_sql_query(mdb, query.c_str(), db_list_handler, jobids);
1240 Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids->list);
1244 Mmsg(query, "DROP TABLE btemp3%s", jobid);
1245 db_sql_query(mdb, query.c_str(), NULL, NULL);
1250 bool db_get_base_file_list(JCR *jcr, B_DB *mdb,
1251 DB_RESULT_HANDLER *result_handler, void *ctx)
1253 POOL_MEM buf(PM_MESSAGE);
1256 "SELECT Path, Name, FileIndex, JobId, LStat, MD5 "
1257 "FROM new_basefile%lld ORDER BY JobId, FileIndex ASC",
1258 (uint64_t) jcr->JobId);
1260 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1263 bool db_get_base_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr, JobId_t *jobid)
1265 POOL_MEM query(PM_FNAME);
1268 char date[MAX_TIME_LENGTH];
1272 // char clientid[50], filesetid[50];
1274 StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1275 bstrutime(date, sizeof(date), StartTime + 1);
1277 /* we can take also client name, fileset, etc... */
1280 "SELECT JobId, Job, StartTime, EndTime, JobTDate, PurgedFiles "
1282 // "JOIN FileSet USING (FileSetId) JOIN Client USING (ClientId) "
1283 "WHERE Job.Name = '%s' "
1284 "AND Level='B' AND JobStatus IN ('T','W') AND Type='B' "
1285 // "AND FileSet.FileSet= '%s' "
1286 // "AND Client.Name = '%s' "
1287 "AND StartTime<'%s' "
1288 "ORDER BY Job.JobTDate DESC LIMIT 1",
1290 // edit_uint64(jr->ClientId, clientid),
1291 // edit_uint64(jr->FileSetId, filesetid));
1294 Dmsg1(10, "db_get_base_jobid q=%s\n", query.c_str());
1295 if (!db_sql_query(mdb, query.c_str(), db_int64_handler, &lctx)) {
1298 *jobid = (JobId_t) lctx.value;
1300 Dmsg1(10, "db_get_base_jobid=%lld\n", *jobid);
1307 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */