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 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
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 * 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));
129 } else if (jr != NULL) {
131 * Note, if jr given jr->FileIndex must be valid
132 * This is probably no longer used.
135 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
136 "File.FilenameId=%s AND FileIndex=%u",
137 edit_int64(fdbr->JobId, ed1),
138 edit_int64(fdbr->PathId, ed2),
139 edit_int64(fdbr->FilenameId,ed3),
143 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
144 "File.FilenameId=%s",
145 edit_int64(fdbr->JobId, ed1),
146 edit_int64(fdbr->PathId, ed2),
147 edit_int64(fdbr->FilenameId,ed3));
149 Dmsg3(450, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
150 fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
152 Dmsg1(100, "Query=%s\n", mdb->cmd);
154 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
155 mdb->num_rows = sql_num_rows(mdb);
156 Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows);
157 if (mdb->num_rows >= 1) {
158 if ((row = sql_fetch_row(mdb)) == NULL) {
159 Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
161 fdbr->FileId = (FileId_t)str_to_int64(row[0]);
162 bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
163 bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
165 if (mdb->num_rows > 1) {
166 Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
168 edit_int64(fdbr->PathId, ed1),
169 edit_int64(fdbr->FilenameId, ed2));
170 Dmsg1(000, "=== Problem! %s", mdb->errmsg);
174 Mmsg2(mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"),
175 edit_int64(fdbr->PathId, ed1),
176 edit_int64(fdbr->FilenameId, ed2));
178 sql_free_result(mdb);
180 Mmsg(mdb->errmsg, _("File record not found in Catalog.\n"));
187 * Get Filename record
188 * Returns: 0 on failure
189 * FilenameId on success
191 * DO NOT use Jmsg in this routine (see notes for get_file_record)
193 static int db_get_filename_record(JCR *jcr, B_DB *mdb)
198 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
199 db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
201 Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
202 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
204 mdb->num_rows = sql_num_rows(mdb);
205 if (mdb->num_rows > 1) {
206 Mmsg2(mdb->errmsg, _("More than one Filename!: %s for file: %s\n"),
207 edit_uint64(mdb->num_rows, ed1), mdb->fname);
208 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
210 if (mdb->num_rows >= 1) {
211 if ((row = sql_fetch_row(mdb)) == NULL) {
212 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
214 FilenameId = str_to_int64(row[0]);
215 if (FilenameId <= 0) {
216 Mmsg2(mdb->errmsg, _("Get DB Filename record %s found bad record: %d\n"),
217 mdb->cmd, FilenameId);
222 Mmsg1(mdb->errmsg, _("Filename record: %s not found.\n"), mdb->fname);
224 sql_free_result(mdb);
226 Mmsg(mdb->errmsg, _("Filename record: %s not found in Catalog.\n"), mdb->fname);
233 * Returns: 0 on failure
236 * DO NOT use Jmsg in this routine (see notes for get_file_record)
238 int db_get_path_record(JCR *jcr, B_DB *mdb)
243 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
244 db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
246 if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
247 strcmp(mdb->cached_path, mdb->path) == 0) {
248 return mdb->cached_path_id;
251 Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
253 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
255 mdb->num_rows = sql_num_rows(mdb);
256 if (mdb->num_rows > 1) {
257 Mmsg2(mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
258 edit_uint64(mdb->num_rows, ed1), mdb->path);
259 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
261 /* Even if there are multiple paths, take the first one */
262 if (mdb->num_rows >= 1) {
263 if ((row = sql_fetch_row(mdb)) == NULL) {
264 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
266 PathId = str_to_int64(row[0]);
268 Mmsg2(mdb->errmsg, _("Get DB path record %s found bad record: %s\n"),
269 mdb->cmd, edit_int64(PathId, ed1));
273 if (PathId != mdb->cached_path_id) {
274 mdb->cached_path_id = PathId;
275 mdb->cached_path_len = mdb->pnl;
276 pm_strcpy(mdb->cached_path, mdb->path);
281 Mmsg1(mdb->errmsg, _("Path record: %s not found.\n"), mdb->path);
283 sql_free_result(mdb);
285 Mmsg(mdb->errmsg, _("Path record: %s not found in Catalog.\n"), mdb->path);
292 * Get Job record for given JobId or Job name
293 * Returns: false on failure
296 bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
302 if (jr->JobId == 0) {
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 Job='%s'", jr->Job);
309 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
310 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
311 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
312 "SchedTime,RealEndTime,ReadBytes,HasBase "
313 "FROM Job WHERE JobId=%s",
314 edit_int64(jr->JobId, ed1));
317 if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
319 return false; /* failed */
321 if ((row = sql_fetch_row(mdb)) == NULL) {
322 Mmsg1(mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1));
323 sql_free_result(mdb);
325 return false; /* failed */
328 jr->VolSessionId = str_to_uint64(row[0]);
329 jr->VolSessionTime = str_to_uint64(row[1]);
330 jr->PoolId = str_to_int64(row[2]);
331 bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime));
332 bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime));
333 jr->JobFiles = str_to_int64(row[5]);
334 jr->JobBytes = str_to_int64(row[6]);
335 jr->JobTDate = str_to_int64(row[7]);
336 bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job));
337 jr->JobStatus = row[9]!=NULL?(int)*row[9]:JS_FatalError;
338 jr->JobType = row[10]!=NULL?(int)*row[10]:JT_BACKUP;
339 jr->JobLevel = row[11]!=NULL?(int)*row[11]:L_NONE;
340 jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)"");
341 bstrncpy(jr->Name, row[13]!=NULL?row[13]:"", sizeof(jr->Name));
342 jr->PriorJobId = str_to_uint64(row[14]!=NULL?row[14]:(char *)"");
343 bstrncpy(jr->cRealEndTime, row[15]!=NULL?row[15]:"", sizeof(jr->cRealEndTime));
344 if (jr->JobId == 0) {
345 jr->JobId = str_to_int64(row[16]);
347 jr->FileSetId = str_to_int64(row[17]);
348 bstrncpy(jr->cSchedTime, row[3]!=NULL?row[18]:"", sizeof(jr->cSchedTime));
349 bstrncpy(jr->cRealEndTime, row[3]!=NULL?row[19]:"", sizeof(jr->cRealEndTime));
350 jr->ReadBytes = str_to_int64(row[20]);
351 jr->StartTime = str_to_utime(jr->cStartTime);
352 jr->SchedTime = str_to_utime(jr->cSchedTime);
353 jr->EndTime = str_to_utime(jr->cEndTime);
354 jr->RealEndTime = str_to_utime(jr->cRealEndTime);
355 jr->HasBase = str_to_int64(row[21]);
356 sql_free_result(mdb);
363 * Find VolumeNames for a given JobId
364 * Returns: 0 on error or no Volumes found
365 * number of volumes on success
366 * Volumes are concatenated in VolumeNames
367 * separated by a vertical bar (|) in the order
368 * that they were written.
370 * Returns: number of volumes on success
372 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **VolumeNames)
380 /* Get one entry per VolumeName, but "sort" by VolIndex */
382 "SELECT VolumeName,MAX(VolIndex) FROM JobMedia,Media WHERE "
383 "JobMedia.JobId=%s AND JobMedia.MediaId=Media.MediaId "
384 "GROUP BY VolumeName "
385 "ORDER BY 2 ASC", edit_int64(JobId,ed1));
387 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
389 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
390 mdb->num_rows = sql_num_rows(mdb);
391 Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
392 if (mdb->num_rows <= 0) {
393 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
396 stat = mdb->num_rows;
397 for (i=0; i < stat; i++) {
398 if ((row = sql_fetch_row(mdb)) == NULL) {
399 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
400 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
404 if (*VolumeNames[0] != 0) {
405 pm_strcat(VolumeNames, "|");
407 pm_strcat(VolumeNames, row[0]);
411 sql_free_result(mdb);
413 Mmsg(mdb->errmsg, _("No Volume for JobId %d found in Catalog.\n"), JobId);
420 * Find Volume parameters for a give JobId
421 * Returns: 0 on error or no Volumes found
422 * number of volumes on success
423 * List of Volumes and start/end file/blocks (malloced structure!)
425 * Returns: number of volumes on success
427 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS **VolParams)
433 VOL_PARAMS *Vols = NULL;
437 "SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile,"
438 "JobMedia.EndFile,StartBlock,JobMedia.EndBlock,"
439 "Slot,StorageId,InChanger"
440 " FROM JobMedia,Media WHERE JobMedia.JobId=%s"
441 " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId",
442 edit_int64(JobId, ed1));
444 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
445 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
446 mdb->num_rows = sql_num_rows(mdb);
447 Dmsg1(200, "Num rows=%d\n", mdb->num_rows);
448 if (mdb->num_rows <= 0) {
449 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
452 stat = mdb->num_rows;
455 *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
456 SId = (DBId_t *)malloc(stat * sizeof(DBId_t));
458 for (i=0; i < stat; i++) {
459 if ((row = sql_fetch_row(mdb)) == NULL) {
460 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
461 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
466 uint32_t StartBlock, EndBlock, StartFile, EndFile;
467 bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH);
468 bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH);
469 Vols[i].FirstIndex = str_to_uint64(row[2]);
470 Vols[i].LastIndex = str_to_uint64(row[3]);
471 StartFile = str_to_uint64(row[4]);
472 EndFile = str_to_uint64(row[5]);
473 StartBlock = str_to_uint64(row[6]);
474 EndBlock = str_to_uint64(row[7]);
475 Vols[i].StartAddr = (((uint64_t)StartFile)<<32) | StartBlock;
476 Vols[i].EndAddr = (((uint64_t)EndFile)<<32) | EndBlock;
477 Vols[i].Slot = str_to_uint64(row[8]);
478 StorageId = str_to_uint64(row[9]);
479 Vols[i].InChanger = str_to_uint64(row[10]);
480 Vols[i].Storage[0] = 0;
484 for (i=0; i < stat; i++) {
486 Mmsg(mdb->cmd, "SELECT Name from Storage WHERE StorageId=%s",
487 edit_int64(SId[i], ed1));
488 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
489 if ((row = sql_fetch_row(mdb)) && row[0]) {
490 bstrncpy(Vols[i].Storage, row[0], MAX_NAME_LENGTH);
499 sql_free_result(mdb);
508 * Get the number of pool records
510 * Returns: -1 on failure
513 int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
518 Mmsg(mdb->cmd, "SELECT count(*) from Pool");
519 stat = get_sql_record_max(jcr, mdb);
525 * This function returns a list of all the Pool record ids.
526 * The caller must free ids if non-NULL.
528 * Returns 0: on failure
531 int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
540 Mmsg(mdb->cmd, "SELECT PoolId FROM Pool");
541 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
542 *num_ids = sql_num_rows(mdb);
544 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
545 while ((row = sql_fetch_row(mdb)) != NULL) {
546 id[i++] = str_to_uint64(row[0]);
550 sql_free_result(mdb);
553 Mmsg(mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
554 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
562 * This function returns a list of all the Client record ids.
563 * The caller must free ids if non-NULL.
565 * Returns 0: on failure
568 int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
577 Mmsg(mdb->cmd, "SELECT ClientId FROM Client ORDER BY Name");
578 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
579 *num_ids = sql_num_rows(mdb);
581 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
582 while ((row = sql_fetch_row(mdb)) != NULL) {
583 id[i++] = str_to_uint64(row[0]);
587 sql_free_result(mdb);
590 Mmsg(mdb->errmsg, _("Client id select failed: ERR=%s\n"), sql_strerror(mdb));
591 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
602 * If the PoolId is non-zero, we get its record,
603 * otherwise, we search on the PoolName
605 * Returns: false on failure
608 bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
615 if (pdbr->PoolId != 0) { /* find by id */
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.PoolId=%s",
621 edit_int64(pdbr->PoolId, ed1));
622 } else { /* find by name */
624 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
625 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
626 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
627 "ActionOnPurge FROM Pool WHERE Pool.Name='%s'",
630 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
631 mdb->num_rows = sql_num_rows(mdb);
632 if (mdb->num_rows > 1) {
634 Mmsg1(mdb->errmsg, _("More than one Pool!: %s\n"),
635 edit_uint64(mdb->num_rows, ed1));
636 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
637 } else if (mdb->num_rows == 1) {
638 if ((row = sql_fetch_row(mdb)) == NULL) {
639 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
640 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
642 pdbr->PoolId = str_to_int64(row[0]);
643 bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name));
644 pdbr->NumVols = str_to_int64(row[2]);
645 pdbr->MaxVols = str_to_int64(row[3]);
646 pdbr->UseOnce = str_to_int64(row[4]);
647 pdbr->UseCatalog = str_to_int64(row[5]);
648 pdbr->AcceptAnyVolume = str_to_int64(row[6]);
649 pdbr->AutoPrune = str_to_int64(row[7]);
650 pdbr->Recycle = str_to_int64(row[8]);
651 pdbr->VolRetention = str_to_int64(row[9]);
652 pdbr->VolUseDuration = str_to_int64(row[10]);
653 pdbr->MaxVolJobs = str_to_int64(row[11]);
654 pdbr->MaxVolFiles = str_to_int64(row[12]);
655 pdbr->MaxVolBytes = str_to_uint64(row[13]);
656 bstrncpy(pdbr->PoolType, row[14]!=NULL?row[14]:"", sizeof(pdbr->PoolType));
657 pdbr->LabelType = str_to_int64(row[15]);
658 bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat));
659 pdbr->RecyclePoolId = str_to_int64(row[17]);
660 pdbr->ScratchPoolId = str_to_int64(row[18]);
661 pdbr->ActionOnPurge = str_to_int32(row[19]);
665 sql_free_result(mdb);
669 Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
670 edit_int64(pdbr->PoolId, ed1));
671 NumVols = get_sql_record_max(jcr, mdb);
672 Dmsg2(400, "Actual NumVols=%d Pool NumVols=%d\n", NumVols, pdbr->NumVols);
673 if (NumVols != pdbr->NumVols) {
674 pdbr->NumVols = NumVols;
675 db_update_pool_record(jcr, mdb, pdbr);
678 Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n"));
686 * If the ClientId is non-zero, we get its record,
687 * otherwise, we search on the Client Name
689 * Returns: 0 on failure
692 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
699 if (cdbr->ClientId != 0) { /* find by id */
701 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
702 "FROM Client WHERE Client.ClientId=%s",
703 edit_int64(cdbr->ClientId, ed1));
704 } else { /* find by name */
706 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
707 "FROM Client WHERE Client.Name='%s'", cdbr->Name);
710 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
711 mdb->num_rows = sql_num_rows(mdb);
712 if (mdb->num_rows > 1) {
713 Mmsg1(mdb->errmsg, _("More than one Client!: %s\n"),
714 edit_uint64(mdb->num_rows, ed1));
715 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
716 } else if (mdb->num_rows == 1) {
717 if ((row = sql_fetch_row(mdb)) == NULL) {
718 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
719 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
721 cdbr->ClientId = str_to_int64(row[0]);
722 bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name));
723 bstrncpy(cdbr->Uname, row[2]!=NULL?row[2]:"", sizeof(cdbr->Uname));
724 cdbr->AutoPrune = str_to_int64(row[3]);
725 cdbr->FileRetention = str_to_int64(row[4]);
726 cdbr->JobRetention = str_to_int64(row[5]);
730 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
732 sql_free_result(mdb);
734 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
743 * Returns: 0 on failure
746 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
751 Mmsg(mdb->cmd, "SELECT MinValue,MaxValue,CurrentValue,WrapCounter "
752 "FROM Counters WHERE Counter='%s'", cr->Counter);
754 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
755 mdb->num_rows = sql_num_rows(mdb);
757 /* If more than one, report error, but return first row */
758 if (mdb->num_rows > 1) {
759 Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), (int)(mdb->num_rows));
760 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
762 if (mdb->num_rows >= 1) {
763 if ((row = sql_fetch_row(mdb)) == NULL) {
764 Mmsg1(mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb));
765 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
766 sql_free_result(mdb);
770 cr->MinValue = str_to_int64(row[0]);
771 cr->MaxValue = str_to_int64(row[1]);
772 cr->CurrentValue = str_to_int64(row[2]);
774 bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter));
776 cr->WrapCounter[0] = 0;
778 sql_free_result(mdb);
782 sql_free_result(mdb);
784 Mmsg(mdb->errmsg, _("Counter record: %s not found in Catalog.\n"), cr->Counter);
793 * If the FileSetId is non-zero, we get its record,
794 * otherwise, we search on the name
796 * Returns: 0 on failure
799 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
806 if (fsr->FileSetId != 0) { /* find by id */
808 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
809 "WHERE FileSetId=%s",
810 edit_int64(fsr->FileSetId, ed1));
811 } else { /* find by name */
813 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
814 "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", fsr->FileSet);
817 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
818 mdb->num_rows = sql_num_rows(mdb);
819 if (mdb->num_rows > 1) {
821 Mmsg1(mdb->errmsg, _("Error got %s FileSets but expected only one!\n"),
822 edit_uint64(mdb->num_rows, ed1));
823 sql_data_seek(mdb, mdb->num_rows-1);
825 if ((row = sql_fetch_row(mdb)) == NULL) {
826 Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
828 fsr->FileSetId = str_to_int64(row[0]);
829 bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
830 bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
831 bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime));
832 stat = fsr->FileSetId;
834 sql_free_result(mdb);
836 Mmsg(mdb->errmsg, _("FileSet record not found in Catalog.\n"));
844 * Get the number of Media records
846 * Returns: -1 on failure
849 int db_get_num_media_records(JCR *jcr, B_DB *mdb)
854 Mmsg(mdb->cmd, "SELECT count(*) from Media");
855 stat = get_sql_record_max(jcr, mdb);
861 * This function returns a list of all the Media record ids for
862 * the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
863 * VolumeName if specified
864 * The caller must free ids if non-NULL.
866 * Returns false: on failure
869 bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, int *num_ids, uint32_t *ids[])
876 char buf[MAX_NAME_LENGTH*3]; /* Can contain MAX_NAME_LENGTH*2+1 + AND ....='' */
877 char esc[MAX_NAME_LENGTH*2+1];
882 Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE Recycle=%d AND Enabled=%d ",
883 mr->Recycle, mr->Enabled);
885 if (*mr->MediaType) {
886 db_escape_string(jcr, mdb, esc, mr->MediaType, strlen(mr->MediaType));
887 bsnprintf(buf, sizeof(buf), "AND MediaType='%s' ", esc);
888 pm_strcat(mdb->cmd, buf);
892 bsnprintf(buf, sizeof(buf), "AND StorageId=%s ", edit_uint64(mr->StorageId, ed1));
893 pm_strcat(mdb->cmd, buf);
897 bsnprintf(buf, sizeof(buf), "AND PoolId=%s ", edit_uint64(mr->PoolId, ed1));
898 pm_strcat(mdb->cmd, buf);
902 bsnprintf(buf, sizeof(buf), "AND VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
903 pm_strcat(mdb->cmd, buf);
906 if (*mr->VolumeName) {
907 db_escape_string(jcr, mdb, esc, mr->VolumeName, strlen(mr->VolumeName));
908 bsnprintf(buf, sizeof(buf), "AND VolumeName = '%s' ", esc);
909 pm_strcat(mdb->cmd, buf);
912 if (*mr->VolStatus) {
913 db_escape_string(jcr, mdb, esc, mr->VolStatus, strlen(mr->VolStatus));
914 bsnprintf(buf, sizeof(buf), "AND VolStatus = '%s' ", esc);
915 pm_strcat(mdb->cmd, buf);
918 Dmsg1(100, "q=%s\n", mdb->cmd);
920 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
921 *num_ids = sql_num_rows(mdb);
923 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
924 while ((row = sql_fetch_row(mdb)) != NULL) {
925 id[i++] = str_to_uint64(row[0]);
929 sql_free_result(mdb);
932 Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
933 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
942 * This function returns a list of all the DBIds that are returned
945 * Returns false: on failure
948 bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids)
956 if (QUERY_DB(jcr, mdb, query.c_str())) {
957 ids.num_ids = sql_num_rows(mdb);
958 if (ids.num_ids > 0) {
959 if (ids.max_ids < ids.num_ids) {
961 ids.DBId = (DBId_t *)malloc(ids.num_ids * sizeof(DBId_t));
963 while ((row = sql_fetch_row(mdb)) != NULL) {
964 ids.DBId[i++] = str_to_uint64(row[0]);
967 sql_free_result(mdb);
970 Mmsg(mdb->errmsg, _("query dbids failed: ERR=%s\n"), sql_strerror(mdb));
971 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
981 * Returns: false: on failure
984 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
991 if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
992 Mmsg(mdb->cmd, "SELECT count(*) from Media");
993 mr->MediaId = get_sql_record_max(jcr, mdb);
997 if (mr->MediaId != 0) { /* find by id */
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 MediaId=%s",
1006 edit_int64(mr->MediaId, ed1));
1007 } else { /* find by name */
1008 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
1009 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
1010 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
1011 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
1012 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
1013 "Enabled,LocationId,RecycleCount,InitialWrite,"
1014 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
1015 "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
1018 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1020 mdb->num_rows = sql_num_rows(mdb);
1021 if (mdb->num_rows > 1) {
1022 Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
1023 edit_uint64(mdb->num_rows, ed1));
1024 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1025 } else if (mdb->num_rows == 1) {
1026 if ((row = sql_fetch_row(mdb)) == NULL) {
1027 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
1028 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1031 mr->MediaId = str_to_int64(row[0]);
1032 bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
1033 mr->VolJobs = str_to_int64(row[2]);
1034 mr->VolFiles = str_to_int64(row[3]);
1035 mr->VolBlocks = str_to_int64(row[4]);
1036 mr->VolBytes = str_to_uint64(row[5]);
1037 mr->VolMounts = str_to_int64(row[6]);
1038 mr->VolErrors = str_to_int64(row[7]);
1039 mr->VolWrites = str_to_int64(row[8]);
1040 mr->MaxVolBytes = str_to_uint64(row[9]);
1041 mr->VolCapacityBytes = str_to_uint64(row[10]);
1042 bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
1043 bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
1044 mr->PoolId = str_to_int64(row[13]);
1045 mr->VolRetention = str_to_uint64(row[14]);
1046 mr->VolUseDuration = str_to_uint64(row[15]);
1047 mr->MaxVolJobs = str_to_int64(row[16]);
1048 mr->MaxVolFiles = str_to_int64(row[17]);
1049 mr->Recycle = str_to_int64(row[18]);
1050 mr->Slot = str_to_int64(row[19]);
1051 bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
1052 mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
1053 bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
1054 mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
1055 mr->InChanger = str_to_uint64(row[22]);
1056 mr->EndFile = str_to_uint64(row[23]);
1057 mr->EndBlock = str_to_uint64(row[24]);
1058 mr->VolParts = str_to_int64(row[25]);
1059 mr->LabelType = str_to_int64(row[26]);
1060 bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
1061 mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
1062 mr->StorageId = str_to_int64(row[28]);
1063 mr->Enabled = str_to_int64(row[29]);
1064 mr->LocationId = str_to_int64(row[30]);
1065 mr->RecycleCount = str_to_int64(row[31]);
1066 bstrncpy(mr->cInitialWrite, row[32]!=NULL?row[32]:"", sizeof(mr->cInitialWrite));
1067 mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
1068 mr->ScratchPoolId = str_to_int64(row[33]);
1069 mr->RecyclePoolId = str_to_int64(row[34]);
1070 mr->VolReadTime = str_to_int64(row[35]);
1071 mr->VolWriteTime = str_to_int64(row[36]);
1072 mr->ActionOnPurge = str_to_int32(row[37]);
1077 if (mr->MediaId != 0) {
1078 Mmsg1(mdb->errmsg, _("Media record MediaId=%s not found.\n"),
1079 edit_int64(mr->MediaId, ed1));
1081 Mmsg1(mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"),
1085 sql_free_result(mdb);
1087 if (mr->MediaId != 0) {
1088 Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"),
1091 Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"),
1099 * Find the last "accurate" backup state (that can take deleted files in
1101 * 1) Get all files with jobid in list (F subquery)
1102 * Get all files in BaseFiles with jobid in list
1103 * 2) Take only the last version of each file (Temp subquery) => accurate list
1105 * 3) Join the result to file table to get fileindex, jobid and lstat information
1107 * TODO: See if we can do the SORT only if needed (as an argument)
1109 bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
1110 DB_RESULT_HANDLER *result_handler, void *ctx)
1114 Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
1118 POOL_MEM buf(PM_MESSAGE);
1120 #define new_db_get_file_list
1121 #ifdef new_db_get_file_list
1122 POOL_MEM buf2(PM_MESSAGE);
1123 Mmsg(buf2, select_recent_version_with_basejob[db_type],
1124 jobids, jobids, jobids, jobids);
1126 "SELECT Path.Path, Filename.Name, Temp.FileIndex, Temp.JobId, LStat, MD5 "
1127 "FROM ( %s ) AS Temp "
1128 "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
1129 "JOIN Path ON (Path.PathId = Temp.PathId) "
1130 "WHERE FileIndex > 0 "
1131 "ORDER BY Temp.JobId, FileIndex ASC",/* Return sorted by JobId, */
1132 /* FileIndex for restore code */
1136 * I am not sure that this works the same as the code in ua_restore.c but it
1137 * is very similar. The accurate-test fails in a restore. Bad file count.
1139 Mmsg(buf, uar_sel_files, jobids);
1142 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1146 * This procedure gets the base jobid list used by jobids,
1148 bool db_get_used_base_jobids(JCR *jcr, B_DB *mdb,
1149 POOLMEM *jobids, db_list_ctx *result)
1153 "SELECT DISTINCT BaseJobId "
1154 " FROM Job JOIN BaseFiles USING (JobId) "
1155 " WHERE Job.HasBase = 1 "
1156 " AND Job.JobId IN (%s) ", jobids);
1157 return db_sql_query(mdb, buf.c_str(), db_list_handler, result);
1161 * The decision do change an incr/diff was done before
1163 * Differential : get the last full id
1164 * Incremental : get the last full + last diff + last incr(s) ids
1166 * If you specify jr->StartTime, it will be used to limit the search
1167 * in the time. (usually now)
1169 * TODO: look and merge from ua_restore.c
1171 bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
1172 JOB_DBR *jr, db_list_ctx *jobids)
1175 char clientid[50], jobid[50], filesetid[50];
1176 char date[MAX_TIME_LENGTH];
1177 POOL_MEM query(PM_FNAME);
1179 /* Take the current time as upper limit if nothing else specified */
1180 utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1182 bstrutime(date, sizeof(date), StartTime + 1);
1183 jobids->list[0] = 0;
1186 /* First, find the last good Full backup for this job/client/fileset */
1188 "CREATE TABLE btemp3%s AS "
1189 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1190 "FROM Job JOIN FileSet USING (FileSetId) "
1191 "WHERE ClientId = %s "
1192 "AND Level='F' AND JobStatus IN ('T','W') AND Type='B' "
1193 "AND StartTime<'%s' "
1194 "AND FileSet.FileSet=(SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1195 "ORDER BY Job.JobTDate DESC LIMIT 1",
1196 edit_uint64(jcr->JobId, jobid),
1197 edit_uint64(jr->ClientId, clientid),
1199 edit_uint64(jr->FileSetId, filesetid));
1201 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1205 if (jr->JobLevel == L_INCREMENTAL || jr->JobLevel == L_VIRTUAL_FULL) {
1206 /* Now, find the last differential backup after the last full */
1208 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1209 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1210 "FROM Job JOIN FileSet USING (FileSetId) "
1211 "WHERE ClientId = %s "
1212 "AND Level='D' AND JobStatus IN ('T','W') AND Type='B' "
1213 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1214 "AND StartTime < '%s' "
1215 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1216 "ORDER BY Job.JobTDate DESC LIMIT 1 ",
1223 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1227 /* We just have to take all incremental after the last Full/Diff */
1229 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1230 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1231 "FROM Job JOIN FileSet USING (FileSetId) "
1232 "WHERE ClientId = %s "
1233 "AND Level='I' AND JobStatus IN ('T','W') AND Type='B' "
1234 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1235 "AND StartTime < '%s' "
1236 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1237 "ORDER BY Job.JobTDate DESC ",
1243 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1248 /* build a jobid list ie: 1,2,3,4 */
1249 Mmsg(query, "SELECT JobId FROM btemp3%s ORDER by JobTDate", jobid);
1250 db_sql_query(mdb, query.c_str(), db_list_handler, jobids);
1251 Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids->list);
1255 Mmsg(query, "DROP TABLE btemp3%s", jobid);
1256 db_sql_query(mdb, query.c_str(), NULL, NULL);
1261 bool db_get_base_file_list(JCR *jcr, B_DB *mdb,
1262 DB_RESULT_HANDLER *result_handler, void *ctx)
1264 POOL_MEM buf(PM_MESSAGE);
1267 "SELECT Path, Name, FileIndex, JobId, LStat, MD5 "
1268 "FROM new_basefile%lld ORDER BY JobId, FileIndex ASC",
1269 (uint64_t) jcr->JobId);
1271 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1274 bool db_get_base_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr, JobId_t *jobid)
1276 POOL_MEM query(PM_FNAME);
1279 char date[MAX_TIME_LENGTH];
1283 // char clientid[50], filesetid[50];
1285 StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1286 bstrutime(date, sizeof(date), StartTime + 1);
1288 /* we can take also client name, fileset, etc... */
1291 "SELECT JobId, Job, StartTime, EndTime, JobTDate, PurgedFiles "
1293 // "JOIN FileSet USING (FileSetId) JOIN Client USING (ClientId) "
1294 "WHERE Job.Name = '%s' "
1295 "AND Level='B' AND JobStatus IN ('T','W') AND Type='B' "
1296 // "AND FileSet.FileSet= '%s' "
1297 // "AND Client.Name = '%s' "
1298 "AND StartTime<'%s' "
1299 "ORDER BY Job.JobTDate DESC LIMIT 1",
1301 // edit_uint64(jr->ClientId, clientid),
1302 // edit_uint64(jr->FileSetId, filesetid));
1305 Dmsg1(10, "db_get_base_jobid q=%s\n", query.c_str());
1306 if (!db_sql_query(mdb, query.c_str(), db_int64_handler, &lctx)) {
1309 *jobid = (JobId_t) lctx.value;
1311 Dmsg1(10, "db_get_base_jobid=%lld\n", *jobid);
1318 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */