2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula Catalog Database Update record interface routines
23 * Written by Kern Sibbald, March 2000
29 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
33 /* -----------------------------------------------------------------------
35 * Generic Routines (or almost generic)
37 * -----------------------------------------------------------------------
40 /* -----------------------------------------------------------------------
42 * Generic Routines (or almost generic)
44 * -----------------------------------------------------------------------
46 /* Update the attributes record by adding the file digest */
47 int BDB::bdb_add_digest_to_file_record(JCR *jcr, FileId_t FileId, char *digest,
52 int len = strlen(digest);
55 esc_name = check_pool_memory_size(esc_name, len*2+1);
56 bdb_escape_string(jcr, esc_name, digest, len);
57 Mmsg(cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", esc_name,
58 edit_int64(FileId, ed1));
59 ret = UpdateDB(jcr, cmd);
64 /* Mark the file record as being visited during database
65 * verify compare. Stuff JobId into the MarkId field
67 int BDB::bdb_mark_file_record(JCR *jcr, FileId_t FileId, JobId_t JobId)
70 char ed1[50], ed2[50];
73 Mmsg(cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s",
74 edit_int64(JobId, ed1), edit_int64(FileId, ed2));
75 stat = UpdateDB(jcr, cmd);
81 * Update the Job record at start of Job
83 * Returns: false on failure
86 bool BDB::bdb_update_job_start_record(JCR *jcr, JOB_DBR *jr)
88 char dt[MAX_TIME_LENGTH];
93 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
95 stime = jr->StartTime;
96 (void)localtime_r(&stime, &tm);
97 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
98 JobTDate = (btime_t)stime;
101 Mmsg(cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s',"
102 "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s",
103 (char)(jcr->JobStatus),
104 (char)(jr->JobLevel), dt,
105 edit_int64(jr->ClientId, ed1),
106 edit_uint64(JobTDate, ed2),
107 edit_int64(jr->PoolId, ed3),
108 edit_int64(jr->FileSetId, ed4),
109 edit_int64(jr->JobId, ed5));
111 stat = UpdateDB(jcr, cmd);
118 * Update Long term statistics with all jobs that were run before
121 int BDB::bdb_update_stats(JCR *jcr, utime_t age)
126 utime_t now = (utime_t)time(NULL);
127 edit_uint64(now - age, ed1);
131 Mmsg(cmd, fill_jobhisto, ed1);
132 QueryDB(jcr, cmd); /* TODO: get a message ? */
133 rows = sql_affected_rows();
141 * Update the Job record at end of Job
143 * Returns: 0 on failure
146 int BDB::bdb_update_job_end_record(JCR *jcr, JOB_DBR *jr)
148 char dt[MAX_TIME_LENGTH];
149 char rdt[MAX_TIME_LENGTH];
153 char ed1[30], ed2[30], ed3[50], ed4[50];
157 if (jr->PriorJobId) {
158 bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
160 bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
164 (void)localtime_r(&ttime, &tm);
165 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
167 if (jr->RealEndTime == 0 || jr->RealEndTime < jr->EndTime) {
168 jr->RealEndTime = jr->EndTime;
170 ttime = jr->RealEndTime;
171 (void)localtime_r(&ttime, &tm);
172 strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
178 "UPDATE Job SET JobStatus='%c',EndTime='%s',"
179 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
180 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
181 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
182 (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
183 edit_uint64(jr->ReadBytes, ed4),
184 jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
185 jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2),
186 rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
187 edit_int64(jr->JobId, ed3));
189 stat = UpdateDB(jcr, cmd);
196 * Update Client record
197 * Returns: 0 on failure
200 int BDB::bdb_update_client_record(JCR *jcr, CLIENT_DBR *cr)
203 char ed1[50], ed2[50];
204 char esc_name[MAX_ESCAPE_NAME_LENGTH];
205 char esc_uname[MAX_ESCAPE_NAME_LENGTH];
209 memcpy(&tcr, cr, sizeof(tcr));
210 if (!bdb_create_client_record(jcr, &tcr)) {
215 bdb_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
216 bdb_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
218 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
219 "Uname='%s' WHERE Name='%s'",
221 edit_uint64(cr->FileRetention, ed1),
222 edit_uint64(cr->JobRetention, ed2),
223 esc_uname, esc_name);
225 stat = UpdateDB(jcr, cmd);
232 * Update Counters record
233 * Returns: 0 on failure
236 int BDB::bdb_update_counter_record(JCR *jcr, COUNTER_DBR *cr)
238 char esc[MAX_ESCAPE_NAME_LENGTH];
241 bdb_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
242 Mmsg(cmd, update_counter_values[bdb_get_type_index()],
243 cr->MinValue, cr->MaxValue, cr->CurrentValue,
244 cr->WrapCounter, esc);
246 int stat = UpdateDB(jcr, cmd);
252 int BDB::bdb_update_pool_record(JCR *jcr, POOL_DBR *pr)
255 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
256 char esc[MAX_ESCAPE_NAME_LENGTH];
259 bdb_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
261 Mmsg(cmd, "SELECT count(*) from Media WHERE PoolId=%s",
262 edit_int64(pr->PoolId, ed4));
263 pr->NumVols = get_sql_record_max(jcr, this);
264 Dmsg1(400, "NumVols=%d\n", pr->NumVols);
267 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
268 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
269 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
270 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s,"
271 "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s",
272 pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
273 pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
274 edit_uint64(pr->VolUseDuration, ed2),
275 pr->MaxVolJobs, pr->MaxVolFiles,
276 edit_uint64(pr->MaxVolBytes, ed3),
277 pr->Recycle, pr->AutoPrune, pr->LabelType,
278 esc, edit_int64(pr->RecyclePoolId,ed5),
279 edit_int64(pr->ScratchPoolId,ed6),
282 stat = UpdateDB(jcr, cmd);
287 bool BDB::bdb_update_storage_record(JCR *jcr, STORAGE_DBR *sr)
293 Mmsg(cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
294 sr->AutoChanger, edit_int64(sr->StorageId, ed1));
296 stat = UpdateDB(jcr, cmd);
303 * Update the Media Record at end of Session
305 * Returns: 0 on failure
308 int BDB::bdb_update_media_record(JCR *jcr, MEDIA_DBR *mr)
310 char dt[MAX_TIME_LENGTH];
314 char ed1[50], ed2[50], ed3[50], ed4[50];
315 char ed5[50], ed6[50], ed7[50], ed8[50];
316 char ed9[50], ed10[50], ed11[50], ed12[50];
317 char ed13[50], ed14[50];
318 char esc_name[MAX_ESCAPE_NAME_LENGTH];
319 char esc_status[MAX_ESCAPE_NAME_LENGTH];
321 Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
323 bdb_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
324 bdb_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
326 if (mr->set_first_written) {
327 Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
328 ttime = mr->FirstWritten;
329 (void)localtime_r(&ttime, &tm);
330 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
331 Mmsg(cmd, "UPDATE Media SET FirstWritten='%s'"
332 " WHERE VolumeName='%s'", dt, esc_name);
333 stat = UpdateDB(jcr, cmd);
334 Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
337 /* Label just done? */
338 if (mr->set_label_date) {
339 ttime = mr->LabelDate;
343 (void)localtime_r(&ttime, &tm);
344 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
345 Mmsg(cmd, "UPDATE Media SET LabelDate='%s' "
346 "WHERE VolumeName='%s'", dt, esc_name);
350 if (mr->LastWritten != 0) {
351 ttime = mr->LastWritten;
352 (void)localtime_r(&ttime, &tm);
353 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
354 Mmsg(cmd, "UPDATE Media Set LastWritten='%s' "
355 "WHERE VolumeName='%s'", dt, esc_name);
359 /* sanity checks for #1066 */
360 if (mr->VolReadTime < 0) {
363 if (mr->VolWriteTime < 0) {
364 mr->VolWriteTime = 0;
367 Mmsg(cmd, "UPDATE Media SET VolJobs=%u,"
368 "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolABytes=%s,"
369 "VolHoleBytes=%s,VolHoles=%u,VolMounts=%u,VolErrors=%u,"
370 "VolWrites=%s,MaxVolBytes=%s,VolStatus='%s',"
371 "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
372 "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
373 "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
374 "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,"
376 " WHERE VolumeName='%s'",
377 mr->VolJobs, mr->VolFiles, mr->VolBlocks,
378 edit_uint64(mr->VolBytes, ed1),
379 edit_uint64(mr->VolABytes, ed2),
380 edit_uint64(mr->VolHoleBytes, ed3),
381 mr->VolHoles, mr->VolMounts, mr->VolErrors,
382 edit_uint64(mr->VolWrites, ed4),
383 edit_uint64(mr->MaxVolBytes, ed5),
384 esc_status, mr->Slot, mr->InChanger,
385 edit_int64(mr->VolReadTime, ed6),
386 edit_int64(mr->VolWriteTime, ed7),
387 mr->VolType, /* formerly VolParts */
389 edit_int64(mr->StorageId, ed8),
390 edit_int64(mr->PoolId, ed9),
391 edit_uint64(mr->VolRetention, ed10),
392 edit_uint64(mr->VolUseDuration, ed11),
393 mr->MaxVolJobs, mr->MaxVolFiles,
394 mr->Enabled, edit_uint64(mr->LocationId, ed12),
395 edit_uint64(mr->ScratchPoolId, ed13),
396 edit_uint64(mr->RecyclePoolId, ed14),
397 mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
400 Dmsg1(400, "%s\n", cmd);
402 stat = UpdateDB(jcr, cmd);
404 /* Make sure InChanger is 0 for any record having the same Slot */
405 db_make_inchanger_unique(jcr, this, mr);
412 * Update the Media Record Default values from Pool
414 * Returns: 0 on failure
417 int BDB::bdb_update_media_defaults(JCR *jcr, MEDIA_DBR *mr)
420 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
421 char esc[MAX_ESCAPE_NAME_LENGTH];
424 if (mr->VolumeName[0]) {
425 bdb_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
426 Mmsg(cmd, "UPDATE Media SET "
427 "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
428 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
429 " WHERE VolumeName='%s'",
430 mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
431 edit_uint64(mr->VolUseDuration, ed2),
432 mr->MaxVolJobs, mr->MaxVolFiles,
433 edit_uint64(mr->MaxVolBytes, ed3),
434 edit_uint64(mr->RecyclePoolId, ed4),
437 Mmsg(cmd, "UPDATE Media SET "
438 "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
439 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
441 mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
442 edit_uint64(mr->VolUseDuration, ed2),
443 mr->MaxVolJobs, mr->MaxVolFiles,
444 edit_uint64(mr->MaxVolBytes, ed3),
445 edit_int64(mr->RecyclePoolId, ed4),
446 edit_int64(mr->PoolId, ed5));
449 Dmsg1(400, "%s\n", cmd);
451 stat = UpdateDB(jcr, cmd);
459 * If we have a non-zero InChanger, ensure that no other Media
460 * record has InChanger set on the same Slot.
462 * This routine assumes the database is already locked.
464 void BDB::bdb_make_inchanger_unique(JCR *jcr, MEDIA_DBR *mr)
466 char ed1[50], ed2[50];
467 char esc[MAX_ESCAPE_NAME_LENGTH];
469 if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
470 if (mr->MediaId != 0) {
471 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
472 "Slot=%d AND StorageId=%s AND MediaId!=%s",
474 edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
476 } else if (*mr->VolumeName) {
477 bdb_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName));
478 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
479 "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
481 edit_int64(mr->StorageId, ed1), esc);
483 } else { /* used by ua_label to reset all volume with this slot */
484 Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
485 "Slot=%d AND StorageId=%s",
487 edit_int64(mr->StorageId, ed1), mr->VolumeName);
489 Dmsg1(100, "%s\n", cmd);
494 /* Update only Retention */
495 bool BDB::bdb_update_snapshot_record(JCR *jcr, SNAPSHOT_DBR *sr)
498 char ed1[50], ed2[50];
500 len = strlen(sr->Comment);
503 esc_name = check_pool_memory_size(esc_name, len*2+1);
504 bdb_escape_string(jcr, esc_name, sr->Comment, len);
506 Mmsg(cmd, "UPDATE Snapshot SET Retention=%s, Comment='%s' WHERE SnapshotId=%s",
507 edit_int64(sr->Retention, ed2), sr->Comment, edit_int64(sr->SnapshotId, ed1));
509 stat = UpdateDB(jcr, cmd);
514 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */