]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
Switch from GPLv2 to AGPLv3
[bacula/bacula] / bacula / src / cats / sql_update.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 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 /* The following is necessary so that we do not include
37  * the dummy external definition of DB.
38  */
39 #define __SQL_C                       /* indicate that this is sql.c */
40
41 #include "bacula.h"
42 #include "cats.h"
43
44 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
45
46 /* -----------------------------------------------------------------------
47  *
48  *   Generic Routines (or almost generic)
49  *
50  * -----------------------------------------------------------------------
51  */
52
53 /* -----------------------------------------------------------------------
54  *
55  *   Generic Routines (or almost generic)
56  *
57  * -----------------------------------------------------------------------
58  */
59 /* Update the attributes record by adding the file digest */
60 int
61 db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest,
62                           int type)
63 {
64    int stat;
65    char ed1[50];
66
67    db_lock(mdb);
68    Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", digest, 
69       edit_int64(FileId, ed1));
70    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
71    db_unlock(mdb);
72    return stat;
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    utime_t now = (utime_t)time(NULL);
138    edit_uint64(now - age, ed1);
139
140    Mmsg(mdb->cmd, fill_jobhisto, ed1);
141    QUERY_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
142    return sql_affected_rows(mdb);
143 }
144
145 /*
146  * Update the Job record at end of Job
147  *
148  *  Returns: 0 on failure
149  *           1 on success
150  */
151 int
152 db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
153 {
154    char dt[MAX_TIME_LENGTH];
155    char rdt[MAX_TIME_LENGTH];
156    time_t ttime;
157    struct tm tm;
158    int stat;
159    char ed1[30], ed2[30], ed3[50], ed4[50];
160    btime_t JobTDate;
161    char PriorJobId[50];
162
163    if (jr->PriorJobId) {
164       bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
165    } else {
166       bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
167    }
168
169    ttime = jr->EndTime;
170    (void)localtime_r(&ttime, &tm);
171    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
172
173    if (jr->RealEndTime == 0) {
174       jr->RealEndTime = jr->EndTime;
175    }
176    ttime = jr->RealEndTime;
177    (void)localtime_r(&ttime, &tm);
178    strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
179
180    JobTDate = ttime;
181
182    db_lock(mdb);
183    Mmsg(mdb->cmd,
184       "UPDATE Job SET JobStatus='%c',EndTime='%s',"
185 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
186 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
187 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
188       (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
189       edit_uint64(jr->ReadBytes, ed4),
190       jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
191       jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2), 
192       rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
193       edit_int64(jr->JobId, ed3));
194
195    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
196
197    db_unlock(mdb);
198    return stat;
199 }
200
201 /*
202  * Update Client record
203  *   Returns: 0 on failure
204  *            1 on success
205  */
206 int
207 db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
208 {
209    int stat;
210    char ed1[50], ed2[50];
211    CLIENT_DBR tcr;
212
213    db_lock(mdb);
214    memcpy(&tcr, cr, sizeof(tcr));
215    if (!db_create_client_record(jcr, mdb, &tcr)) {
216       db_unlock(mdb);
217       return 0;
218    }
219
220    Mmsg(mdb->cmd,
221 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
222 "Uname='%s' WHERE Name='%s'",
223       cr->AutoPrune,
224       edit_uint64(cr->FileRetention, ed1),
225       edit_uint64(cr->JobRetention, ed2),
226       cr->Uname, cr->Name);
227
228    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
229    db_unlock(mdb);
230    return stat;
231 }
232
233
234 /*
235  * Update Counters record
236  *   Returns: 0 on failure
237  *            1 on success
238  */
239 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
240 {
241    db_lock(mdb);
242
243    Mmsg(mdb->cmd,
244 "UPDATE Counters SET MinValue=%d,MaxValue=%d,CurrentValue=%d,"
245 "WrapCounter='%s' WHERE Counter='%s'",
246       cr->MinValue, cr->MaxValue, cr->CurrentValue,
247       cr->WrapCounter, cr->Counter);
248
249    int stat = UPDATE_DB(jcr, mdb, mdb->cmd);
250    db_unlock(mdb);
251    return stat;
252 }
253
254
255 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
256 {
257    int stat;
258    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
259
260    db_lock(mdb);
261    Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
262       edit_int64(pr->PoolId, ed4));
263    pr->NumVols = get_sql_record_max(jcr, mdb);
264    Dmsg1(400, "NumVols=%d\n", pr->NumVols);
265
266    Mmsg(mdb->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       pr->LabelFormat, edit_int64(pr->RecyclePoolId,ed5),
279       edit_int64(pr->ScratchPoolId,ed6),
280       pr->ActionOnPurge,
281       ed4);
282    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
283    db_unlock(mdb);
284    return stat;
285 }
286
287 bool
288 db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
289 {
290    int stat;
291    char ed1[50];
292    db_lock(mdb);
293    Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s", 
294       sr->AutoChanger, edit_int64(sr->StorageId, ed1));
295
296    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
297    db_unlock(mdb);
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
309 db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
310 {
311    char dt[MAX_TIME_LENGTH];
312    time_t ttime;
313    struct tm tm;
314    int stat;
315    char ed1[50], ed2[50],  ed3[50],  ed4[50]; 
316    char ed5[50], ed6[50],  ed7[50],  ed8[50];
317    char ed9[50], ed10[50], ed11[50];
318
319
320    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
321    db_lock(mdb);
322    if (mr->set_first_written) {
323       Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
324       ttime = mr->FirstWritten;
325       (void)localtime_r(&ttime, &tm);
326       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
327       Mmsg(mdb->cmd, "UPDATE Media SET FirstWritten='%s'"
328            " WHERE VolumeName='%s'", dt, mr->VolumeName);
329       stat = UPDATE_DB(jcr, mdb, mdb->cmd);
330       Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
331    }
332
333    /* Label just done? */
334    if (mr->set_label_date) {
335       ttime = mr->LabelDate;
336       if (ttime == 0) {
337          ttime = time(NULL);
338       }
339       (void)localtime_r(&ttime, &tm);
340       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
341       Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
342            "WHERE VolumeName='%s'", dt, mr->VolumeName);
343       UPDATE_DB(jcr, mdb, mdb->cmd);
344    }
345
346    if (mr->LastWritten != 0) {
347       ttime = mr->LastWritten;
348       (void)localtime_r(&ttime, &tm);
349       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
350       Mmsg(mdb->cmd, "UPDATE Media Set LastWritten='%s' "
351            "WHERE VolumeName='%s'", dt, mr->VolumeName);
352       UPDATE_DB(jcr, mdb, mdb->cmd);
353    }
354
355    /* sanity checks for #1066 */
356    if (mr->VolReadTime < 0) {
357       mr->VolReadTime = 0;
358    }
359    if (mr->VolWriteTime < 0) {
360       mr->VolWriteTime = 0;
361    }
362
363    Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
364         "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
365         "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
366         "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
367         "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
368         "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
369         "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,ActionOnPurge=%d"
370         " WHERE VolumeName='%s'",
371         mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
372         mr->VolMounts, mr->VolErrors, mr->VolWrites,
373         edit_uint64(mr->MaxVolBytes, ed2),
374         mr->VolStatus, mr->Slot, mr->InChanger,
375         edit_int64(mr->VolReadTime, ed3),
376         edit_int64(mr->VolWriteTime, ed4),
377         mr->VolParts,
378         mr->LabelType,
379         edit_int64(mr->StorageId, ed5),
380         edit_int64(mr->PoolId, ed6),
381         edit_uint64(mr->VolRetention, ed7),
382         edit_uint64(mr->VolUseDuration, ed8),
383         mr->MaxVolJobs, mr->MaxVolFiles,
384         mr->Enabled, edit_uint64(mr->LocationId, ed9),
385         edit_uint64(mr->ScratchPoolId, ed10),
386         edit_uint64(mr->RecyclePoolId, ed11),
387         mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
388         mr->VolumeName);
389
390    Dmsg1(400, "%s\n", mdb->cmd);
391
392    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
393
394    /* Make sure InChanger is 0 for any record having the same Slot */
395    db_make_inchanger_unique(jcr, mdb, mr);
396
397    db_unlock(mdb);
398    return stat;
399 }
400
401 /*
402  * Update the Media Record Default values from Pool
403  *
404  * Returns: 0 on failure
405  *          numrows on success
406  */
407 int
408 db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
409 {
410    int stat;
411    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
412
413
414    db_lock(mdb);
415    if (mr->VolumeName[0]) {
416       Mmsg(mdb->cmd, "UPDATE Media SET "
417            "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
418            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
419            " WHERE VolumeName='%s'",
420            mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
421            edit_uint64(mr->VolUseDuration, ed2),
422            mr->MaxVolJobs, mr->MaxVolFiles,
423            edit_uint64(mr->MaxVolBytes, ed3),
424            edit_uint64(mr->RecyclePoolId, ed4),
425            mr->VolumeName);
426    } else {
427       Mmsg(mdb->cmd, "UPDATE Media SET "
428            "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
429            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
430            " WHERE PoolId=%s",
431            mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
432            edit_uint64(mr->VolUseDuration, ed2),
433            mr->MaxVolJobs, mr->MaxVolFiles,
434            edit_uint64(mr->MaxVolBytes, ed3),
435            edit_int64(mr->RecyclePoolId, ed4),
436            edit_int64(mr->PoolId, ed5));
437    }
438
439    Dmsg1(400, "%s\n", mdb->cmd);
440
441    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
442
443    db_unlock(mdb);
444    return stat;
445 }
446
447
448 /*
449  * If we have a non-zero InChanger, ensure that no other Media
450  *  record has InChanger set on the same Slot.
451  *
452  * This routine assumes the database is already locked.
453  */
454 void
455 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
456 {
457    char ed1[50], ed2[50];
458    if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
459
460        if (mr->MediaId != 0) {
461           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
462                "Slot=%d AND StorageId=%s AND MediaId!=%s",
463                mr->Slot, 
464                edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
465
466        } else if (*mr->VolumeName) {
467           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
468                "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
469                mr->Slot, 
470                edit_int64(mr->StorageId, ed1), mr->VolumeName);
471
472        } else {  /* used by ua_label to reset all volume with this slot */
473           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
474                "Slot=%d AND StorageId=%s",
475                mr->Slot, 
476                edit_int64(mr->StorageId, ed1), mr->VolumeName);          
477        }
478        Dmsg1(100, "%s\n", mdb->cmd);
479        UPDATE_DB(jcr, mdb, mdb->cmd);
480    }
481 }
482
483 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES */