]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
Fix bug #1810 use single quotes instead of double quotes for MinValue and MaxValue...
[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  *    Version $Id: sql_update.c 8478 2009-02-18 20:11:55Z kerns $
34  */
35
36 #include "bacula.h"
37
38 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
39
40 #include "cats.h"
41 #include "bdb_priv.h"
42 #include "sql_glue.h"
43
44 /* -----------------------------------------------------------------------
45  *
46  *   Generic Routines (or almost generic)
47  *
48  * -----------------------------------------------------------------------
49  */
50
51 /* -----------------------------------------------------------------------
52  *
53  *   Generic Routines (or almost generic)
54  *
55  * -----------------------------------------------------------------------
56  */
57 /* Update the attributes record by adding the file digest */
58 int
59 db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest,
60                           int type)
61 {
62    int ret;
63    char ed1[50];
64    int len = strlen(digest);
65
66    db_lock(mdb);
67    mdb->esc_name = check_pool_memory_size(mdb->esc_name, len*2+1);
68    mdb->db_escape_string(jcr, mdb->esc_name, digest, len); 
69    Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", mdb->esc_name, 
70         edit_int64(FileId, ed1));
71    ret = UPDATE_DB(jcr, mdb, mdb->cmd);
72    db_unlock(mdb);
73    return ret;
74 }
75
76 /* Mark the file record as being visited during database
77  * verify compare. Stuff JobId into the MarkId field
78  */
79 int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId)
80 {
81    int stat;
82    char ed1[50], ed2[50];
83
84    db_lock(mdb);
85    Mmsg(mdb->cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s", 
86       edit_int64(JobId, ed1), edit_int64(FileId, ed2));
87    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
88    db_unlock(mdb);
89    return stat;
90 }
91
92 /*
93  * Update the Job record at start of Job
94  *
95  *  Returns: false on failure
96  *           true  on success
97  */
98 bool
99 db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
100 {
101    char dt[MAX_TIME_LENGTH];
102    time_t stime;
103    struct tm tm;
104    btime_t JobTDate;
105    int stat;
106    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
107
108    stime = jr->StartTime;
109    (void)localtime_r(&stime, &tm);
110    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
111    JobTDate = (btime_t)stime;
112
113    db_lock(mdb);
114    Mmsg(mdb->cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s',"
115 "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s",
116       (char)(jcr->JobStatus),
117       (char)(jr->JobLevel), dt, 
118       edit_int64(jr->ClientId, ed1),
119       edit_uint64(JobTDate, ed2), 
120       edit_int64(jr->PoolId, ed3),
121       edit_int64(jr->FileSetId, ed4),
122       edit_int64(jr->JobId, ed5));
123
124    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
125    mdb->changes = 0;
126    db_unlock(mdb);
127    return stat;
128 }
129
130 /*
131  * Update Long term statistics with all jobs that were run before
132  * age seconds
133  */
134 int
135 db_update_stats(JCR *jcr, B_DB *mdb, utime_t age)
136 {
137    char ed1[30];
138    int rows;
139    utime_t now = (utime_t)time(NULL);
140    edit_uint64(now - age, ed1);
141
142    db_lock(mdb);
143
144    Mmsg(mdb->cmd, fill_jobhisto, ed1);
145    QUERY_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
146    rows = sql_affected_rows(mdb);
147
148    db_unlock(mdb);
149
150    return rows;
151 }
152
153 /*
154  * Update the Job record at end of Job
155  *
156  *  Returns: 0 on failure
157  *           1 on success
158  */
159 int
160 db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
161 {
162    char dt[MAX_TIME_LENGTH];
163    char rdt[MAX_TIME_LENGTH];
164    time_t ttime;
165    struct tm tm;
166    int stat;
167    char ed1[30], ed2[30], ed3[50], ed4[50];
168    btime_t JobTDate;
169    char PriorJobId[50];
170
171    if (jr->PriorJobId) {
172       bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
173    } else {
174       bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
175    }
176
177    ttime = jr->EndTime;
178    (void)localtime_r(&ttime, &tm);
179    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
180
181    if (jr->RealEndTime == 0) {
182       jr->RealEndTime = jr->EndTime;
183    }
184    ttime = jr->RealEndTime;
185    (void)localtime_r(&ttime, &tm);
186    strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
187
188    JobTDate = ttime;
189
190    db_lock(mdb);
191    Mmsg(mdb->cmd,
192       "UPDATE Job SET JobStatus='%c',EndTime='%s',"
193 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
194 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
195 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
196       (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
197       edit_uint64(jr->ReadBytes, ed4),
198       jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
199       jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2), 
200       rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
201       edit_int64(jr->JobId, ed3));
202
203    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
204
205    db_unlock(mdb);
206    return stat;
207 }
208
209 /*
210  * Update Client record
211  *   Returns: 0 on failure
212  *            1 on success
213  */
214 int
215 db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
216 {
217    int stat;
218    char ed1[50], ed2[50];
219    char esc_name[MAX_ESCAPE_NAME_LENGTH];
220    char esc_uname[MAX_ESCAPE_NAME_LENGTH];
221    CLIENT_DBR tcr;
222
223    db_lock(mdb);
224    memcpy(&tcr, cr, sizeof(tcr));
225    if (!db_create_client_record(jcr, mdb, &tcr)) {
226       db_unlock(mdb);
227       return 0;
228    }
229
230    mdb->db_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
231    mdb->db_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
232    Mmsg(mdb->cmd,
233 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
234 "Uname='%s' WHERE Name='%s'",
235       cr->AutoPrune,
236       edit_uint64(cr->FileRetention, ed1),
237       edit_uint64(cr->JobRetention, ed2),
238       esc_uname, esc_name);
239
240    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
241    db_unlock(mdb);
242    return stat;
243 }
244
245
246 /*
247  * Update Counters record
248  *   Returns: 0 on failure
249  *            1 on success
250  */
251 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
252 {
253    char esc[MAX_ESCAPE_NAME_LENGTH];
254    db_lock(mdb);
255    mdb->db_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
256    Mmsg(mdb->cmd,
257 "UPDATE Counters SET 'MinValue'=%d,'MaxValue'=%d,CurrentValue=%d,"
258 "WrapCounter='%s' WHERE Counter='%s'",
259       cr->MinValue, cr->MaxValue, cr->CurrentValue,
260       cr->WrapCounter, esc);
261
262    int stat = UPDATE_DB(jcr, mdb, mdb->cmd);
263    db_unlock(mdb);
264    return stat;
265 }
266
267
268 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
269 {
270    int stat;
271    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
272    char esc[MAX_ESCAPE_NAME_LENGTH];
273
274    db_lock(mdb);
275    mdb->db_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
276
277    Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
278       edit_int64(pr->PoolId, ed4));
279    pr->NumVols = get_sql_record_max(jcr, mdb);
280    Dmsg1(400, "NumVols=%d\n", pr->NumVols);
281
282    Mmsg(mdb->cmd,
283 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
284 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
285 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
286 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s,"
287 "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s",
288       pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
289       pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
290       edit_uint64(pr->VolUseDuration, ed2),
291       pr->MaxVolJobs, pr->MaxVolFiles,
292       edit_uint64(pr->MaxVolBytes, ed3),
293       pr->Recycle, pr->AutoPrune, pr->LabelType,
294       esc, edit_int64(pr->RecyclePoolId,ed5),
295       edit_int64(pr->ScratchPoolId,ed6),
296       pr->ActionOnPurge,
297       ed4);
298    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
299    db_unlock(mdb);
300    return stat;
301 }
302
303 bool
304 db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
305 {
306    int stat;
307    char ed1[50];
308    db_lock(mdb);
309    Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s", 
310       sr->AutoChanger, edit_int64(sr->StorageId, ed1));
311
312    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
313    db_unlock(mdb);
314    return stat;
315 }
316
317
318 /*
319  * Update the Media Record at end of Session
320  *
321  * Returns: 0 on failure
322  *          numrows on success
323  */
324 int
325 db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
326 {
327    char dt[MAX_TIME_LENGTH];
328    time_t ttime;
329    struct tm tm;
330    int stat;
331    char ed1[50], ed2[50],  ed3[50],  ed4[50]; 
332    char ed5[50], ed6[50],  ed7[50],  ed8[50];
333    char ed9[50], ed10[50], ed11[50];
334    char esc_name[MAX_ESCAPE_NAME_LENGTH];
335    char esc_status[MAX_ESCAPE_NAME_LENGTH];
336
337    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
338    db_lock(mdb);
339    mdb->db_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
340    mdb->db_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
341
342    if (mr->set_first_written) {
343       Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
344       ttime = mr->FirstWritten;
345       (void)localtime_r(&ttime, &tm);
346       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
347       Mmsg(mdb->cmd, "UPDATE Media SET FirstWritten='%s'"
348            " WHERE VolumeName='%s'", dt, esc_name);
349       stat = UPDATE_DB(jcr, mdb, mdb->cmd);
350       Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
351    }
352
353    /* Label just done? */
354    if (mr->set_label_date) {
355       ttime = mr->LabelDate;
356       if (ttime == 0) {
357          ttime = time(NULL);
358       }
359       (void)localtime_r(&ttime, &tm);
360       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
361       Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
362            "WHERE VolumeName='%s'", dt, esc_name);
363       UPDATE_DB(jcr, mdb, mdb->cmd);
364    }
365
366    if (mr->LastWritten != 0) {
367       ttime = mr->LastWritten;
368       (void)localtime_r(&ttime, &tm);
369       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
370       Mmsg(mdb->cmd, "UPDATE Media Set LastWritten='%s' "
371            "WHERE VolumeName='%s'", dt, esc_name);
372       UPDATE_DB(jcr, mdb, mdb->cmd);
373    }
374
375    /* sanity checks for #1066 */
376    if (mr->VolReadTime < 0) {
377       mr->VolReadTime = 0;
378    }
379    if (mr->VolWriteTime < 0) {
380       mr->VolWriteTime = 0;
381    }
382
383    Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
384         "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
385         "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
386         "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
387         "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
388         "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
389         "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,ActionOnPurge=%d"
390         " WHERE VolumeName='%s'",
391         mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
392         mr->VolMounts, mr->VolErrors, mr->VolWrites,
393         edit_uint64(mr->MaxVolBytes, ed2),
394         esc_status, mr->Slot, mr->InChanger,
395         edit_int64(mr->VolReadTime, ed3),
396         edit_int64(mr->VolWriteTime, ed4),
397         mr->VolParts,
398         mr->LabelType,
399         edit_int64(mr->StorageId, ed5),
400         edit_int64(mr->PoolId, ed6),
401         edit_uint64(mr->VolRetention, ed7),
402         edit_uint64(mr->VolUseDuration, ed8),
403         mr->MaxVolJobs, mr->MaxVolFiles,
404         mr->Enabled, edit_uint64(mr->LocationId, ed9),
405         edit_uint64(mr->ScratchPoolId, ed10),
406         edit_uint64(mr->RecyclePoolId, ed11),
407         mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
408         esc_name);
409
410    Dmsg1(400, "%s\n", mdb->cmd);
411
412    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
413
414    /* Make sure InChanger is 0 for any record having the same Slot */
415    db_make_inchanger_unique(jcr, mdb, mr);
416
417    db_unlock(mdb);
418    return stat;
419 }
420
421 /*
422  * Update the Media Record Default values from Pool
423  *
424  * Returns: 0 on failure
425  *          numrows on success
426  */
427 int
428 db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
429 {
430    int stat;
431    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
432    char esc[MAX_ESCAPE_NAME_LENGTH];
433
434    db_lock(mdb);
435    if (mr->VolumeName[0]) {
436       mdb->db_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
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 VolumeName='%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_uint64(mr->RecyclePoolId, ed4),
446            esc);
447    } else {
448       Mmsg(mdb->cmd, "UPDATE Media SET "
449            "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
450            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
451            " WHERE PoolId=%s",
452            mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
453            edit_uint64(mr->VolUseDuration, ed2),
454            mr->MaxVolJobs, mr->MaxVolFiles,
455            edit_uint64(mr->MaxVolBytes, ed3),
456            edit_int64(mr->RecyclePoolId, ed4),
457            edit_int64(mr->PoolId, ed5));
458    }
459
460    Dmsg1(400, "%s\n", mdb->cmd);
461
462    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
463
464    db_unlock(mdb);
465    return stat;
466 }
467
468
469 /*
470  * If we have a non-zero InChanger, ensure that no other Media
471  *  record has InChanger set on the same Slot.
472  *
473  * This routine assumes the database is already locked.
474  */
475 void
476 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
477 {
478    char ed1[50], ed2[50];
479    char esc[MAX_ESCAPE_NAME_LENGTH];
480    if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
481
482        if (mr->MediaId != 0) {
483           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
484                "Slot=%d AND StorageId=%s AND MediaId!=%s",
485                mr->Slot, 
486                edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
487
488        } else if (*mr->VolumeName) {
489           mdb->db_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName));
490           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
491                "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
492                mr->Slot, 
493                edit_int64(mr->StorageId, ed1), esc);
494
495        } else {  /* used by ua_label to reset all volume with this slot */
496           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
497                "Slot=%d AND StorageId=%s",
498                mr->Slot, 
499                edit_int64(mr->StorageId, ed1), mr->VolumeName);          
500        }
501        Dmsg1(100, "%s\n", mdb->cmd);
502        UPDATE_DB(jcr, mdb, mdb->cmd);
503    }
504 }
505
506 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */