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
32 /* -----------------------------------------------------------------------
34 * Generic Routines (or almost generic)
36 * -----------------------------------------------------------------------
39 /* -----------------------------------------------------------------------
41 * Generic Routines (or almost generic)
43 * -----------------------------------------------------------------------
45 /* Update the attributes record by adding the file digest */
46 int BDB::bdb_add_digest_to_file_record(JCR *jcr, FileId_t FileId, char *digest,
51 int len = strlen(digest);
54 esc_name = check_pool_memory_size(esc_name, len*2+1);
55 bdb_escape_string(jcr, esc_name, digest, len);
56 Mmsg(cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", esc_name,
57 edit_int64(FileId, ed1));
58 ret = UpdateDB(jcr, cmd);
63 /* Mark the file record as being visited during database
64 * verify compare. Stuff JobId into the MarkId field
66 int BDB::bdb_mark_file_record(JCR *jcr, FileId_t FileId, JobId_t JobId)
69 char ed1[50], ed2[50];
72 Mmsg(cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s",
73 edit_int64(JobId, ed1), edit_int64(FileId, ed2));
74 stat = UpdateDB(jcr, cmd);
80 * Update the Job record at start of Job
82 * Returns: false on failure
85 bool BDB::bdb_update_job_start_record(JCR *jcr, JOB_DBR *jr)
87 char dt[MAX_TIME_LENGTH];
92 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
94 stime = jr->StartTime;
95 (void)localtime_r(&stime, &tm);
96 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
97 JobTDate = (btime_t)stime;
100 Mmsg(cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s',"
101 "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s",
102 (char)(jcr->JobStatus),
103 (char)(jr->JobLevel), dt,
104 edit_int64(jr->ClientId, ed1),
105 edit_uint64(JobTDate, ed2),
106 edit_int64(jr->PoolId, ed3),
107 edit_int64(jr->FileSetId, ed4),
108 edit_int64(jr->JobId, ed5));
110 stat = UpdateDB(jcr, cmd);
117 * Update Long term statistics with all jobs that were run before
120 int BDB::bdb_update_stats(JCR *jcr, utime_t age)
125 utime_t now = (utime_t)time(NULL);
126 edit_uint64(now - age, ed1);
130 Mmsg(cmd, fill_jobhisto, ed1);
131 QueryDB(jcr, cmd); /* TODO: get a message ? */
132 rows = sql_affected_rows();
140 * Update the Job record at end of Job
142 * Returns: 0 on failure
145 int BDB::bdb_update_job_end_record(JCR *jcr, JOB_DBR *jr)
147 char dt[MAX_TIME_LENGTH];
148 char rdt[MAX_TIME_LENGTH];
152 char ed1[30], ed2[30], ed3[50], ed4[50];
156 if (jr->PriorJobId) {
157 bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
159 bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
163 (void)localtime_r(&ttime, &tm);
164 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
166 if (jr->RealEndTime == 0 || jr->RealEndTime < jr->EndTime) {
167 jr->RealEndTime = jr->EndTime;
169 ttime = jr->RealEndTime;
170 (void)localtime_r(&ttime, &tm);
171 strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
177 "UPDATE Job SET JobStatus='%c',EndTime='%s',"
178 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
179 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
180 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
181 (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
182 edit_uint64(jr->ReadBytes, ed4),
183 jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
184 jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2),
185 rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
186 edit_int64(jr->JobId, ed3));
188 stat = UpdateDB(jcr, cmd);
195 * Update Client record
196 * Returns: 0 on failure
199 int BDB::bdb_update_client_record(JCR *jcr, CLIENT_DBR *cr)
202 char ed1[50], ed2[50];
203 char esc_name[MAX_ESCAPE_NAME_LENGTH];
204 char esc_uname[MAX_ESCAPE_NAME_LENGTH];
208 memcpy(&tcr, cr, sizeof(tcr));
209 if (!bdb_create_client_record(jcr, &tcr)) {
214 bdb_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
215 bdb_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
217 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
218 "Uname='%s' WHERE Name='%s'",
220 edit_uint64(cr->FileRetention, ed1),
221 edit_uint64(cr->JobRetention, ed2),
222 esc_uname, esc_name);
224 stat = UpdateDB(jcr, cmd);
231 * Update Counters record
232 * Returns: 0 on failure
235 int BDB::bdb_update_counter_record(JCR *jcr, COUNTER_DBR *cr)
237 char esc[MAX_ESCAPE_NAME_LENGTH];
240 bdb_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
241 Mmsg(cmd, update_counter_values[bdb_get_type_index()],
242 cr->MinValue, cr->MaxValue, cr->CurrentValue,
243 cr->WrapCounter, esc);
245 int stat = UpdateDB(jcr, cmd);
251 int BDB::bdb_update_pool_record(JCR *jcr, POOL_DBR *pr)
254 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
255 char esc[MAX_ESCAPE_NAME_LENGTH];
258 bdb_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
260 Mmsg(cmd, "SELECT count(*) from Media WHERE PoolId=%s",
261 edit_int64(pr->PoolId, ed4));
262 pr->NumVols = get_sql_record_max(jcr, this);
263 Dmsg1(400, "NumVols=%d\n", pr->NumVols);
266 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
267 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
268 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
269 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s,"
270 "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s",
271 pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
272 pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
273 edit_uint64(pr->VolUseDuration, ed2),
274 pr->MaxVolJobs, pr->MaxVolFiles,
275 edit_uint64(pr->MaxVolBytes, ed3),
276 pr->Recycle, pr->AutoPrune, pr->LabelType,
277 esc, edit_int64(pr->RecyclePoolId,ed5),
278 edit_int64(pr->ScratchPoolId,ed6),
281 stat = UpdateDB(jcr, cmd);
286 bool BDB::bdb_update_storage_record(JCR *jcr, STORAGE_DBR *sr)
292 Mmsg(cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
293 sr->AutoChanger, edit_int64(sr->StorageId, ed1));
295 stat = UpdateDB(jcr, cmd);
302 * Update the Media Record at end of Session
304 * Returns: 0 on failure
307 int BDB::bdb_update_media_record(JCR *jcr, MEDIA_DBR *mr)
309 char dt[MAX_TIME_LENGTH];
313 char ed1[50], ed2[50], ed3[50], ed4[50];
314 char ed5[50], ed6[50], ed7[50], ed8[50];
315 char ed9[50], ed10[50], ed11[50], ed12[50];
316 char ed13[50], ed14[50];
317 char esc_name[MAX_ESCAPE_NAME_LENGTH];
318 char esc_status[MAX_ESCAPE_NAME_LENGTH];
320 Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
322 bdb_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
323 bdb_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
325 if (mr->set_first_written) {
326 Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
327 ttime = mr->FirstWritten;
328 (void)localtime_r(&ttime, &tm);
329 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
330 Mmsg(cmd, "UPDATE Media SET FirstWritten='%s'"
331 " WHERE VolumeName='%s'", dt, esc_name);
332 stat = UpdateDB(jcr, cmd);
333 Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
336 /* Label just done? */
337 if (mr->set_label_date) {
338 ttime = mr->LabelDate;
342 (void)localtime_r(&ttime, &tm);
343 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
344 Mmsg(cmd, "UPDATE Media SET LabelDate='%s' "
345 "WHERE VolumeName='%s'", dt, esc_name);
349 if (mr->LastWritten != 0) {
350 ttime = mr->LastWritten;
351 (void)localtime_r(&ttime, &tm);
352 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
353 Mmsg(cmd, "UPDATE Media Set LastWritten='%s' "
354 "WHERE VolumeName='%s'", dt, esc_name);
358 /* sanity checks for #1066 */
359 if (mr->VolReadTime < 0) {
362 if (mr->VolWriteTime < 0) {
363 mr->VolWriteTime = 0;
366 Mmsg(cmd, "UPDATE Media SET VolJobs=%u,"
367 "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolABytes=%s,"
368 "VolHoleBytes=%s,VolHoles=%u,VolMounts=%u,VolErrors=%u,"
369 "VolWrites=%s,MaxVolBytes=%s,VolStatus='%s',"
370 "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
371 "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
372 "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
373 "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,"
375 " WHERE VolumeName='%s'",
376 mr->VolJobs, mr->VolFiles, mr->VolBlocks,
377 edit_uint64(mr->VolBytes, ed1),
378 edit_uint64(mr->VolABytes, ed2),
379 edit_uint64(mr->VolHoleBytes, ed3),
380 mr->VolHoles, mr->VolMounts, mr->VolErrors,
381 edit_uint64(mr->VolWrites, ed4),
382 edit_uint64(mr->MaxVolBytes, ed5),
383 esc_status, mr->Slot, mr->InChanger,
384 edit_int64(mr->VolReadTime, ed6),
385 edit_int64(mr->VolWriteTime, ed7),
386 mr->VolType, /* formerly VolParts */
388 edit_int64(mr->StorageId, ed8),
389 edit_int64(mr->PoolId, ed9),
390 edit_uint64(mr->VolRetention, ed10),
391 edit_uint64(mr->VolUseDuration, ed11),
392 mr->MaxVolJobs, mr->MaxVolFiles,
393 mr->Enabled, edit_uint64(mr->LocationId, ed12),
394 edit_uint64(mr->ScratchPoolId, ed13),
395 edit_uint64(mr->RecyclePoolId, ed14),
396 mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
399 Dmsg1(400, "%s\n", cmd);
401 stat = UpdateDB(jcr, cmd);
403 /* Make sure InChanger is 0 for any record having the same Slot */
404 db_make_inchanger_unique(jcr, this, mr);
411 * Update the Media Record Default values from Pool
413 * Returns: 0 on failure
416 int BDB::bdb_update_media_defaults(JCR *jcr, MEDIA_DBR *mr)
419 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
420 char esc[MAX_ESCAPE_NAME_LENGTH];
423 if (mr->VolumeName[0]) {
424 bdb_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
425 Mmsg(cmd, "UPDATE Media SET "
426 "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
427 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
428 " WHERE VolumeName='%s'",
429 mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
430 edit_uint64(mr->VolUseDuration, ed2),
431 mr->MaxVolJobs, mr->MaxVolFiles,
432 edit_uint64(mr->MaxVolBytes, ed3),
433 edit_uint64(mr->RecyclePoolId, ed4),
436 Mmsg(cmd, "UPDATE Media SET "
437 "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
438 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
440 mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
441 edit_uint64(mr->VolUseDuration, ed2),
442 mr->MaxVolJobs, mr->MaxVolFiles,
443 edit_uint64(mr->MaxVolBytes, ed3),
444 edit_int64(mr->RecyclePoolId, ed4),
445 edit_int64(mr->PoolId, ed5));
448 Dmsg1(400, "%s\n", cmd);
450 stat = UpdateDB(jcr, cmd);
458 * If we have a non-zero InChanger, ensure that no other Media
459 * record has InChanger set on the same Slot.
461 * This routine assumes the database is already locked.
463 void BDB::bdb_make_inchanger_unique(JCR *jcr, MEDIA_DBR *mr)
465 char ed1[50], ed2[50];
466 char esc[MAX_ESCAPE_NAME_LENGTH];
468 if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
469 if (mr->MediaId != 0) {
470 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
471 "Slot=%d AND StorageId=%s AND MediaId!=%s",
473 edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
475 } else if (*mr->VolumeName) {
476 bdb_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName));
477 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
478 "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
480 edit_int64(mr->StorageId, ed1), esc);
482 } else { /* used by ua_label to reset all volume with this slot */
483 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
484 "Slot=%d AND StorageId=%s",
486 edit_int64(mr->StorageId, ed1), mr->VolumeName);
488 Dmsg1(100, "%s\n", cmd);
493 /* Update only Retention */
494 bool BDB::bdb_update_snapshot_record(JCR *jcr, SNAPSHOT_DBR *sr)
497 char ed1[50], ed2[50];
499 len = strlen(sr->Comment);
502 esc_name = check_pool_memory_size(esc_name, len*2+1);
503 bdb_escape_string(jcr, esc_name, sr->Comment, len);
505 Mmsg(cmd, "UPDATE Snapshot SET Retention=%s, Comment='%s' WHERE SnapshotId=%s",
506 edit_int64(sr->Retention, ed2), sr->Comment, edit_int64(sr->SnapshotId, ed1));
508 stat = UpdateDB(jcr, cmd);
513 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */