]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
Change copyright as per agreement with FSFE
[bacula/bacula] / bacula / src / cats / sql_update.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many 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    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Bacula Catalog Database Update record interface routines
21  *
22  *    Written by Kern Sibbald, March 2000
23  *
24  */
25
26 #include  "bacula.h"
27
28 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
29  
30 #include  "cats.h"
31
32 /* -----------------------------------------------------------------------
33  *
34  *   Generic Routines (or almost generic)
35  *
36  * -----------------------------------------------------------------------
37  */
38
39 /* -----------------------------------------------------------------------
40  *
41  *   Generic Routines (or almost generic)
42  *
43  * -----------------------------------------------------------------------
44  */
45 /* Update the attributes record by adding the file digest */
46 int BDB::bdb_add_digest_to_file_record(JCR *jcr, FileId_t FileId, char *digest,
47                           int type)
48 {
49    int ret;
50    char ed1[50];
51    int len = strlen(digest);
52
53    bdb_lock();
54    esc_name = check_pool_memory_size(esc_name, len*2+1);
55    bdb_escape_string(jcr, esc_name, digest, len);
56    Mmsg(cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", esc_name,
57         edit_int64(FileId, ed1));
58    ret = UpdateDB(jcr, cmd);
59    bdb_unlock();
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 BDB::bdb_mark_file_record(JCR *jcr, FileId_t FileId, JobId_t JobId)
67 {
68    int stat;
69    char ed1[50], ed2[50];
70
71    bdb_lock();
72    Mmsg(cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s",
73       edit_int64(JobId, ed1), edit_int64(FileId, ed2));
74    stat = UpdateDB(jcr, cmd);
75    bdb_unlock();
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 BDB::bdb_update_job_start_record(JCR *jcr, JOB_DBR *jr)
86 {
87    char dt[MAX_TIME_LENGTH];
88    time_t stime;
89    struct tm tm;
90    btime_t JobTDate;
91    int stat;
92    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
93
94    stime = jr->StartTime;
95    (void)localtime_r(&stime, &tm);
96    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
97    JobTDate = (btime_t)stime;
98
99    bdb_lock();
100    Mmsg(cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s',"
101 "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s",
102       (char)(jcr->JobStatus),
103       (char)(jr->JobLevel), dt,
104       edit_int64(jr->ClientId, ed1),
105       edit_uint64(JobTDate, ed2),
106       edit_int64(jr->PoolId, ed3),
107       edit_int64(jr->FileSetId, ed4),
108       edit_int64(jr->JobId, ed5));
109
110    stat = UpdateDB(jcr, cmd);
111    changes = 0;
112    bdb_unlock();
113    return stat;
114 }
115
116 /*
117  * Update Long term statistics with all jobs that were run before
118  * age seconds
119  */
120 int BDB::bdb_update_stats(JCR *jcr, utime_t age)
121 {
122    char ed1[30];
123    int rows;
124
125    utime_t now = (utime_t)time(NULL);
126    edit_uint64(now - age, ed1);
127
128    bdb_lock();
129
130    Mmsg(cmd, fill_jobhisto, ed1);
131    QueryDB(jcr, cmd); /* TODO: get a message ? */
132    rows = sql_affected_rows();
133
134    bdb_unlock();
135
136    return rows;
137 }
138
139 /*
140  * Update the Job record at end of Job
141  *
142  *  Returns: 0 on failure
143  *           1 on success
144  */
145 int BDB::bdb_update_job_end_record(JCR *jcr, JOB_DBR *jr)
146 {
147    char dt[MAX_TIME_LENGTH];
148    char rdt[MAX_TIME_LENGTH];
149    time_t ttime;
150    struct tm tm;
151    int stat;
152    char ed1[30], ed2[30], ed3[50], ed4[50];
153    btime_t JobTDate;
154    char PriorJobId[50];
155
156    if (jr->PriorJobId) {
157       bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
158    } else {
159       bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
160    }
161
162    ttime = jr->EndTime;
163    (void)localtime_r(&ttime, &tm);
164    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
165
166    if (jr->RealEndTime == 0 || jr->RealEndTime < jr->EndTime) {
167       jr->RealEndTime = jr->EndTime;
168    }
169    ttime = jr->RealEndTime;
170    (void)localtime_r(&ttime, &tm);
171    strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
172
173    JobTDate = ttime;
174
175    bdb_lock();
176    Mmsg(cmd,
177       "UPDATE Job SET JobStatus='%c',EndTime='%s',"
178 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
179 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
180 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
181       (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
182       edit_uint64(jr->ReadBytes, ed4),
183       jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
184       jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2),
185       rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
186       edit_int64(jr->JobId, ed3));
187
188    stat = UpdateDB(jcr, cmd);
189
190    bdb_unlock();
191    return stat;
192 }
193
194 /*
195  * Update Client record
196  *   Returns: 0 on failure
197  *            1 on success
198  */
199 int BDB::bdb_update_client_record(JCR *jcr, CLIENT_DBR *cr)
200 {
201    int stat;
202    char ed1[50], ed2[50];
203    char esc_name[MAX_ESCAPE_NAME_LENGTH];
204    char esc_uname[MAX_ESCAPE_NAME_LENGTH];
205    CLIENT_DBR tcr;
206
207    bdb_lock();
208    memcpy(&tcr, cr, sizeof(tcr));
209    if (!bdb_create_client_record(jcr, &tcr)) {
210       bdb_unlock();
211       return 0;
212    }
213
214    bdb_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
215    bdb_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
216    Mmsg(cmd,
217 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
218 "Uname='%s' WHERE Name='%s'",
219       cr->AutoPrune,
220       edit_uint64(cr->FileRetention, ed1),
221       edit_uint64(cr->JobRetention, ed2),
222       esc_uname, esc_name);
223
224    stat = UpdateDB(jcr, cmd);
225    bdb_unlock();
226    return stat;
227 }
228
229
230 /*
231  * Update Counters record
232  *   Returns: 0 on failure
233  *            1 on success
234  */
235 int BDB::bdb_update_counter_record(JCR *jcr, COUNTER_DBR *cr)
236 {
237    char esc[MAX_ESCAPE_NAME_LENGTH];
238
239    bdb_lock();
240    bdb_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
241    Mmsg(cmd, update_counter_values[bdb_get_type_index()],
242       cr->MinValue, cr->MaxValue, cr->CurrentValue,
243       cr->WrapCounter, esc);
244
245    int stat = UpdateDB(jcr, cmd);
246    bdb_unlock();
247    return stat;
248 }
249
250
251 int BDB::bdb_update_pool_record(JCR *jcr, POOL_DBR *pr)
252 {
253    int stat;
254    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
255    char esc[MAX_ESCAPE_NAME_LENGTH];
256
257    bdb_lock();
258    bdb_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
259
260    Mmsg(cmd, "SELECT count(*) from Media WHERE PoolId=%s",
261       edit_int64(pr->PoolId, ed4));
262    pr->NumVols = get_sql_record_max(jcr, this);
263    Dmsg1(400, "NumVols=%d\n", pr->NumVols);
264
265    Mmsg(cmd,
266 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
267 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
268 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
269 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s,"
270 "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s",
271       pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
272       pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
273       edit_uint64(pr->VolUseDuration, ed2),
274       pr->MaxVolJobs, pr->MaxVolFiles,
275       edit_uint64(pr->MaxVolBytes, ed3),
276       pr->Recycle, pr->AutoPrune, pr->LabelType,
277       esc, edit_int64(pr->RecyclePoolId,ed5),
278       edit_int64(pr->ScratchPoolId,ed6),
279       pr->ActionOnPurge,
280       ed4);
281    stat = UpdateDB(jcr, cmd);
282    bdb_unlock();
283    return stat;
284 }
285
286 bool BDB::bdb_update_storage_record(JCR *jcr, STORAGE_DBR *sr)
287 {
288    int stat;
289    char ed1[50];
290
291    bdb_lock();
292    Mmsg(cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
293       sr->AutoChanger, edit_int64(sr->StorageId, ed1));
294
295    stat = UpdateDB(jcr, cmd);
296    bdb_unlock();
297    return stat;
298 }
299
300
301 /*
302  * Update the Media Record at end of Session
303  *
304  * Returns: 0 on failure
305  *          numrows on success
306  */
307 int BDB::bdb_update_media_record(JCR *jcr, MEDIA_DBR *mr)
308 {
309    char dt[MAX_TIME_LENGTH];
310    time_t ttime;
311    struct tm tm;
312    int stat;
313    char ed1[50], ed2[50],  ed3[50],  ed4[50];
314    char ed5[50], ed6[50],  ed7[50],  ed8[50];
315    char ed9[50], ed10[50], ed11[50], ed12[50];
316    char ed13[50], ed14[50];
317    char esc_name[MAX_ESCAPE_NAME_LENGTH];
318    char esc_status[MAX_ESCAPE_NAME_LENGTH];
319
320    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
321    bdb_lock();
322    bdb_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
323    bdb_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
324
325    if (mr->set_first_written) {
326       Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
327       ttime = mr->FirstWritten;
328       (void)localtime_r(&ttime, &tm);
329       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
330       Mmsg(cmd, "UPDATE Media SET FirstWritten='%s'"
331            " WHERE VolumeName='%s'", dt, esc_name);
332       stat = UpdateDB(jcr, cmd);
333       Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
334    }
335
336    /* Label just done? */
337    if (mr->set_label_date) {
338       ttime = mr->LabelDate;
339       if (ttime == 0) {
340          ttime = time(NULL);
341       }
342       (void)localtime_r(&ttime, &tm);
343       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
344       Mmsg(cmd, "UPDATE Media SET LabelDate='%s' "
345            "WHERE VolumeName='%s'", dt, esc_name);
346       UpdateDB(jcr, cmd);
347    }
348
349    if (mr->LastWritten != 0) {
350       ttime = mr->LastWritten;
351       (void)localtime_r(&ttime, &tm);
352       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
353       Mmsg(cmd, "UPDATE Media Set LastWritten='%s' "
354            "WHERE VolumeName='%s'", dt, esc_name);
355       UpdateDB(jcr, cmd);
356    }
357
358    /* sanity checks for #1066 */
359    if (mr->VolReadTime < 0) {
360       mr->VolReadTime = 0;
361    }
362    if (mr->VolWriteTime < 0) {
363       mr->VolWriteTime = 0;
364    }
365
366    Mmsg(cmd, "UPDATE Media SET VolJobs=%u,"
367         "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolABytes=%s,"
368         "VolHoleBytes=%s,VolHoles=%u,VolMounts=%u,VolErrors=%u,"
369         "VolWrites=%s,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,Recycle=%d,"
374         "ActionOnPurge=%d"
375         " WHERE VolumeName='%s'",
376         mr->VolJobs, mr->VolFiles, mr->VolBlocks,
377         edit_uint64(mr->VolBytes, ed1),
378         edit_uint64(mr->VolABytes, ed2),
379         edit_uint64(mr->VolHoleBytes, ed3),
380         mr->VolHoles, mr->VolMounts, mr->VolErrors,
381         edit_uint64(mr->VolWrites, ed4),
382         edit_uint64(mr->MaxVolBytes, ed5),
383         esc_status, mr->Slot, mr->InChanger,
384         edit_int64(mr->VolReadTime, ed6),
385         edit_int64(mr->VolWriteTime, ed7),
386         mr->VolType,  /* formerly VolParts */
387         mr->LabelType,
388         edit_int64(mr->StorageId, ed8),
389         edit_int64(mr->PoolId, ed9),
390         edit_uint64(mr->VolRetention, ed10),
391         edit_uint64(mr->VolUseDuration, ed11),
392         mr->MaxVolJobs, mr->MaxVolFiles,
393         mr->Enabled, edit_uint64(mr->LocationId, ed12),
394         edit_uint64(mr->ScratchPoolId, ed13),
395         edit_uint64(mr->RecyclePoolId, ed14),
396         mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
397         esc_name);
398
399    Dmsg1(400, "%s\n", cmd);
400
401    stat = UpdateDB(jcr, cmd);
402
403    /* Make sure InChanger is 0 for any record having the same Slot */
404    db_make_inchanger_unique(jcr, this, mr);
405
406    bdb_unlock();
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 BDB::bdb_update_media_defaults(JCR *jcr, MEDIA_DBR *mr)
417 {
418    int stat;
419    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
420    char esc[MAX_ESCAPE_NAME_LENGTH];
421
422    bdb_lock();
423    if (mr->VolumeName[0]) {
424       bdb_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
425       Mmsg(cmd, "UPDATE Media SET "
426            "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
427            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
428            " WHERE VolumeName='%s'",
429            mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
430            edit_uint64(mr->VolUseDuration, ed2),
431            mr->MaxVolJobs, mr->MaxVolFiles,
432            edit_uint64(mr->MaxVolBytes, ed3),
433            edit_uint64(mr->RecyclePoolId, ed4),
434            esc);
435    } else {
436       Mmsg(cmd, "UPDATE Media SET "
437            "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
438            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
439            " WHERE PoolId=%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_int64(mr->RecyclePoolId, ed4),
445            edit_int64(mr->PoolId, ed5));
446    }
447
448    Dmsg1(400, "%s\n", cmd);
449
450    stat = UpdateDB(jcr, cmd);
451
452    bdb_unlock();
453    return stat;
454 }
455
456
457 /*
458  * If we have a non-zero InChanger, ensure that no other Media
459  *  record has InChanger set on the same Slot.
460  *
461  * This routine assumes the database is already locked.
462  */
463 void BDB::bdb_make_inchanger_unique(JCR *jcr, MEDIA_DBR *mr)
464 {
465    char ed1[50], ed2[50];
466    char esc[MAX_ESCAPE_NAME_LENGTH];
467
468    if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
469        if (mr->MediaId != 0) {
470           Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
471                "Slot=%d AND StorageId=%s AND MediaId!=%s",
472                mr->Slot,
473                edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
474
475        } else if (*mr->VolumeName) {
476           bdb_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName));
477           Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
478                "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
479                mr->Slot,
480                edit_int64(mr->StorageId, ed1), esc);
481
482        } else {  /* used by ua_label to reset all volume with this slot */
483           Mmsg(cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
484                "Slot=%d AND StorageId=%s",
485                mr->Slot,
486                edit_int64(mr->StorageId, ed1), mr->VolumeName);
487        }
488        Dmsg1(100, "%s\n", cmd);
489        UpdateDB(jcr, cmd);
490    }
491 }
492
493 /* Update only Retention */
494 bool BDB::bdb_update_snapshot_record(JCR *jcr, SNAPSHOT_DBR *sr)
495 {
496    int stat, len;
497    char ed1[50], ed2[50];
498
499    len = strlen(sr->Comment);
500    bdb_lock();
501
502    esc_name = check_pool_memory_size(esc_name, len*2+1);
503    bdb_escape_string(jcr, esc_name, sr->Comment, len);
504
505    Mmsg(cmd, "UPDATE Snapshot SET Retention=%s, Comment='%s' WHERE SnapshotId=%s",
506         edit_int64(sr->Retention, ed2), sr->Comment, edit_int64(sr->SnapshotId, ed1));
507
508    stat = UpdateDB(jcr, cmd);
509    bdb_unlock();
510    return stat;
511 }
512
513 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */