2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula Catalog Database Update record interface routines
22 * Written by Kern Sibbald, March 2000
28 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
35 /* -----------------------------------------------------------------------
37 * Generic Routines (or almost generic)
39 * -----------------------------------------------------------------------
42 /* -----------------------------------------------------------------------
44 * Generic Routines (or almost generic)
46 * -----------------------------------------------------------------------
48 /* Update the attributes record by adding the file digest */
49 int BDB::bdb_add_digest_to_file_record(JCR *jcr, FileId_t FileId, char *digest,
54 int len = strlen(digest);
57 esc_name = check_pool_memory_size(esc_name, len*2+1);
58 bdb_escape_string(jcr, esc_name, digest, len);
59 Mmsg(cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", esc_name,
60 edit_int64(FileId, ed1));
61 ret = UpdateDB(jcr, cmd, false);
66 /* Mark the file record as being visited during database
67 * verify compare. Stuff JobId into the MarkId field
69 int BDB::bdb_mark_file_record(JCR *jcr, FileId_t FileId, JobId_t JobId)
72 char ed1[50], ed2[50];
75 Mmsg(cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s",
76 edit_int64(JobId, ed1), edit_int64(FileId, ed2));
77 stat = UpdateDB(jcr, cmd, false);
83 * Update the Job record at start of Job
85 * Returns: false on failure
88 bool BDB::bdb_update_job_start_record(JCR *jcr, JOB_DBR *jr)
90 char dt[MAX_TIME_LENGTH];
95 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
97 stime = jr->StartTime;
98 (void)localtime_r(&stime, &tm);
99 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
100 JobTDate = (btime_t)stime;
103 Mmsg(cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s',"
104 "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s",
105 (char)(jcr->JobStatus),
106 (char)(jr->JobLevel), dt,
107 edit_int64(jr->ClientId, ed1),
108 edit_uint64(JobTDate, ed2),
109 edit_int64(jr->PoolId, ed3),
110 edit_int64(jr->FileSetId, ed4),
111 edit_int64(jr->JobId, ed5));
113 stat = UpdateDB(jcr, cmd, false);
120 * Update Long term statistics with all jobs that were run before
123 int BDB::bdb_update_stats(JCR *jcr, utime_t age)
128 utime_t now = (utime_t)time(NULL);
129 edit_uint64(now - age, ed1);
133 Mmsg(cmd, fill_jobhisto, ed1);
134 QueryDB(jcr, cmd); /* TODO: get a message ? */
135 rows = sql_affected_rows();
143 * Update the Job record at end of Job
145 * Returns: 0 on failure
148 int BDB::bdb_update_job_end_record(JCR *jcr, JOB_DBR *jr)
150 char dt[MAX_TIME_LENGTH];
151 char rdt[MAX_TIME_LENGTH];
155 char ed1[30], ed2[30], ed3[50], ed4[50];
159 if (jr->PriorJobId) {
160 bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
162 bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
166 (void)localtime_r(&ttime, &tm);
167 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
169 if (jr->RealEndTime == 0 || jr->RealEndTime < jr->EndTime) {
170 jr->RealEndTime = jr->EndTime;
172 ttime = jr->RealEndTime;
173 (void)localtime_r(&ttime, &tm);
174 strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
180 "UPDATE Job SET JobStatus='%c',EndTime='%s',"
181 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
182 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
183 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
184 (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
185 edit_uint64(jr->ReadBytes, ed4),
186 jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
187 jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2),
188 rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
189 edit_int64(jr->JobId, ed3));
191 stat = UpdateDB(jcr, cmd, false);
198 * Update Client record
199 * Returns: 0 on failure
202 int BDB::bdb_update_client_record(JCR *jcr, CLIENT_DBR *cr)
205 char ed1[50], ed2[50];
206 char esc_name[MAX_ESCAPE_NAME_LENGTH];
207 char esc_uname[MAX_ESCAPE_NAME_LENGTH];
211 memcpy(&tcr, cr, sizeof(tcr));
212 if (!bdb_create_client_record(jcr, &tcr)) {
217 bdb_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
218 bdb_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
220 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
221 "Uname='%s' WHERE Name='%s'",
223 edit_uint64(cr->FileRetention, ed1),
224 edit_uint64(cr->JobRetention, ed2),
225 esc_uname, esc_name);
227 stat = UpdateDB(jcr, cmd, false);
234 * Update Counters record
235 * Returns: 0 on failure
238 int BDB::bdb_update_counter_record(JCR *jcr, COUNTER_DBR *cr)
240 char esc[MAX_ESCAPE_NAME_LENGTH];
243 bdb_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
244 Mmsg(cmd, update_counter_values[bdb_get_type_index()],
245 cr->MinValue, cr->MaxValue, cr->CurrentValue,
246 cr->WrapCounter, esc);
248 int stat = UpdateDB(jcr, cmd, false);
254 int BDB::bdb_update_pool_record(JCR *jcr, POOL_DBR *pr)
257 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
258 char esc[MAX_ESCAPE_NAME_LENGTH];
261 bdb_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
263 Mmsg(cmd, "SELECT count(*) from Media WHERE PoolId=%s",
264 edit_int64(pr->PoolId, ed4));
265 pr->NumVols = get_sql_record_max(jcr, this);
266 Dmsg1(dbglevel2, "NumVols=%d\n", pr->NumVols);
269 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
270 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
271 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
272 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s,"
273 "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s",
274 pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
275 pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
276 edit_uint64(pr->VolUseDuration, ed2),
277 pr->MaxVolJobs, pr->MaxVolFiles,
278 edit_uint64(pr->MaxVolBytes, ed3),
279 pr->Recycle, pr->AutoPrune, pr->LabelType,
280 esc, edit_int64(pr->RecyclePoolId,ed5),
281 edit_int64(pr->ScratchPoolId,ed6),
284 stat = UpdateDB(jcr, cmd, false);
289 bool BDB::bdb_update_storage_record(JCR *jcr, STORAGE_DBR *sr)
295 Mmsg(cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
296 sr->AutoChanger, edit_int64(sr->StorageId, ed1));
298 stat = UpdateDB(jcr, cmd, false);
305 * Update the Media Record at end of Session
307 * Returns: 0 on failure
310 int BDB::bdb_update_media_record(JCR *jcr, MEDIA_DBR *mr)
312 char dt[MAX_TIME_LENGTH];
316 char ed1[50], ed2[50], ed3[50], ed4[50];
317 char ed5[50], ed6[50], ed7[50], ed8[50];
318 char ed9[50], ed10[50], ed11[50], ed12[50];
319 char ed13[50], ed14[50];
320 char esc_name[MAX_ESCAPE_NAME_LENGTH];
321 char esc_status[MAX_ESCAPE_NAME_LENGTH];
323 Dmsg1(dbglevel1, "update_media: FirstWritten=%d\n", mr->FirstWritten);
325 bdb_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
326 bdb_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
328 if (mr->set_first_written) {
329 Dmsg1(dbglevel2, "Set FirstWritten Vol=%s\n", mr->VolumeName);
330 ttime = mr->FirstWritten;
331 (void)localtime_r(&ttime, &tm);
332 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
333 Mmsg(cmd, "UPDATE Media SET FirstWritten='%s'"
334 " WHERE VolumeName='%s'", dt, esc_name);
335 stat = UpdateDB(jcr, cmd, false);
336 Dmsg1(dbglevel2, "Firstwritten=%d\n", mr->FirstWritten);
339 /* Label just done? */
340 if (mr->set_label_date) {
341 ttime = mr->LabelDate;
345 (void)localtime_r(&ttime, &tm);
346 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
347 Mmsg(cmd, "UPDATE Media SET LabelDate='%s' "
348 "WHERE VolumeName='%s'", dt, esc_name);
349 UpdateDB(jcr, cmd, false);
352 if (mr->LastWritten != 0) {
353 ttime = mr->LastWritten;
354 (void)localtime_r(&ttime, &tm);
355 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
356 Mmsg(cmd, "UPDATE Media Set LastWritten='%s' "
357 "WHERE VolumeName='%s'", dt, esc_name);
358 UpdateDB(jcr, cmd, false);
361 /* sanity checks for #1066 */
362 if (mr->VolReadTime < 0) {
365 if (mr->VolWriteTime < 0) {
366 mr->VolWriteTime = 0;
369 Mmsg(cmd, "UPDATE Media SET VolJobs=%u,"
370 "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolABytes=%s,"
371 "VolHoleBytes=%s,VolHoles=%u,VolMounts=%u,VolErrors=%u,"
372 "VolWrites=%s,MaxVolBytes=%s,VolStatus='%s',"
373 "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
374 "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
375 "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
376 "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,"
378 " WHERE VolumeName='%s'",
379 mr->VolJobs, mr->VolFiles, mr->VolBlocks,
380 edit_uint64(mr->VolBytes, ed1),
381 edit_uint64(mr->VolABytes, ed2),
382 edit_uint64(mr->VolHoleBytes, ed3),
383 mr->VolHoles, mr->VolMounts, mr->VolErrors,
384 edit_uint64(mr->VolWrites, ed4),
385 edit_uint64(mr->MaxVolBytes, ed5),
386 esc_status, mr->Slot, mr->InChanger,
387 edit_int64(mr->VolReadTime, ed6),
388 edit_int64(mr->VolWriteTime, ed7),
389 mr->VolType, /* formerly VolParts */
391 edit_int64(mr->StorageId, ed8),
392 edit_int64(mr->PoolId, ed9),
393 edit_uint64(mr->VolRetention, ed10),
394 edit_uint64(mr->VolUseDuration, ed11),
395 mr->MaxVolJobs, mr->MaxVolFiles,
396 mr->Enabled, edit_uint64(mr->LocationId, ed12),
397 edit_uint64(mr->ScratchPoolId, ed13),
398 edit_uint64(mr->RecyclePoolId, ed14),
399 mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
402 Dmsg1(dbglevel1, "%s\n", cmd);
404 stat = UpdateDB(jcr, cmd, false);
406 /* Make sure InChanger is 0 for any record having the same Slot */
407 db_make_inchanger_unique(jcr, this, mr);
414 * Update the Media Record Default values from Pool
416 * Returns: 0 on failure
419 int BDB::bdb_update_media_defaults(JCR *jcr, MEDIA_DBR *mr)
422 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
423 char esc[MAX_ESCAPE_NAME_LENGTH];
427 if (mr->VolumeName[0]) {
428 bdb_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
429 Mmsg(cmd, "UPDATE Media SET "
430 "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
431 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
432 " WHERE VolumeName='%s'",
433 mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
434 edit_uint64(mr->VolUseDuration, ed2),
435 mr->MaxVolJobs, mr->MaxVolFiles,
436 edit_uint64(mr->MaxVolBytes, ed3),
437 edit_uint64(mr->RecyclePoolId, ed4),
439 can_be_empty = false;
442 Mmsg(cmd, "UPDATE Media SET "
443 "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
444 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
446 mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
447 edit_uint64(mr->VolUseDuration, ed2),
448 mr->MaxVolJobs, mr->MaxVolFiles,
449 edit_uint64(mr->MaxVolBytes, ed3),
450 edit_int64(mr->RecyclePoolId, ed4),
451 edit_int64(mr->PoolId, ed5));
455 Dmsg1(dbglevel1, "%s\n", cmd);
457 stat = UpdateDB(jcr, cmd, can_be_empty);
465 * If we have a non-zero InChanger, ensure that no other Media
466 * record has InChanger set on the same Slot.
468 * This routine assumes the database is already locked.
470 void BDB::bdb_make_inchanger_unique(JCR *jcr, MEDIA_DBR *mr)
472 char ed1[50], ed2[50];
473 char esc[MAX_ESCAPE_NAME_LENGTH];
475 if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
476 if (mr->MediaId != 0) {
477 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
478 "Slot=%d AND StorageId=%s AND MediaId!=%s",
480 edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
482 } else if (*mr->VolumeName) {
483 bdb_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName));
484 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
485 "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
487 edit_int64(mr->StorageId, ed1), esc);
489 } else { /* used by ua_label to reset all volume with this slot */
490 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
491 "Slot=%d AND StorageId=%s",
493 edit_int64(mr->StorageId, ed1), mr->VolumeName);
495 Dmsg1(dbglevel1, "%s\n", cmd);
496 UpdateDB(jcr, cmd, true);
500 /* Update only Retention */
501 bool BDB::bdb_update_snapshot_record(JCR *jcr, SNAPSHOT_DBR *sr)
504 char ed1[50], ed2[50];
506 len = strlen(sr->Comment);
509 esc_name = check_pool_memory_size(esc_name, len*2+1);
510 bdb_escape_string(jcr, esc_name, sr->Comment, len);
512 Mmsg(cmd, "UPDATE Snapshot SET Retention=%s, Comment='%s' WHERE SnapshotId=%s",
513 edit_int64(sr->Retention, ed2), sr->Comment, edit_int64(sr->SnapshotId, ed1));
515 stat = UpdateDB(jcr, cmd, false);
520 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */