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) {
122 "SELECT FileId, LStat, MD5 FROM File,Job WHERE "
123 "File.JobId=Job.JobId AND File.PathId=%s AND "
124 "File.FilenameId=%s AND Job.Type='B' AND Job.JobStatus IN ('T','W') AND "
125 "ClientId=%s ORDER BY StartTime DESC FETCH FIRST 1 ROW ONLY",
126 edit_int64(fdbr->PathId, ed1),
127 edit_int64(fdbr->FilenameId, ed2),
128 edit_int64(jr->ClientId,ed3));
131 "SELECT FileId, LStat, MD5 FROM File,Job WHERE "
132 "File.JobId=Job.JobId AND File.PathId=%s AND "
133 "File.FilenameId=%s AND Job.Type='B' AND Job.JobStatus IN ('T','W') AND "
134 "ClientId=%s ORDER BY StartTime DESC LIMIT 1",
135 edit_int64(fdbr->PathId, ed1),
136 edit_int64(fdbr->FilenameId, ed2),
137 edit_int64(jr->ClientId,ed3));
141 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
142 "File.FilenameId=%s",
143 edit_int64(fdbr->JobId, ed1),
144 edit_int64(fdbr->PathId, ed2),
145 edit_int64(fdbr->FilenameId,ed3));
147 Dmsg3(450, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
148 fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
150 Dmsg1(100, "Query=%s\n", mdb->cmd);
152 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
153 mdb->num_rows = sql_num_rows(mdb);
154 Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows);
155 if (mdb->num_rows >= 1) {
156 if ((row = sql_fetch_row(mdb)) == NULL) {
157 Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
159 fdbr->FileId = (FileId_t)str_to_int64(row[0]);
160 bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
161 bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
163 if (mdb->num_rows > 1) {
164 Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
166 edit_int64(fdbr->PathId, ed1),
167 edit_int64(fdbr->FilenameId, ed2));
168 Dmsg1(000, "=== Problem! %s", mdb->errmsg);
172 Mmsg2(mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"),
173 edit_int64(fdbr->PathId, ed1),
174 edit_int64(fdbr->FilenameId, ed2));
176 sql_free_result(mdb);
178 Mmsg(mdb->errmsg, _("File record not found in Catalog.\n"));
185 * Get Filename record
186 * Returns: 0 on failure
187 * FilenameId on success
189 * DO NOT use Jmsg in this routine (see notes for get_file_record)
191 static int db_get_filename_record(JCR *jcr, B_DB *mdb)
196 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
197 db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
199 Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
200 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
202 mdb->num_rows = sql_num_rows(mdb);
203 if (mdb->num_rows > 1) {
204 Mmsg2(mdb->errmsg, _("More than one Filename!: %s for file: %s\n"),
205 edit_uint64(mdb->num_rows, ed1), mdb->fname);
206 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
208 if (mdb->num_rows >= 1) {
209 if ((row = sql_fetch_row(mdb)) == NULL) {
210 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
212 FilenameId = str_to_int64(row[0]);
213 if (FilenameId <= 0) {
214 Mmsg2(mdb->errmsg, _("Get DB Filename record %s found bad record: %d\n"),
215 mdb->cmd, FilenameId);
220 Mmsg1(mdb->errmsg, _("Filename record: %s not found.\n"), mdb->fname);
222 sql_free_result(mdb);
224 Mmsg(mdb->errmsg, _("Filename record: %s not found in Catalog.\n"), mdb->fname);
231 * Returns: 0 on failure
234 * DO NOT use Jmsg in this routine (see notes for get_file_record)
236 int db_get_path_record(JCR *jcr, B_DB *mdb)
241 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
242 db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
244 if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
245 strcmp(mdb->cached_path, mdb->path) == 0) {
246 return mdb->cached_path_id;
249 Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
251 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
253 mdb->num_rows = sql_num_rows(mdb);
254 if (mdb->num_rows > 1) {
255 Mmsg2(mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
256 edit_uint64(mdb->num_rows, ed1), mdb->path);
257 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
259 /* Even if there are multiple paths, take the first one */
260 if (mdb->num_rows >= 1) {
261 if ((row = sql_fetch_row(mdb)) == NULL) {
262 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
264 PathId = str_to_int64(row[0]);
266 Mmsg2(mdb->errmsg, _("Get DB path record %s found bad record: %s\n"),
267 mdb->cmd, edit_int64(PathId, ed1));
271 if (PathId != mdb->cached_path_id) {
272 mdb->cached_path_id = PathId;
273 mdb->cached_path_len = mdb->pnl;
274 pm_strcpy(mdb->cached_path, mdb->path);
279 Mmsg1(mdb->errmsg, _("Path record: %s not found.\n"), mdb->path);
281 sql_free_result(mdb);
283 Mmsg(mdb->errmsg, _("Path record: %s not found in Catalog.\n"), mdb->path);
290 * Get Job record for given JobId or Job name
291 * Returns: false on failure
294 bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
300 if (jr->JobId == 0) {
301 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
302 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
303 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
304 "SchedTime,RealEndTime,ReadBytes,HasBase "
305 "FROM Job WHERE Job='%s'", jr->Job);
307 Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
308 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
309 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
310 "SchedTime,RealEndTime,ReadBytes,HasBase "
311 "FROM Job WHERE JobId=%s",
312 edit_int64(jr->JobId, ed1));
315 if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
317 return false; /* failed */
319 if ((row = sql_fetch_row(mdb)) == NULL) {
320 Mmsg1(mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1));
321 sql_free_result(mdb);
323 return false; /* failed */
326 jr->VolSessionId = str_to_uint64(row[0]);
327 jr->VolSessionTime = str_to_uint64(row[1]);
328 jr->PoolId = str_to_int64(row[2]);
329 bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime));
330 bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime));
331 jr->JobFiles = str_to_int64(row[5]);
332 jr->JobBytes = str_to_int64(row[6]);
333 jr->JobTDate = str_to_int64(row[7]);
334 bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job));
335 jr->JobStatus = row[9]!=NULL?(int)*row[9]:JS_FatalError;
336 jr->JobType = row[10]!=NULL?(int)*row[10]:JT_BACKUP;
337 jr->JobLevel = row[11]!=NULL?(int)*row[11]:L_NONE;
338 jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)"");
339 bstrncpy(jr->Name, row[13]!=NULL?row[13]:"", sizeof(jr->Name));
340 jr->PriorJobId = str_to_uint64(row[14]!=NULL?row[14]:(char *)"");
341 bstrncpy(jr->cRealEndTime, row[15]!=NULL?row[15]:"", sizeof(jr->cRealEndTime));
342 if (jr->JobId == 0) {
343 jr->JobId = str_to_int64(row[16]);
345 jr->FileSetId = str_to_int64(row[17]);
346 bstrncpy(jr->cSchedTime, row[3]!=NULL?row[18]:"", sizeof(jr->cSchedTime));
347 bstrncpy(jr->cRealEndTime, row[3]!=NULL?row[19]:"", sizeof(jr->cRealEndTime));
348 jr->ReadBytes = str_to_int64(row[20]);
349 jr->StartTime = str_to_utime(jr->cStartTime);
350 jr->SchedTime = str_to_utime(jr->cSchedTime);
351 jr->EndTime = str_to_utime(jr->cEndTime);
352 jr->RealEndTime = str_to_utime(jr->cRealEndTime);
353 jr->HasBase = str_to_int64(row[21]);
354 sql_free_result(mdb);
361 * Find VolumeNames for a given JobId
362 * Returns: 0 on error or no Volumes found
363 * number of volumes on success
364 * Volumes are concatenated in VolumeNames
365 * separated by a vertical bar (|) in the order
366 * that they were written.
368 * Returns: number of volumes on success
370 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **VolumeNames)
378 /* Get one entry per VolumeName, but "sort" by VolIndex */
380 "SELECT VolumeName,MAX(VolIndex) FROM JobMedia,Media WHERE "
381 "JobMedia.JobId=%s AND JobMedia.MediaId=Media.MediaId "
382 "GROUP BY VolumeName "
383 "ORDER BY 2 ASC", edit_int64(JobId,ed1));
385 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
387 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
388 mdb->num_rows = sql_num_rows(mdb);
389 Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
390 if (mdb->num_rows <= 0) {
391 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
394 stat = mdb->num_rows;
395 for (i=0; i < stat; i++) {
396 if ((row = sql_fetch_row(mdb)) == NULL) {
397 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
398 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
402 if (*VolumeNames[0] != 0) {
403 pm_strcat(VolumeNames, "|");
405 pm_strcat(VolumeNames, row[0]);
409 sql_free_result(mdb);
411 Mmsg(mdb->errmsg, _("No Volume for JobId %d found in Catalog.\n"), JobId);
418 * Find Volume parameters for a give JobId
419 * Returns: 0 on error or no Volumes found
420 * number of volumes on success
421 * List of Volumes and start/end file/blocks (malloced structure!)
423 * Returns: number of volumes on success
425 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS **VolParams)
431 VOL_PARAMS *Vols = NULL;
435 "SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile,"
436 "JobMedia.EndFile,StartBlock,JobMedia.EndBlock,"
437 "Slot,StorageId,InChanger"
438 " FROM JobMedia,Media WHERE JobMedia.JobId=%s"
439 " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId",
440 edit_int64(JobId, ed1));
442 Dmsg1(130, "VolNam=%s\n", mdb->cmd);
443 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
444 mdb->num_rows = sql_num_rows(mdb);
445 Dmsg1(200, "Num rows=%d\n", mdb->num_rows);
446 if (mdb->num_rows <= 0) {
447 Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
450 stat = mdb->num_rows;
453 *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
454 SId = (DBId_t *)malloc(stat * sizeof(DBId_t));
456 for (i=0; i < stat; i++) {
457 if ((row = sql_fetch_row(mdb)) == NULL) {
458 Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
459 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
464 uint32_t StartBlock, EndBlock, StartFile, EndFile;
465 bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH);
466 bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH);
467 Vols[i].FirstIndex = str_to_uint64(row[2]);
468 Vols[i].LastIndex = str_to_uint64(row[3]);
469 StartFile = str_to_uint64(row[4]);
470 EndFile = str_to_uint64(row[5]);
471 StartBlock = str_to_uint64(row[6]);
472 EndBlock = str_to_uint64(row[7]);
473 Vols[i].StartAddr = (((uint64_t)StartFile)<<32) | StartBlock;
474 Vols[i].EndAddr = (((uint64_t)EndFile)<<32) | EndBlock;
475 Vols[i].Slot = str_to_uint64(row[8]);
476 StorageId = str_to_uint64(row[9]);
477 Vols[i].InChanger = str_to_uint64(row[10]);
478 Vols[i].Storage[0] = 0;
482 for (i=0; i < stat; i++) {
484 Mmsg(mdb->cmd, "SELECT Name from Storage WHERE StorageId=%s",
485 edit_int64(SId[i], ed1));
486 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
487 if ((row = sql_fetch_row(mdb)) && row[0]) {
488 bstrncpy(Vols[i].Storage, row[0], MAX_NAME_LENGTH);
497 sql_free_result(mdb);
506 * Get the number of pool records
508 * Returns: -1 on failure
511 int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
516 Mmsg(mdb->cmd, "SELECT count(*) from Pool");
517 stat = get_sql_record_max(jcr, mdb);
523 * This function returns a list of all the Pool record ids.
524 * The caller must free ids if non-NULL.
526 * Returns 0: on failure
529 int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
538 Mmsg(mdb->cmd, "SELECT PoolId FROM Pool");
539 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
540 *num_ids = sql_num_rows(mdb);
542 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
543 while ((row = sql_fetch_row(mdb)) != NULL) {
544 id[i++] = str_to_uint64(row[0]);
548 sql_free_result(mdb);
551 Mmsg(mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
552 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
560 * This function returns a list of all the Client record ids.
561 * The caller must free ids if non-NULL.
563 * Returns 0: on failure
566 int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
575 Mmsg(mdb->cmd, "SELECT ClientId FROM Client ORDER BY Name");
576 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
577 *num_ids = sql_num_rows(mdb);
579 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
580 while ((row = sql_fetch_row(mdb)) != NULL) {
581 id[i++] = str_to_uint64(row[0]);
585 sql_free_result(mdb);
588 Mmsg(mdb->errmsg, _("Client id select failed: ERR=%s\n"), sql_strerror(mdb));
589 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
600 * If the PoolId is non-zero, we get its record,
601 * otherwise, we search on the PoolName
603 * Returns: false on failure
606 bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
613 if (pdbr->PoolId != 0) { /* find by id */
615 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
616 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
617 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
618 "ActionOnPurge FROM Pool WHERE Pool.PoolId=%s",
619 edit_int64(pdbr->PoolId, ed1));
620 } else { /* find by name */
622 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
623 "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
624 "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
625 "ActionOnPurge FROM Pool WHERE Pool.Name='%s'",
628 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
629 mdb->num_rows = sql_num_rows(mdb);
630 if (mdb->num_rows > 1) {
632 Mmsg1(mdb->errmsg, _("More than one Pool!: %s\n"),
633 edit_uint64(mdb->num_rows, ed1));
634 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
635 } else if (mdb->num_rows == 1) {
636 if ((row = sql_fetch_row(mdb)) == NULL) {
637 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
638 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
640 pdbr->PoolId = str_to_int64(row[0]);
641 bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name));
642 pdbr->NumVols = str_to_int64(row[2]);
643 pdbr->MaxVols = str_to_int64(row[3]);
644 pdbr->UseOnce = str_to_int64(row[4]);
645 pdbr->UseCatalog = str_to_int64(row[5]);
646 pdbr->AcceptAnyVolume = str_to_int64(row[6]);
647 pdbr->AutoPrune = str_to_int64(row[7]);
648 pdbr->Recycle = str_to_int64(row[8]);
649 pdbr->VolRetention = str_to_int64(row[9]);
650 pdbr->VolUseDuration = str_to_int64(row[10]);
651 pdbr->MaxVolJobs = str_to_int64(row[11]);
652 pdbr->MaxVolFiles = str_to_int64(row[12]);
653 pdbr->MaxVolBytes = str_to_uint64(row[13]);
654 bstrncpy(pdbr->PoolType, row[14]!=NULL?row[14]:"", sizeof(pdbr->PoolType));
655 pdbr->LabelType = str_to_int64(row[15]);
656 bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat));
657 pdbr->RecyclePoolId = str_to_int64(row[17]);
658 pdbr->ScratchPoolId = str_to_int64(row[18]);
659 pdbr->ActionOnPurge = str_to_int32(row[19]);
663 sql_free_result(mdb);
667 Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
668 edit_int64(pdbr->PoolId, ed1));
669 NumVols = get_sql_record_max(jcr, mdb);
670 Dmsg2(400, "Actual NumVols=%d Pool NumVols=%d\n", NumVols, pdbr->NumVols);
671 if (NumVols != pdbr->NumVols) {
672 pdbr->NumVols = NumVols;
673 db_update_pool_record(jcr, mdb, pdbr);
676 Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n"));
684 * If the ClientId is non-zero, we get its record,
685 * otherwise, we search on the Client Name
687 * Returns: 0 on failure
690 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
697 if (cdbr->ClientId != 0) { /* find by id */
699 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
700 "FROM Client WHERE Client.ClientId=%s",
701 edit_int64(cdbr->ClientId, ed1));
702 } else { /* find by name */
704 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
705 "FROM Client WHERE Client.Name='%s'", cdbr->Name);
708 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
709 mdb->num_rows = sql_num_rows(mdb);
710 if (mdb->num_rows > 1) {
711 Mmsg1(mdb->errmsg, _("More than one Client!: %s\n"),
712 edit_uint64(mdb->num_rows, ed1));
713 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
714 } else if (mdb->num_rows == 1) {
715 if ((row = sql_fetch_row(mdb)) == NULL) {
716 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
717 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
719 cdbr->ClientId = str_to_int64(row[0]);
720 bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name));
721 bstrncpy(cdbr->Uname, row[2]!=NULL?row[2]:"", sizeof(cdbr->Uname));
722 cdbr->AutoPrune = str_to_int64(row[3]);
723 cdbr->FileRetention = str_to_int64(row[4]);
724 cdbr->JobRetention = str_to_int64(row[5]);
728 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
730 sql_free_result(mdb);
732 Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n"));
741 * Returns: 0 on failure
744 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
749 Mmsg(mdb->cmd, "SELECT MinValue,MaxValue,CurrentValue,WrapCounter "
750 "FROM Counters WHERE Counter='%s'", cr->Counter);
752 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
753 mdb->num_rows = sql_num_rows(mdb);
755 /* If more than one, report error, but return first row */
756 if (mdb->num_rows > 1) {
757 Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), (int)(mdb->num_rows));
758 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
760 if (mdb->num_rows >= 1) {
761 if ((row = sql_fetch_row(mdb)) == NULL) {
762 Mmsg1(mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb));
763 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
764 sql_free_result(mdb);
768 cr->MinValue = str_to_int64(row[0]);
769 cr->MaxValue = str_to_int64(row[1]);
770 cr->CurrentValue = str_to_int64(row[2]);
772 bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter));
774 cr->WrapCounter[0] = 0;
776 sql_free_result(mdb);
780 sql_free_result(mdb);
782 Mmsg(mdb->errmsg, _("Counter record: %s not found in Catalog.\n"), cr->Counter);
791 * If the FileSetId is non-zero, we get its record,
792 * otherwise, we search on the name
794 * Returns: 0 on failure
797 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
804 if (fsr->FileSetId != 0) { /* find by id */
806 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
807 "WHERE FileSetId=%s",
808 edit_int64(fsr->FileSetId, ed1));
809 } else { /* find by name */
812 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
813 "WHERE FileSet='%s' ORDER BY CreateTime DESC FETCH FIRST 1 ROW ONLY", fsr->FileSet);
816 "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
817 "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", fsr->FileSet);
821 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
822 mdb->num_rows = sql_num_rows(mdb);
823 if (mdb->num_rows > 1) {
825 Mmsg1(mdb->errmsg, _("Error got %s FileSets but expected only one!\n"),
826 edit_uint64(mdb->num_rows, ed1));
827 sql_data_seek(mdb, mdb->num_rows-1);
829 if ((row = sql_fetch_row(mdb)) == NULL) {
830 Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
832 fsr->FileSetId = str_to_int64(row[0]);
833 bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
834 bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
835 bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime));
836 stat = fsr->FileSetId;
838 sql_free_result(mdb);
840 Mmsg(mdb->errmsg, _("FileSet record not found in Catalog.\n"));
848 * Get the number of Media records
850 * Returns: -1 on failure
853 int db_get_num_media_records(JCR *jcr, B_DB *mdb)
858 Mmsg(mdb->cmd, "SELECT count(*) from Media");
859 stat = get_sql_record_max(jcr, mdb);
865 * This function returns a list of all the Media record ids for
866 * the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
867 * VolumeName if specified
868 * The caller must free ids if non-NULL.
870 * Returns false: on failure
873 bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, int *num_ids, uint32_t *ids[])
880 char buf[MAX_NAME_LENGTH*3]; /* Can contain MAX_NAME_LENGTH*2+1 + AND ....='' */
881 char esc[MAX_NAME_LENGTH*2+1];
886 Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE Recycle=%d AND Enabled=%d ",
887 mr->Recycle, mr->Enabled);
889 if (*mr->MediaType) {
890 db_escape_string(jcr, mdb, esc, mr->MediaType, strlen(mr->MediaType));
891 bsnprintf(buf, sizeof(buf), "AND MediaType='%s' ", esc);
892 pm_strcat(mdb->cmd, buf);
896 bsnprintf(buf, sizeof(buf), "AND StorageId=%s ", edit_uint64(mr->StorageId, ed1));
897 pm_strcat(mdb->cmd, buf);
901 bsnprintf(buf, sizeof(buf), "AND PoolId=%s ", edit_uint64(mr->PoolId, ed1));
902 pm_strcat(mdb->cmd, buf);
906 bsnprintf(buf, sizeof(buf), "AND VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
907 pm_strcat(mdb->cmd, buf);
910 if (*mr->VolumeName) {
911 db_escape_string(jcr, mdb, esc, mr->VolumeName, strlen(mr->VolumeName));
912 bsnprintf(buf, sizeof(buf), "AND VolumeName = '%s' ", esc);
913 pm_strcat(mdb->cmd, buf);
916 if (*mr->VolStatus) {
917 db_escape_string(jcr, mdb, esc, mr->VolStatus, strlen(mr->VolStatus));
918 bsnprintf(buf, sizeof(buf), "AND VolStatus = '%s' ", esc);
919 pm_strcat(mdb->cmd, buf);
922 Dmsg1(100, "q=%s\n", mdb->cmd);
924 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
925 *num_ids = sql_num_rows(mdb);
927 id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
928 while ((row = sql_fetch_row(mdb)) != NULL) {
929 id[i++] = str_to_uint64(row[0]);
933 sql_free_result(mdb);
936 Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
937 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
946 * This function returns a list of all the DBIds that are returned
949 * Returns false: on failure
952 bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids)
960 if (QUERY_DB(jcr, mdb, query.c_str())) {
961 ids.num_ids = sql_num_rows(mdb);
962 if (ids.num_ids > 0) {
963 if (ids.max_ids < ids.num_ids) {
965 ids.DBId = (DBId_t *)malloc(ids.num_ids * sizeof(DBId_t));
967 while ((row = sql_fetch_row(mdb)) != NULL) {
968 ids.DBId[i++] = str_to_uint64(row[0]);
971 sql_free_result(mdb);
974 Mmsg(mdb->errmsg, _("query dbids failed: ERR=%s\n"), sql_strerror(mdb));
975 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
985 * Returns: false: on failure
988 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
995 if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
996 Mmsg(mdb->cmd, "SELECT count(*) from Media");
997 mr->MediaId = get_sql_record_max(jcr, mdb);
1001 if (mr->MediaId != 0) { /* find by id */
1002 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
1003 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
1004 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
1005 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
1006 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
1007 "Enabled,LocationId,RecycleCount,InitialWrite,"
1008 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
1009 "FROM Media WHERE MediaId=%s",
1010 edit_int64(mr->MediaId, ed1));
1011 } else { /* find by name */
1012 Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
1013 "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
1014 "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
1015 "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
1016 "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
1017 "Enabled,LocationId,RecycleCount,InitialWrite,"
1018 "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
1019 "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
1022 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1024 mdb->num_rows = sql_num_rows(mdb);
1025 if (mdb->num_rows > 1) {
1026 Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
1027 edit_uint64(mdb->num_rows, ed1));
1028 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1029 } else if (mdb->num_rows == 1) {
1030 if ((row = sql_fetch_row(mdb)) == NULL) {
1031 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
1032 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1035 mr->MediaId = str_to_int64(row[0]);
1036 bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
1037 mr->VolJobs = str_to_int64(row[2]);
1038 mr->VolFiles = str_to_int64(row[3]);
1039 mr->VolBlocks = str_to_int64(row[4]);
1040 mr->VolBytes = str_to_uint64(row[5]);
1041 mr->VolMounts = str_to_int64(row[6]);
1042 mr->VolErrors = str_to_int64(row[7]);
1043 mr->VolWrites = str_to_int64(row[8]);
1044 mr->MaxVolBytes = str_to_uint64(row[9]);
1045 mr->VolCapacityBytes = str_to_uint64(row[10]);
1046 bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
1047 bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
1048 mr->PoolId = str_to_int64(row[13]);
1049 mr->VolRetention = str_to_uint64(row[14]);
1050 mr->VolUseDuration = str_to_uint64(row[15]);
1051 mr->MaxVolJobs = str_to_int64(row[16]);
1052 mr->MaxVolFiles = str_to_int64(row[17]);
1053 mr->Recycle = str_to_int64(row[18]);
1054 mr->Slot = str_to_int64(row[19]);
1055 bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
1056 mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
1057 bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
1058 mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
1059 mr->InChanger = str_to_uint64(row[22]);
1060 mr->EndFile = str_to_uint64(row[23]);
1061 mr->EndBlock = str_to_uint64(row[24]);
1062 mr->VolParts = str_to_int64(row[25]);
1063 mr->LabelType = str_to_int64(row[26]);
1064 bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
1065 mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
1066 mr->StorageId = str_to_int64(row[28]);
1067 mr->Enabled = str_to_int64(row[29]);
1068 mr->LocationId = str_to_int64(row[30]);
1069 mr->RecycleCount = str_to_int64(row[31]);
1070 bstrncpy(mr->cInitialWrite, row[32]!=NULL?row[32]:"", sizeof(mr->cInitialWrite));
1071 mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
1072 mr->ScratchPoolId = str_to_int64(row[33]);
1073 mr->RecyclePoolId = str_to_int64(row[34]);
1074 mr->VolReadTime = str_to_int64(row[35]);
1075 mr->VolWriteTime = str_to_int64(row[36]);
1076 mr->ActionOnPurge = str_to_int32(row[37]);
1081 if (mr->MediaId != 0) {
1082 Mmsg1(mdb->errmsg, _("Media record MediaId=%s not found.\n"),
1083 edit_int64(mr->MediaId, ed1));
1085 Mmsg1(mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"),
1089 sql_free_result(mdb);
1091 if (mr->MediaId != 0) {
1092 Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"),
1095 Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"),
1103 * Find the last "accurate" backup state (that can take deleted files in
1105 * 1) Get all files with jobid in list (F subquery)
1106 * Get all files in BaseFiles with jobid in list
1107 * 2) Take only the last version of each file (Temp subquery) => accurate list
1109 * 3) Join the result to file table to get fileindex, jobid and lstat information
1111 * TODO: See if we can do the SORT only if needed (as an argument)
1113 bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
1114 DB_RESULT_HANDLER *result_handler, void *ctx)
1118 Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
1122 POOL_MEM buf(PM_MESSAGE);
1124 #define new_db_get_file_list
1125 #ifdef new_db_get_file_list
1126 POOL_MEM buf2(PM_MESSAGE);
1127 Mmsg(buf2, select_recent_version_with_basejob[db_type],
1128 jobids, jobids, jobids, jobids);
1130 "SELECT Path.Path, Filename.Name, Temp.FileIndex, Temp.JobId, LStat, MD5 "
1131 "FROM ( %s ) AS Temp "
1132 "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
1133 "JOIN Path ON (Path.PathId = Temp.PathId) "
1134 "WHERE FileIndex > 0 "
1135 "ORDER BY Temp.JobId, FileIndex ASC",/* Return sorted by JobId, */
1136 /* FileIndex for restore code */
1140 * I am not sure that this works the same as the code in ua_restore.c but it
1141 * is very similar. The accurate-test fails in a restore. Bad file count.
1143 Mmsg(buf, uar_sel_files, jobids);
1146 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1150 * This procedure gets the base jobid list used by jobids,
1152 bool db_get_used_base_jobids(JCR *jcr, B_DB *mdb,
1153 POOLMEM *jobids, db_list_ctx *result)
1157 "SELECT DISTINCT BaseJobId "
1158 " FROM Job JOIN BaseFiles USING (JobId) "
1159 " WHERE Job.HasBase = 1 "
1160 " AND Job.JobId IN (%s) ", jobids);
1161 return db_sql_query(mdb, buf.c_str(), db_list_handler, result);
1165 * The decision do change an incr/diff was done before
1167 * Differential : get the last full id
1168 * Incremental : get the last full + last diff + last incr(s) ids
1170 * If you specify jr->StartTime, it will be used to limit the search
1171 * in the time. (usually now)
1173 * TODO: look and merge from ua_restore.c
1175 bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
1176 JOB_DBR *jr, db_list_ctx *jobids)
1179 char clientid[50], jobid[50], filesetid[50];
1180 char date[MAX_TIME_LENGTH];
1181 POOL_MEM query(PM_FNAME);
1183 /* Take the current time as upper limit if nothing else specified */
1184 utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1186 bstrutime(date, sizeof(date), StartTime + 1);
1187 jobids->list[0] = 0;
1190 /* First, find the last good Full backup for this job/client/fileset */
1193 "CREATE TABLE btemp3%s AS "
1194 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1195 "FROM Job JOIN FileSet USING (FileSetId) "
1196 "WHERE ClientId = %s "
1197 "AND Level='F' AND JobStatus IN ('T','W') AND Type='B' "
1198 "AND StartTime<'%s' "
1199 "AND FileSet.FileSet=(SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1200 "ORDER BY Job.JobTDate DESC FETCH FIRST 1 ROW ONLY",
1201 edit_uint64(jcr->JobId, jobid),
1202 edit_uint64(jr->ClientId, clientid),
1204 edit_uint64(jr->FileSetId, filesetid));
1207 "CREATE TABLE btemp3%s AS "
1208 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1209 "FROM Job JOIN FileSet USING (FileSetId) "
1210 "WHERE ClientId = %s "
1211 "AND Level='F' AND JobStatus IN ('T','W') AND Type='B' "
1212 "AND StartTime<'%s' "
1213 "AND FileSet.FileSet=(SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1214 "ORDER BY Job.JobTDate DESC LIMIT 1",
1215 edit_uint64(jcr->JobId, jobid),
1216 edit_uint64(jr->ClientId, clientid),
1218 edit_uint64(jr->FileSetId, filesetid));
1221 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1225 if (jr->JobLevel == L_INCREMENTAL || jr->JobLevel == L_VIRTUAL_FULL) {
1226 /* Now, find the last differential backup after the last full */
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='D' 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 FETCH FIRST 1 ROW ONLY ",
1245 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1246 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1247 "FROM Job JOIN FileSet USING (FileSetId) "
1248 "WHERE ClientId = %s "
1249 "AND Level='D' AND JobStatus IN ('T','W') AND Type='B' "
1250 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1251 "AND StartTime < '%s' "
1252 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1253 "ORDER BY Job.JobTDate DESC LIMIT 1 ",
1261 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1265 /* We just have to take all incremental after the last Full/Diff */
1268 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1269 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1270 "FROM Job JOIN FileSet USING (FileSetId) "
1271 "WHERE ClientId = %s "
1272 "AND Level='I' AND JobStatus IN ('T','W') AND Type='B' "
1273 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC FETCH FIRST 1 ROW ONLY) "
1274 "AND StartTime < '%s' "
1275 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1276 "ORDER BY Job.JobTDate DESC ",
1284 "INSERT INTO btemp3%s (JobId, StartTime, EndTime, JobTDate, PurgedFiles) "
1285 "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
1286 "FROM Job JOIN FileSet USING (FileSetId) "
1287 "WHERE ClientId = %s "
1288 "AND Level='I' AND JobStatus IN ('T','W') AND Type='B' "
1289 "AND StartTime > (SELECT EndTime FROM btemp3%s ORDER BY EndTime DESC LIMIT 1) "
1290 "AND StartTime < '%s' "
1291 "AND FileSet.FileSet= (SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
1292 "ORDER BY Job.JobTDate DESC ",
1299 if (!db_sql_query(mdb, query.c_str(), NULL, NULL)) {
1304 /* build a jobid list ie: 1,2,3,4 */
1305 Mmsg(query, "SELECT JobId FROM btemp3%s ORDER by JobTDate", jobid);
1306 db_sql_query(mdb, query.c_str(), db_list_handler, jobids);
1307 Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids->list);
1311 Mmsg(query, "DROP TABLE btemp3%s", jobid);
1312 db_sql_query(mdb, query.c_str(), NULL, NULL);
1317 bool db_get_base_file_list(JCR *jcr, B_DB *mdb,
1318 DB_RESULT_HANDLER *result_handler, void *ctx)
1320 POOL_MEM buf(PM_MESSAGE);
1323 "SELECT Path, Name, FileIndex, JobId, LStat, MD5 "
1324 "FROM new_basefile%lld ORDER BY JobId, FileIndex ASC",
1325 (uint64_t) jcr->JobId);
1327 return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
1330 bool db_get_base_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr, JobId_t *jobid)
1332 POOL_MEM query(PM_FNAME);
1335 char date[MAX_TIME_LENGTH];
1339 // char clientid[50], filesetid[50];
1341 StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
1342 bstrutime(date, sizeof(date), StartTime + 1);
1344 /* we can take also client name, fileset, etc... */
1347 "SELECT JobId, Job, StartTime, EndTime, JobTDate, PurgedFiles "
1349 // "JOIN FileSet USING (FileSetId) JOIN Client USING (ClientId) "
1350 "WHERE Job.Name = '%s' "
1351 "AND Level='B' AND JobStatus IN ('T','W') AND Type='B' "
1352 // "AND FileSet.FileSet= '%s' "
1353 // "AND Client.Name = '%s' "
1354 "AND StartTime<'%s' "
1357 "ORDER BY Job.JobTDate DESC FETCH FIRST 1 ROW ONLY",
1359 "ORDER BY Job.JobTDate DESC LIMIT 1",
1361 // edit_uint64(jr->ClientId, clientid),
1362 // edit_uint64(jr->FileSetId, filesetid));
1365 Dmsg1(10, "db_get_base_jobid q=%s\n", query.c_str());
1366 if (!db_sql_query(mdb, query.c_str(), db_int64_handler, &lctx)) {
1369 *jobid = (JobId_t) lctx.value;
1371 Dmsg1(10, "db_get_base_jobid=%lld\n", *jobid);
1378 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */