2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2012 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 three of the GNU Affero 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 Affero 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 Update record interface routines
31 * Kern Sibbald, March 2000
37 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
43 /* -----------------------------------------------------------------------
45 * Generic Routines (or almost generic)
47 * -----------------------------------------------------------------------
50 /* -----------------------------------------------------------------------
52 * Generic Routines (or almost generic)
54 * -----------------------------------------------------------------------
56 /* Update the attributes record by adding the file digest */
58 db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest,
63 int len = strlen(digest);
66 mdb->esc_name = check_pool_memory_size(mdb->esc_name, len*2+1);
67 mdb->db_escape_string(jcr, mdb->esc_name, digest, len);
68 Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", mdb->esc_name,
69 edit_int64(FileId, ed1));
70 ret = UPDATE_DB(jcr, mdb, mdb->cmd);
75 /* Mark the file record as being visited during database
76 * verify compare. Stuff JobId into the MarkId field
78 int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId)
81 char ed1[50], ed2[50];
84 Mmsg(mdb->cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s",
85 edit_int64(JobId, ed1), edit_int64(FileId, ed2));
86 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
92 * Update the Job record at start of Job
94 * Returns: false on failure
98 db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
100 char dt[MAX_TIME_LENGTH];
105 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
107 stime = jr->StartTime;
108 (void)localtime_r(&stime, &tm);
109 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
110 JobTDate = (btime_t)stime;
113 Mmsg(mdb->cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s',"
114 "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s",
115 (char)(jcr->JobStatus),
116 (char)(jr->JobLevel), dt,
117 edit_int64(jr->ClientId, ed1),
118 edit_uint64(JobTDate, ed2),
119 edit_int64(jr->PoolId, ed3),
120 edit_int64(jr->FileSetId, ed4),
121 edit_int64(jr->JobId, ed5));
123 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
130 * Update Long term statistics with all jobs that were run before
134 db_update_stats(JCR *jcr, B_DB *mdb, utime_t age)
138 utime_t now = (utime_t)time(NULL);
139 edit_uint64(now - age, ed1);
143 Mmsg(mdb->cmd, fill_jobhisto, ed1);
144 QUERY_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
145 rows = sql_affected_rows(mdb);
153 * Update the Job record at end of Job
155 * Returns: 0 on failure
159 db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
161 char dt[MAX_TIME_LENGTH];
162 char rdt[MAX_TIME_LENGTH];
166 char ed1[30], ed2[30], ed3[50], ed4[50];
170 if (jr->PriorJobId) {
171 bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
173 bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
177 (void)localtime_r(&ttime, &tm);
178 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
180 if (jr->RealEndTime == 0) {
181 jr->RealEndTime = jr->EndTime;
183 ttime = jr->RealEndTime;
184 (void)localtime_r(&ttime, &tm);
185 strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
191 "UPDATE Job SET JobStatus='%c',EndTime='%s',"
192 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
193 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
194 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
195 (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
196 edit_uint64(jr->ReadBytes, ed4),
197 jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
198 jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2),
199 rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
200 edit_int64(jr->JobId, ed3));
202 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
209 * Update Client record
210 * Returns: 0 on failure
214 db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
217 char ed1[50], ed2[50];
218 char esc_name[MAX_ESCAPE_NAME_LENGTH];
219 char esc_uname[MAX_ESCAPE_NAME_LENGTH];
223 memcpy(&tcr, cr, sizeof(tcr));
224 if (!db_create_client_record(jcr, mdb, &tcr)) {
229 mdb->db_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
230 mdb->db_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
232 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
233 "Uname='%s' WHERE Name='%s'",
235 edit_uint64(cr->FileRetention, ed1),
236 edit_uint64(cr->JobRetention, ed2),
237 esc_uname, esc_name);
239 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
246 * Update Counters record
247 * Returns: 0 on failure
250 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
252 char esc[MAX_ESCAPE_NAME_LENGTH];
254 mdb->db_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
256 "UPDATE Counters SET Counters.MinValue=%d,Counters.MaxValue=%d,CurrentValue=%d,"
257 "WrapCounter='%s' WHERE Counter='%s'",
258 cr->MinValue, cr->MaxValue, cr->CurrentValue,
259 cr->WrapCounter, esc);
261 int stat = UPDATE_DB(jcr, mdb, mdb->cmd);
267 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
270 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
271 char esc[MAX_ESCAPE_NAME_LENGTH];
274 mdb->db_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
276 Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
277 edit_int64(pr->PoolId, ed4));
278 pr->NumVols = get_sql_record_max(jcr, mdb);
279 Dmsg1(400, "NumVols=%d\n", pr->NumVols);
282 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
283 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
284 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
285 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s,"
286 "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s",
287 pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
288 pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
289 edit_uint64(pr->VolUseDuration, ed2),
290 pr->MaxVolJobs, pr->MaxVolFiles,
291 edit_uint64(pr->MaxVolBytes, ed3),
292 pr->Recycle, pr->AutoPrune, pr->LabelType,
293 esc, edit_int64(pr->RecyclePoolId,ed5),
294 edit_int64(pr->ScratchPoolId,ed6),
297 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
303 db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
308 Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
309 sr->AutoChanger, edit_int64(sr->StorageId, ed1));
311 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
318 * Update the Media Record at end of Session
320 * Returns: 0 on failure
324 db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
326 char dt[MAX_TIME_LENGTH];
330 char ed1[50], ed2[50], ed3[50], ed4[50];
331 char ed5[50], ed6[50], ed7[50], ed8[50];
332 char ed9[50], ed10[50], ed11[50];
333 char esc_name[MAX_ESCAPE_NAME_LENGTH];
334 char esc_status[MAX_ESCAPE_NAME_LENGTH];
336 Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
338 mdb->db_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
339 mdb->db_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
341 if (mr->set_first_written) {
342 Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
343 ttime = mr->FirstWritten;
344 (void)localtime_r(&ttime, &tm);
345 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
346 Mmsg(mdb->cmd, "UPDATE Media SET FirstWritten='%s'"
347 " WHERE VolumeName='%s'", dt, esc_name);
348 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
349 Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
352 /* Label just done? */
353 if (mr->set_label_date) {
354 ttime = mr->LabelDate;
358 (void)localtime_r(&ttime, &tm);
359 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
360 Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
361 "WHERE VolumeName='%s'", dt, esc_name);
362 UPDATE_DB(jcr, mdb, mdb->cmd);
365 if (mr->LastWritten != 0) {
366 ttime = mr->LastWritten;
367 (void)localtime_r(&ttime, &tm);
368 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
369 Mmsg(mdb->cmd, "UPDATE Media Set LastWritten='%s' "
370 "WHERE VolumeName='%s'", dt, esc_name);
371 UPDATE_DB(jcr, mdb, mdb->cmd);
374 /* sanity checks for #1066 */
375 if (mr->VolReadTime < 0) {
378 if (mr->VolWriteTime < 0) {
379 mr->VolWriteTime = 0;
382 Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
383 "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
384 "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
385 "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
386 "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
387 "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
388 "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,ActionOnPurge=%d"
389 " WHERE VolumeName='%s'",
390 mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
391 mr->VolMounts, mr->VolErrors, mr->VolWrites,
392 edit_uint64(mr->MaxVolBytes, ed2),
393 esc_status, mr->Slot, mr->InChanger,
394 edit_int64(mr->VolReadTime, ed3),
395 edit_int64(mr->VolWriteTime, ed4),
398 edit_int64(mr->StorageId, ed5),
399 edit_int64(mr->PoolId, ed6),
400 edit_uint64(mr->VolRetention, ed7),
401 edit_uint64(mr->VolUseDuration, ed8),
402 mr->MaxVolJobs, mr->MaxVolFiles,
403 mr->Enabled, edit_uint64(mr->LocationId, ed9),
404 edit_uint64(mr->ScratchPoolId, ed10),
405 edit_uint64(mr->RecyclePoolId, ed11),
406 mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
409 Dmsg1(400, "%s\n", mdb->cmd);
411 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
413 /* Make sure InChanger is 0 for any record having the same Slot */
414 db_make_inchanger_unique(jcr, mdb, mr);
421 * Update the Media Record Default values from Pool
423 * Returns: 0 on failure
427 db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
430 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
431 char esc[MAX_ESCAPE_NAME_LENGTH];
434 if (mr->VolumeName[0]) {
435 mdb->db_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
436 Mmsg(mdb->cmd, "UPDATE Media SET "
437 "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
438 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
439 " WHERE VolumeName='%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_uint64(mr->RecyclePoolId, ed4),
447 Mmsg(mdb->cmd, "UPDATE Media SET "
448 "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
449 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
451 mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
452 edit_uint64(mr->VolUseDuration, ed2),
453 mr->MaxVolJobs, mr->MaxVolFiles,
454 edit_uint64(mr->MaxVolBytes, ed3),
455 edit_int64(mr->RecyclePoolId, ed4),
456 edit_int64(mr->PoolId, ed5));
459 Dmsg1(400, "%s\n", mdb->cmd);
461 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
469 * If we have a non-zero InChanger, ensure that no other Media
470 * record has InChanger set on the same Slot.
472 * This routine assumes the database is already locked.
475 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
477 char ed1[50], ed2[50];
478 char esc[MAX_ESCAPE_NAME_LENGTH];
479 if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
481 if (mr->MediaId != 0) {
482 Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
483 "Slot=%d AND StorageId=%s AND MediaId!=%s",
485 edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
487 } else if (*mr->VolumeName) {
488 mdb->db_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName));
489 Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
490 "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
492 edit_int64(mr->StorageId, ed1), esc);
494 } else { /* used by ua_label to reset all volume with this slot */
495 Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
496 "Slot=%d AND StorageId=%s",
498 edit_int64(mr->StorageId, ed1), mr->VolumeName);
500 Dmsg1(100, "%s\n", mdb->cmd);
501 UPDATE_DB(jcr, mdb, mdb->cmd);
505 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */