2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 John Walker.
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
36 /* The following is necessary so that we do not include
37 * the dummy external definition of DB.
39 #define __SQL_C /* indicate that this is sql.c */
44 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
46 /* -----------------------------------------------------------------------
48 * Generic Routines (or almost generic)
50 * -----------------------------------------------------------------------
53 /* -----------------------------------------------------------------------
55 * Generic Routines (or almost generic)
57 * -----------------------------------------------------------------------
59 /* Update the attributes record by adding the file digest */
61 db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest,
68 Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", digest,
69 edit_int64(FileId, ed1));
70 stat = 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];
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 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->JobId, ed4));
122 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
129 * Given an incoming integer, set the string buffer to either NULL or the value
132 static void edit_num_or_null(char *s, size_t n, uint64_t id) {
134 bsnprintf(s, n, id ? "%s" : "NULL", edit_int64(id, ed1));
139 * Update the Job record at end of Job
141 * Returns: 0 on failure
145 db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, bool stats_enabled)
147 char dt[MAX_TIME_LENGTH];
148 char rdt[MAX_TIME_LENGTH];
152 char ed1[30], ed2[30], ed3[50];
154 char PoolId[50], FileSetId[50], ClientId[50], PriorJobId[50];
157 /* some values are set to zero, which translates to NULL in SQL */
158 edit_num_or_null(PoolId, sizeof(PoolId), jr->PoolId);
159 edit_num_or_null(FileSetId, sizeof(FileSetId), jr->FileSetId);
160 edit_num_or_null(ClientId, sizeof(ClientId), jr->ClientId);
162 if (jr->PriorJobId) {
163 bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
165 bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
169 (void)localtime_r(&ttime, &tm);
170 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
172 if (jr->RealEndTime == 0) {
173 jr->RealEndTime = jr->EndTime;
175 ttime = jr->RealEndTime;
176 (void)localtime_r(&ttime, &tm);
177 strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
183 "UPDATE Job SET JobStatus='%c',EndTime='%s',"
184 "ClientId=%s,JobBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
185 "VolSessionTime=%u,PoolId=%s,FileSetId=%s,JobTDate=%s,"
186 "RealEndTime='%s',PriorJobId=%s WHERE JobId=%s",
187 (char)(jr->JobStatus), dt, ClientId, edit_uint64(jr->JobBytes, ed1),
188 jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
189 PoolId, FileSetId, edit_uint64(JobTDate, ed2),
192 edit_int64(jr->JobId, ed3));
194 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
196 if (stat && stats_enabled) {
198 "INSERT INTO JobStat (SELECT * FROM Job WHERE JobId=%s)",
199 edit_int64(jr->JobId, ed3));
200 INSERT_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
207 * Update Client record
208 * Returns: 0 on failure
212 db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
215 char ed1[50], ed2[50];
219 memcpy(&tcr, cr, sizeof(tcr));
220 if (!db_create_client_record(jcr, mdb, &tcr)) {
226 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
227 "Uname='%s' WHERE Name='%s'",
229 edit_uint64(cr->FileRetention, ed1),
230 edit_uint64(cr->JobRetention, ed2),
231 cr->Uname, cr->Name);
233 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
240 * Update Counters record
241 * Returns: 0 on failure
244 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
249 "UPDATE Counters SET MinValue=%d,MaxValue=%d,CurrentValue=%d,"
250 "WrapCounter='%s' WHERE Counter='%s'",
251 cr->MinValue, cr->MaxValue, cr->CurrentValue,
252 cr->WrapCounter, cr->Counter);
254 int stat = UPDATE_DB(jcr, mdb, mdb->cmd);
260 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
263 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
266 Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
267 edit_int64(pr->PoolId, ed4));
268 pr->NumVols = get_sql_record_max(jcr, mdb);
269 Dmsg1(400, "NumVols=%d\n", pr->NumVols);
272 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
273 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
274 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
275 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s WHERE PoolId=%s",
276 pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
277 pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
278 edit_uint64(pr->VolUseDuration, ed2),
279 pr->MaxVolJobs, pr->MaxVolFiles,
280 edit_uint64(pr->MaxVolBytes, ed3),
281 pr->Recycle, pr->AutoPrune, pr->LabelType,
282 pr->LabelFormat, edit_int64(pr->RecyclePoolId,ed5),
285 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
291 db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
297 Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
298 sr->AutoChanger, edit_int64(sr->StorageId, ed1));
300 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
307 * Update the Media Record at end of Session
309 * Returns: 0 on failure
313 db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
315 char dt[MAX_TIME_LENGTH];
319 char ed1[50], ed2[50], ed3[50], ed4[50];
320 char ed5[50], ed6[50], ed7[50], ed8[50];
321 char ed9[50], ed10[50], ed11[50];
324 Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
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(mdb->cmd, "UPDATE Media SET FirstWritten='%s'"
332 " WHERE VolumeName='%s'", dt, mr->VolumeName);
333 stat = UPDATE_DB(jcr, mdb, mdb->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(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
346 "WHERE VolumeName='%s'", dt, mr->VolumeName);
347 UPDATE_DB(jcr, mdb, mdb->cmd);
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(mdb->cmd, "UPDATE Media Set LastWritten='%s' "
355 "WHERE VolumeName='%s'", dt, mr->VolumeName);
356 UPDATE_DB(jcr, mdb, mdb->cmd);
359 /* sanity checks for #1066 */
360 if (mr->VolReadTime < 0) {
363 if (mr->VolWriteTime < 0) {
364 mr->VolWriteTime = 0;
367 Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
368 "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
369 "VolWrites=%u,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"
374 " WHERE VolumeName='%s'",
375 mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
376 mr->VolMounts, mr->VolErrors, mr->VolWrites,
377 edit_uint64(mr->MaxVolBytes, ed2),
378 mr->VolStatus, mr->Slot, mr->InChanger,
379 edit_int64(mr->VolReadTime, ed3),
380 edit_int64(mr->VolWriteTime, ed4),
383 edit_int64(mr->StorageId, ed5),
384 edit_int64(mr->PoolId, ed6),
385 edit_uint64(mr->VolRetention, ed7),
386 edit_uint64(mr->VolUseDuration, ed8),
387 mr->MaxVolJobs, mr->MaxVolFiles,
388 mr->Enabled, edit_uint64(mr->LocationId, ed9),
389 edit_uint64(mr->ScratchPoolId, ed10),
390 edit_uint64(mr->RecyclePoolId, ed11),
394 Dmsg1(400, "%s\n", mdb->cmd);
396 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
398 /* Make sure InChanger is 0 for any record having the same Slot */
399 db_make_inchanger_unique(jcr, mdb, mr);
406 * Update the Media Record Default values from Pool
408 * Returns: 0 on failure
412 db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
415 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
419 if (mr->VolumeName[0]) {
420 Mmsg(mdb->cmd, "UPDATE Media SET "
421 "Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
422 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
423 " WHERE VolumeName='%s'",
424 mr->Recycle,edit_uint64(mr->VolRetention, ed1),
425 edit_uint64(mr->VolUseDuration, ed2),
426 mr->MaxVolJobs, mr->MaxVolFiles,
427 edit_uint64(mr->MaxVolBytes, ed3),
428 edit_uint64(mr->RecyclePoolId, ed4),
431 Mmsg(mdb->cmd, "UPDATE Media SET "
432 "Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
433 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
435 mr->Recycle,edit_uint64(mr->VolRetention, ed1),
436 edit_uint64(mr->VolUseDuration, ed2),
437 mr->MaxVolJobs, mr->MaxVolFiles,
438 edit_uint64(mr->MaxVolBytes, ed3),
439 edit_int64(mr->RecyclePoolId, ed4),
440 edit_int64(mr->PoolId, ed5));
443 Dmsg1(400, "%s\n", mdb->cmd);
445 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
453 * If we have a non-zero InChanger, ensure that no other Media
454 * record has InChanger set on the same Slot.
456 * This routine assumes the database is already locked.
459 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
461 char ed1[50], ed2[50];
462 if (mr->InChanger != 0 && mr->Slot != 0) {
463 Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0 WHERE "
464 "Slot=%d AND StorageId=%s AND MediaId!=%s",
466 edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
467 Dmsg1(400, "%s\n", mdb->cmd);
468 UPDATE_DB(jcr, mdb, mdb->cmd);
472 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/