]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
62ce20ec1941ad1e8fb168d6acbb319ea581270a
[bacula/bacula] / bacula / src / cats / sql_update.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  * Bacula Catalog Database Update record interface routines
30  *
31  *    Kern Sibbald, March 2000
32  *
33  */
34
35 #include "bacula.h"
36
37 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
38
39 #include "cats.h"
40 #include "bdb_priv.h"
41 #include "sql_glue.h"
42
43 /* -----------------------------------------------------------------------
44  *
45  *   Generic Routines (or almost generic)
46  *
47  * -----------------------------------------------------------------------
48  */
49
50 /* -----------------------------------------------------------------------
51  *
52  *   Generic Routines (or almost generic)
53  *
54  * -----------------------------------------------------------------------
55  */
56 /* Update the attributes record by adding the file digest */
57 int
58 db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest,
59                           int type)
60 {
61    int ret;
62    char ed1[50];
63    int len = strlen(digest);
64
65    db_lock(mdb);
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);
71    db_unlock(mdb);
72    return ret;
73 }
74
75 /* Mark the file record as being visited during database
76  * verify compare. Stuff JobId into the MarkId field
77  */
78 int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId)
79 {
80    int stat;
81    char ed1[50], ed2[50];
82
83    db_lock(mdb);
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);
87    db_unlock(mdb);
88    return stat;
89 }
90
91 /*
92  * Update the Job record at start of Job
93  *
94  *  Returns: false on failure
95  *           true  on success
96  */
97 bool
98 db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
99 {
100    char dt[MAX_TIME_LENGTH];
101    time_t stime;
102    struct tm tm;
103    btime_t JobTDate;
104    int stat;
105    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
106
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;
111
112    db_lock(mdb);
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));
122
123    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
124    mdb->changes = 0;
125    db_unlock(mdb);
126    return stat;
127 }
128
129 /*
130  * Update Long term statistics with all jobs that were run before
131  * age seconds
132  */
133 int
134 db_update_stats(JCR *jcr, B_DB *mdb, utime_t age)
135 {
136    char ed1[30];
137    int rows;
138    utime_t now = (utime_t)time(NULL);
139    edit_uint64(now - age, ed1);
140
141    db_lock(mdb);
142
143    Mmsg(mdb->cmd, fill_jobhisto, ed1);
144    QUERY_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
145    rows = sql_affected_rows(mdb);
146
147    db_unlock(mdb);
148
149    return rows;
150 }
151
152 /*
153  * Update the Job record at end of Job
154  *
155  *  Returns: 0 on failure
156  *           1 on success
157  */
158 int
159 db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
160 {
161    char dt[MAX_TIME_LENGTH];
162    char rdt[MAX_TIME_LENGTH];
163    time_t ttime;
164    struct tm tm;
165    int stat;
166    char ed1[30], ed2[30], ed3[50], ed4[50];
167    btime_t JobTDate;
168    char PriorJobId[50];
169
170    if (jr->PriorJobId) {
171       bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
172    } else {
173       bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
174    }
175
176    ttime = jr->EndTime;
177    (void)localtime_r(&ttime, &tm);
178    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
179
180    if (jr->RealEndTime == 0) {
181       jr->RealEndTime = jr->EndTime;
182    }
183    ttime = jr->RealEndTime;
184    (void)localtime_r(&ttime, &tm);
185    strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
186
187    JobTDate = ttime;
188
189    db_lock(mdb);
190    Mmsg(mdb->cmd,
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));
201
202    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
203
204    db_unlock(mdb);
205    return stat;
206 }
207
208 /*
209  * Update Client record
210  *   Returns: 0 on failure
211  *            1 on success
212  */
213 int
214 db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
215 {
216    int stat;
217    char ed1[50], ed2[50];
218    char esc_name[MAX_ESCAPE_NAME_LENGTH];
219    char esc_uname[MAX_ESCAPE_NAME_LENGTH];
220    CLIENT_DBR tcr;
221
222    db_lock(mdb);
223    memcpy(&tcr, cr, sizeof(tcr));
224    if (!db_create_client_record(jcr, mdb, &tcr)) {
225       db_unlock(mdb);
226       return 0;
227    }
228
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));
231    Mmsg(mdb->cmd,
232 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
233 "Uname='%s' WHERE Name='%s'",
234       cr->AutoPrune,
235       edit_uint64(cr->FileRetention, ed1),
236       edit_uint64(cr->JobRetention, ed2),
237       esc_uname, esc_name);
238
239    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
240    db_unlock(mdb);
241    return stat;
242 }
243
244
245 /*
246  * Update Counters record
247  *   Returns: 0 on failure
248  *            1 on success
249  */
250 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
251 {
252    char esc[MAX_ESCAPE_NAME_LENGTH];
253    db_lock(mdb);
254    mdb->db_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
255    Mmsg(mdb->cmd,
256 "UPDATE Counters SET MinValue=%d,MaxValue=%d,CurrentValue=%d,"
257 "WrapCounter='%s' WHERE Counter='%s'",
258       cr->MinValue, cr->MaxValue, cr->CurrentValue,
259       cr->WrapCounter, esc);
260
261    int stat = UPDATE_DB(jcr, mdb, mdb->cmd);
262    db_unlock(mdb);
263    return stat;
264 }
265
266
267 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
268 {
269    int stat;
270    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
271    char esc[MAX_ESCAPE_NAME_LENGTH];
272
273    db_lock(mdb);
274    mdb->db_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
275
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);
280
281    Mmsg(mdb->cmd,
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),
295       pr->ActionOnPurge,
296       ed4);
297    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
298    db_unlock(mdb);
299    return stat;
300 }
301
302 bool
303 db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
304 {
305    int stat;
306    char ed1[50];
307    db_lock(mdb);
308    Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s", 
309       sr->AutoChanger, edit_int64(sr->StorageId, ed1));
310
311    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
312    db_unlock(mdb);
313    return stat;
314 }
315
316
317 /*
318  * Update the Media Record at end of Session
319  *
320  * Returns: 0 on failure
321  *          numrows on success
322  */
323 int
324 db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
325 {
326    char dt[MAX_TIME_LENGTH];
327    time_t ttime;
328    struct tm tm;
329    int stat;
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];
335
336    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
337    db_lock(mdb);
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));
340
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);
350    }
351
352    /* Label just done? */
353    if (mr->set_label_date) {
354       ttime = mr->LabelDate;
355       if (ttime == 0) {
356          ttime = time(NULL);
357       }
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);
363    }
364
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);
372    }
373
374    /* sanity checks for #1066 */
375    if (mr->VolReadTime < 0) {
376       mr->VolReadTime = 0;
377    }
378    if (mr->VolWriteTime < 0) {
379       mr->VolWriteTime = 0;
380    }
381
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),
396         mr->VolParts,
397         mr->LabelType,
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,
407         esc_name);
408
409    Dmsg1(400, "%s\n", mdb->cmd);
410
411    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
412
413    /* Make sure InChanger is 0 for any record having the same Slot */
414    db_make_inchanger_unique(jcr, mdb, mr);
415
416    db_unlock(mdb);
417    return stat;
418 }
419
420 /*
421  * Update the Media Record Default values from Pool
422  *
423  * Returns: 0 on failure
424  *          numrows on success
425  */
426 int
427 db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
428 {
429    int stat;
430    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
431    char esc[MAX_ESCAPE_NAME_LENGTH];
432
433    db_lock(mdb);
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),
445            esc);
446    } else {
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"
450            " WHERE PoolId=%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));
457    }
458
459    Dmsg1(400, "%s\n", mdb->cmd);
460
461    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
462
463    db_unlock(mdb);
464    return stat;
465 }
466
467
468 /*
469  * If we have a non-zero InChanger, ensure that no other Media
470  *  record has InChanger set on the same Slot.
471  *
472  * This routine assumes the database is already locked.
473  */
474 void
475 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
476 {
477    char ed1[50], ed2[50];
478    char esc[MAX_ESCAPE_NAME_LENGTH];
479    if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
480
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",
484                mr->Slot, 
485                edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
486
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'",
491                mr->Slot, 
492                edit_int64(mr->StorageId, ed1), esc);
493
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",
497                mr->Slot, 
498                edit_int64(mr->StorageId, ed1), mr->VolumeName);          
499        }
500        Dmsg1(100, "%s\n", mdb->cmd);
501        UPDATE_DB(jcr, mdb, mdb->cmd);
502    }
503 }
504
505 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */