]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
Backport from BEE
[bacula/bacula] / bacula / src / cats / sql_update.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
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.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  * Bacula Catalog Database Update record interface routines
18  *
19  *    Written by Kern Sibbald, March 2000
20  *
21  */
22
23 #include "bacula.h"
24
25 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
26
27 #include "cats.h"
28 #include "bdb_priv.h"
29 #include "sql_glue.h"
30
31 /* -----------------------------------------------------------------------
32  *
33  *   Generic Routines (or almost generic)
34  *
35  * -----------------------------------------------------------------------
36  */
37
38 /* -----------------------------------------------------------------------
39  *
40  *   Generic Routines (or almost generic)
41  *
42  * -----------------------------------------------------------------------
43  */
44 /* Update the attributes record by adding the file digest */
45 int
46 db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest,
47                           int type)
48 {
49    int ret;
50    char ed1[50];
51    int len = strlen(digest);
52
53    db_lock(mdb);
54    mdb->esc_name = check_pool_memory_size(mdb->esc_name, len*2+1);
55    mdb->db_escape_string(jcr, mdb->esc_name, digest, len);
56    Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", mdb->esc_name,
57         edit_int64(FileId, ed1));
58    ret = UPDATE_DB(jcr, mdb, mdb->cmd);
59    db_unlock(mdb);
60    return ret;
61 }
62
63 /* Mark the file record as being visited during database
64  * verify compare. Stuff JobId into the MarkId field
65  */
66 int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId)
67 {
68    int stat;
69    char ed1[50], ed2[50];
70
71    db_lock(mdb);
72    Mmsg(mdb->cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s",
73       edit_int64(JobId, ed1), edit_int64(FileId, ed2));
74    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
75    db_unlock(mdb);
76    return stat;
77 }
78
79 /*
80  * Update the Job record at start of Job
81  *
82  *  Returns: false on failure
83  *           true  on success
84  */
85 bool
86 db_update_job_start_record(JCR *jcr, B_DB *mdb, 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    db_lock(mdb);
101    Mmsg(mdb->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 = UPDATE_DB(jcr, mdb, mdb->cmd);
112    mdb->changes = 0;
113    db_unlock(mdb);
114    return stat;
115 }
116
117 /*
118  * Update Long term statistics with all jobs that were run before
119  * age seconds
120  */
121 int
122 db_update_stats(JCR *jcr, B_DB *mdb, utime_t age)
123 {
124    char ed1[30];
125    int rows;
126    utime_t now = (utime_t)time(NULL);
127    edit_uint64(now - age, ed1);
128
129    db_lock(mdb);
130
131    Mmsg(mdb->cmd, fill_jobhisto, ed1);
132    QUERY_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
133    rows = sql_affected_rows(mdb);
134
135    db_unlock(mdb);
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
147 db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
148 {
149    char dt[MAX_TIME_LENGTH];
150    char rdt[MAX_TIME_LENGTH];
151    time_t ttime;
152    struct tm tm;
153    int stat;
154    char ed1[30], ed2[30], ed3[50], ed4[50];
155    btime_t JobTDate;
156    char PriorJobId[50];
157
158    if (jr->PriorJobId) {
159       bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
160    } else {
161       bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
162    }
163
164    ttime = jr->EndTime;
165    (void)localtime_r(&ttime, &tm);
166    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
167
168    if (jr->RealEndTime == 0) {
169       jr->RealEndTime = jr->EndTime;
170    }
171    ttime = jr->RealEndTime;
172    (void)localtime_r(&ttime, &tm);
173    strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
174
175    JobTDate = ttime;
176
177    db_lock(mdb);
178    Mmsg(mdb->cmd,
179       "UPDATE Job SET JobStatus='%c',EndTime='%s',"
180 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
181 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
182 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
183       (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
184       edit_uint64(jr->ReadBytes, ed4),
185       jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
186       jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2),
187       rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
188       edit_int64(jr->JobId, ed3));
189
190    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
191
192    db_unlock(mdb);
193    return stat;
194 }
195
196 /*
197  * Update Client record
198  *   Returns: 0 on failure
199  *            1 on success
200  */
201 int
202 db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
203 {
204    int stat;
205    char ed1[50], ed2[50];
206    char esc_name[MAX_ESCAPE_NAME_LENGTH];
207    char esc_uname[MAX_ESCAPE_NAME_LENGTH];
208    CLIENT_DBR tcr;
209
210    db_lock(mdb);
211    memcpy(&tcr, cr, sizeof(tcr));
212    if (!db_create_client_record(jcr, mdb, &tcr)) {
213       db_unlock(mdb);
214       return 0;
215    }
216
217    mdb->db_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
218    mdb->db_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
219    Mmsg(mdb->cmd,
220 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
221 "Uname='%s' WHERE Name='%s'",
222       cr->AutoPrune,
223       edit_uint64(cr->FileRetention, ed1),
224       edit_uint64(cr->JobRetention, ed2),
225       esc_uname, esc_name);
226
227    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
228    db_unlock(mdb);
229    return stat;
230 }
231
232
233 /*
234  * Update Counters record
235  *   Returns: 0 on failure
236  *            1 on success
237  */
238 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
239 {
240    char esc[MAX_ESCAPE_NAME_LENGTH];
241    db_lock(mdb);
242    mdb->db_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
243    Mmsg(mdb->cmd,
244         update_counter_values[mdb->db_get_type_index()],
245         cr->MinValue, cr->MaxValue, cr->CurrentValue,
246         cr->WrapCounter, esc);
247
248    int stat = UPDATE_DB(jcr, mdb, mdb->cmd);
249    db_unlock(mdb);
250    return stat;
251 }
252
253
254 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
255 {
256    int stat;
257    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
258    char esc[MAX_ESCAPE_NAME_LENGTH];
259
260    db_lock(mdb);
261    mdb->db_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
262
263    Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
264       edit_int64(pr->PoolId, ed4));
265    pr->NumVols = get_sql_record_max(jcr, mdb);
266    Dmsg1(400, "NumVols=%d\n", pr->NumVols);
267
268    Mmsg(mdb->cmd,
269 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
270 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
271 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
272 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s,"
273 "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s",
274       pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
275       pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
276       edit_uint64(pr->VolUseDuration, ed2),
277       pr->MaxVolJobs, pr->MaxVolFiles,
278       edit_uint64(pr->MaxVolBytes, ed3),
279       pr->Recycle, pr->AutoPrune, pr->LabelType,
280       esc, edit_int64(pr->RecyclePoolId,ed5),
281       edit_int64(pr->ScratchPoolId,ed6),
282       pr->ActionOnPurge,
283       ed4);
284    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
285    db_unlock(mdb);
286    return stat;
287 }
288
289 bool
290 db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
291 {
292    int stat;
293    char ed1[50];
294    db_lock(mdb);
295    Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
296       sr->AutoChanger, edit_int64(sr->StorageId, ed1));
297
298    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
299    db_unlock(mdb);
300    return stat;
301 }
302
303
304 /*
305  * Update the Media Record at end of Session
306  *
307  * Returns: 0 on failure
308  *          numrows on success
309  */
310 int
311 db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
312 {
313    char dt[MAX_TIME_LENGTH];
314    time_t ttime;
315    struct tm tm;
316    int stat;
317    char ed1[50], ed4[50];
318    char ed5[50], ed6[50],  ed7[50],  ed8[50];
319    char ed9[50], ed10[50], ed11[50], ed12[50];
320    char ed13[50];
321    char esc_name[MAX_ESCAPE_NAME_LENGTH];
322    char esc_status[MAX_ESCAPE_NAME_LENGTH];
323
324    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
325    db_lock(mdb);
326    mdb->db_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
327    mdb->db_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
328
329    if (mr->set_first_written) {
330       Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
331       ttime = mr->FirstWritten;
332       (void)localtime_r(&ttime, &tm);
333       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
334       Mmsg(mdb->cmd, "UPDATE Media SET FirstWritten='%s'"
335            " WHERE VolumeName='%s'", dt, esc_name);
336       stat = UPDATE_DB(jcr, mdb, mdb->cmd);
337       Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
338    }
339
340    /* Label just done? */
341    if (mr->set_label_date) {
342       ttime = mr->LabelDate;
343       if (ttime == 0) {
344          ttime = time(NULL);
345       }
346       (void)localtime_r(&ttime, &tm);
347       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
348       Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
349            "WHERE VolumeName='%s'", dt, esc_name);
350       UPDATE_DB(jcr, mdb, mdb->cmd);
351    }
352
353    if (mr->LastWritten != 0) {
354       ttime = mr->LastWritten;
355       (void)localtime_r(&ttime, &tm);
356       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
357       Mmsg(mdb->cmd, "UPDATE Media Set LastWritten='%s' "
358            "WHERE VolumeName='%s'", dt, esc_name);
359       UPDATE_DB(jcr, mdb, mdb->cmd);
360    }
361
362    /* sanity checks for #1066 */
363    if (mr->VolReadTime < 0) {
364       mr->VolReadTime = 0;
365    }
366    if (mr->VolWriteTime < 0) {
367       mr->VolWriteTime = 0;
368    }
369
370    Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
371         "VolFiles=%u,VolBlocks=%u,VolBytes=%s,"
372         "VolMounts=%u,VolErrors=%u,"
373         "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
374         "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
375         "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
376         "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
377         "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,ActionOnPurge=%d"
378         " WHERE VolumeName='%s'",
379         mr->VolJobs, mr->VolFiles, mr->VolBlocks,
380         edit_uint64(mr->VolBytes, ed1),
381         mr->VolMounts, mr->VolErrors, mr->VolWrites,
382         edit_uint64(mr->MaxVolBytes, ed4),
383         esc_status, mr->Slot, mr->InChanger,
384         edit_int64(mr->VolReadTime, ed5),
385         edit_int64(mr->VolWriteTime, ed6),
386         mr->VolParts,
387         mr->LabelType,
388         edit_int64(mr->StorageId, ed7),
389         edit_int64(mr->PoolId, ed8),
390         edit_uint64(mr->VolRetention, ed9),
391         edit_uint64(mr->VolUseDuration, ed10),
392         mr->MaxVolJobs, mr->MaxVolFiles,
393         mr->Enabled, edit_uint64(mr->LocationId, ed11),
394         edit_uint64(mr->ScratchPoolId, ed12),
395         edit_uint64(mr->RecyclePoolId, ed13),
396         mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
397         esc_name);
398
399    Dmsg1(400, "%s\n", mdb->cmd);
400
401    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
402
403    /* Make sure InChanger is 0 for any record having the same Slot */
404    db_make_inchanger_unique(jcr, mdb, mr);
405
406    db_unlock(mdb);
407    return stat;
408 }
409
410 /*
411  * Update the Media Record Default values from Pool
412  *
413  * Returns: 0 on failure
414  *          numrows on success
415  */
416 int
417 db_update_media_defaults(JCR *jcr, B_DB *mdb, 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    db_lock(mdb);
424    if (mr->VolumeName[0]) {
425       mdb->db_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
426       Mmsg(mdb->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(mdb->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", mdb->cmd);
450
451    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
452
453    db_unlock(mdb);
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
465 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
466 {
467    char ed1[50], ed2[50];
468    char esc[MAX_ESCAPE_NAME_LENGTH];
469    if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
470
471        if (mr->MediaId != 0) {
472           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
473                "Slot=%d AND StorageId=%s AND MediaId!=%s",
474                mr->Slot,
475                edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
476
477        } else if (*mr->VolumeName) {
478           mdb->db_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName));
479           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
480                "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
481                mr->Slot,
482                edit_int64(mr->StorageId, ed1), esc);
483
484        } else {  /* used by ua_label to reset all volume with this slot */
485           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
486                "Slot=%d AND StorageId=%s",
487                mr->Slot,
488                edit_int64(mr->StorageId, ed1), mr->VolumeName);
489        }
490        Dmsg1(100, "%s\n", mdb->cmd);
491        UPDATE_DB(jcr, mdb, mdb->cmd);
492    }
493 }
494
495 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */