]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
3c051aadce631c480b0010b9da1ca9fcfe3f25b3
[bacula/bacula] / bacula / src / cats / sql_update.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6
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.
9
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.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19 */
20 /*
21  * Bacula Catalog Database Update record interface routines
22  *
23  *    Written by Kern Sibbald, March 2000
24  *
25  */
26
27 #include  "bacula.h"
28
29 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
30  
31 #include  "cats.h"
32
33 /* -----------------------------------------------------------------------
34  *
35  *   Generic Routines (or almost generic)
36  *
37  * -----------------------------------------------------------------------
38  */
39
40 /* -----------------------------------------------------------------------
41  *
42  *   Generic Routines (or almost generic)
43  *
44  * -----------------------------------------------------------------------
45  */
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,
48                           int type)
49 {
50    int ret;
51    char ed1[50];
52    int len = strlen(digest);
53
54    bdb_lock();
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);
60    bdb_unlock();
61    return ret;
62 }
63
64 /* Mark the file record as being visited during database
65  * verify compare. Stuff JobId into the MarkId field
66  */
67 int BDB::bdb_mark_file_record(JCR *jcr, FileId_t FileId, JobId_t JobId)
68 {
69    int stat;
70    char ed1[50], ed2[50];
71
72    bdb_lock();
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);
76    bdb_unlock();
77    return stat;
78 }
79
80 /*
81  * Update the Job record at start of Job
82  *
83  *  Returns: false on failure
84  *           true  on success
85  */
86 bool BDB::bdb_update_job_start_record(JCR *jcr, JOB_DBR *jr)
87 {
88    char dt[MAX_TIME_LENGTH];
89    time_t stime;
90    struct tm tm;
91    btime_t JobTDate;
92    int stat;
93    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
94
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;
99
100    bdb_lock();
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));
110
111    stat = UpdateDB(jcr, cmd);
112    changes = 0;
113    bdb_unlock();
114    return stat;
115 }
116
117 /*
118  * Update Long term statistics with all jobs that were run before
119  * age seconds
120  */
121 int BDB::bdb_update_stats(JCR *jcr, utime_t age)
122 {
123    char ed1[30];
124    int rows;
125
126    utime_t now = (utime_t)time(NULL);
127    edit_uint64(now - age, ed1);
128
129    bdb_lock();
130
131    Mmsg(cmd, fill_jobhisto, ed1);
132    QueryDB(jcr, cmd); /* TODO: get a message ? */
133    rows = sql_affected_rows();
134
135    bdb_unlock();
136
137    return rows;
138 }
139
140 /*
141  * Update the Job record at end of Job
142  *
143  *  Returns: 0 on failure
144  *           1 on success
145  */
146 int BDB::bdb_update_job_end_record(JCR *jcr, JOB_DBR *jr)
147 {
148    char dt[MAX_TIME_LENGTH];
149    char rdt[MAX_TIME_LENGTH];
150    time_t ttime;
151    struct tm tm;
152    int stat;
153    char ed1[30], ed2[30], ed3[50], ed4[50];
154    btime_t JobTDate;
155    char PriorJobId[50];
156
157    if (jr->PriorJobId) {
158       bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
159    } else {
160       bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
161    }
162
163    ttime = jr->EndTime;
164    (void)localtime_r(&ttime, &tm);
165    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
166
167    if (jr->RealEndTime == 0 || jr->RealEndTime < jr->EndTime) {
168       jr->RealEndTime = jr->EndTime;
169    }
170    ttime = jr->RealEndTime;
171    (void)localtime_r(&ttime, &tm);
172    strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
173
174    JobTDate = ttime;
175
176    bdb_lock();
177    Mmsg(cmd,
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));
188
189    stat = UpdateDB(jcr, cmd);
190
191    bdb_unlock();
192    return stat;
193 }
194
195 /*
196  * Update Client record
197  *   Returns: 0 on failure
198  *            1 on success
199  */
200 int BDB::bdb_update_client_record(JCR *jcr, CLIENT_DBR *cr)
201 {
202    int stat;
203    char ed1[50], ed2[50];
204    char esc_name[MAX_ESCAPE_NAME_LENGTH];
205    char esc_uname[MAX_ESCAPE_NAME_LENGTH];
206    CLIENT_DBR tcr;
207
208    bdb_lock();
209    memcpy(&tcr, cr, sizeof(tcr));
210    if (!bdb_create_client_record(jcr, &tcr)) {
211       bdb_unlock();
212       return 0;
213    }
214
215    bdb_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
216    bdb_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
217    Mmsg(cmd,
218 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
219 "Uname='%s' WHERE Name='%s'",
220       cr->AutoPrune,
221       edit_uint64(cr->FileRetention, ed1),
222       edit_uint64(cr->JobRetention, ed2),
223       esc_uname, esc_name);
224
225    stat = UpdateDB(jcr, cmd);
226    bdb_unlock();
227    return stat;
228 }
229
230
231 /*
232  * Update Counters record
233  *   Returns: 0 on failure
234  *            1 on success
235  */
236 int BDB::bdb_update_counter_record(JCR *jcr, COUNTER_DBR *cr)
237 {
238    char esc[MAX_ESCAPE_NAME_LENGTH];
239
240    bdb_lock();
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);
245
246    int stat = UpdateDB(jcr, cmd);
247    bdb_unlock();
248    return stat;
249 }
250
251
252 int BDB::bdb_update_pool_record(JCR *jcr, POOL_DBR *pr)
253 {
254    int stat;
255    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
256    char esc[MAX_ESCAPE_NAME_LENGTH];
257
258    bdb_lock();
259    bdb_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
260
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);
265
266    Mmsg(cmd,
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),
280       pr->ActionOnPurge,
281       ed4);
282    stat = UpdateDB(jcr, cmd);
283    bdb_unlock();
284    return stat;
285 }
286
287 bool BDB::bdb_update_storage_record(JCR *jcr, STORAGE_DBR *sr)
288 {
289    int stat;
290    char ed1[50];
291
292    bdb_lock();
293    Mmsg(cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
294       sr->AutoChanger, edit_int64(sr->StorageId, ed1));
295
296    stat = UpdateDB(jcr, cmd);
297    bdb_unlock();
298    return stat;
299 }
300
301
302 /*
303  * Update the Media Record at end of Session
304  *
305  * Returns: 0 on failure
306  *          numrows on success
307  */
308 int BDB::bdb_update_media_record(JCR *jcr, MEDIA_DBR *mr)
309 {
310    char dt[MAX_TIME_LENGTH];
311    time_t ttime;
312    struct tm tm;
313    int stat;
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];
320
321    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
322    bdb_lock();
323    bdb_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
324    bdb_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
325
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);
335    }
336
337    /* Label just done? */
338    if (mr->set_label_date) {
339       ttime = mr->LabelDate;
340       if (ttime == 0) {
341          ttime = time(NULL);
342       }
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);
347       UpdateDB(jcr, cmd);
348    }
349
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);
356       UpdateDB(jcr, cmd);
357    }
358
359    /* sanity checks for #1066 */
360    if (mr->VolReadTime < 0) {
361       mr->VolReadTime = 0;
362    }
363    if (mr->VolWriteTime < 0) {
364       mr->VolWriteTime = 0;
365    }
366
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,"
375         "ActionOnPurge=%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 */
388         mr->LabelType,
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,
398         esc_name);
399
400    Dmsg1(400, "%s\n", cmd);
401
402    stat = UpdateDB(jcr, cmd);
403
404    /* Make sure InChanger is 0 for any record having the same Slot */
405    db_make_inchanger_unique(jcr, this, mr);
406
407    bdb_unlock();
408    return stat;
409 }
410
411 /*
412  * Update the Media Record Default values from Pool
413  *
414  * Returns: 0 on failure
415  *          numrows on success
416  */
417 int BDB::bdb_update_media_defaults(JCR *jcr, MEDIA_DBR *mr)
418 {
419    int stat;
420    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
421    char esc[MAX_ESCAPE_NAME_LENGTH];
422
423    bdb_lock();
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),
435            esc);
436    } else {
437       Mmsg(cmd, "UPDATE Media SET "
438            "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
439            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
440            " WHERE PoolId=%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));
447    }
448
449    Dmsg1(400, "%s\n", cmd);
450
451    stat = UpdateDB(jcr, cmd);
452
453    bdb_unlock();
454    return stat;
455 }
456
457
458 /*
459  * If we have a non-zero InChanger, ensure that no other Media
460  *  record has InChanger set on the same Slot.
461  *
462  * This routine assumes the database is already locked.
463  */
464 void BDB::bdb_make_inchanger_unique(JCR *jcr, MEDIA_DBR *mr)
465 {
466    char ed1[50], ed2[50];
467    char esc[MAX_ESCAPE_NAME_LENGTH];
468
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",
473                mr->Slot,
474                edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
475
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'",
480                mr->Slot,
481                edit_int64(mr->StorageId, ed1), esc);
482
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",
486                mr->Slot,
487                edit_int64(mr->StorageId, ed1), mr->VolumeName);
488        }
489        Dmsg1(100, "%s\n", cmd);
490        UpdateDB(jcr, cmd);
491    }
492 }
493
494 /* Update only Retention */
495 bool BDB::bdb_update_snapshot_record(JCR *jcr, SNAPSHOT_DBR *sr)
496 {
497    int stat, len;
498    char ed1[50], ed2[50];
499
500    len = strlen(sr->Comment);
501    bdb_lock();
502
503    esc_name = check_pool_memory_size(esc_name, len*2+1);
504    bdb_escape_string(jcr, esc_name, sr->Comment, len);
505
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));
508
509    stat = UpdateDB(jcr, cmd);
510    bdb_unlock();
511    return stat;
512 }
513
514 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */