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