]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
Attempt to fix bug #1128 InChanger flag cleared during Migration
[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 two of the GNU 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 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$
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_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];
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 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->JobId, ed4));
121
122    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
123    mdb->changes = 0;
124    db_unlock(mdb);
125    return stat;
126 }
127
128 /*
129  * Given an incoming integer, set the string buffer to either NULL or the value
130  *
131  */
132 static void edit_num_or_null(char *s, size_t n, uint64_t id) {
133    char ed1[50];
134    bsnprintf(s, n, id ? "%s" : "NULL", edit_int64(id, ed1));
135 }
136
137
138 /*
139  * Update the Job record at end of Job
140  *
141  *  Returns: 0 on failure
142  *           1 on success
143  */
144 int
145 db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, bool stats_enabled)
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];
153    btime_t JobTDate;
154    char PoolId[50], FileSetId[50], ClientId[50], PriorJobId[50];
155
156
157    /* some values are set to zero, which translates to NULL in SQL */
158    edit_num_or_null(PoolId,    sizeof(PoolId),    jr->PoolId);
159    edit_num_or_null(FileSetId, sizeof(FileSetId), jr->FileSetId);
160    edit_num_or_null(ClientId,  sizeof(ClientId),  jr->ClientId);
161
162    if (jr->PriorJobId) {
163       bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
164    } else {
165       bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
166    }
167
168    ttime = jr->EndTime;
169    (void)localtime_r(&ttime, &tm);
170    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
171
172    if (jr->RealEndTime == 0) {
173       jr->RealEndTime = jr->EndTime;
174    }
175    ttime = jr->RealEndTime;
176    (void)localtime_r(&ttime, &tm);
177    strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
178
179    JobTDate = ttime;
180
181    db_lock(mdb);
182    Mmsg(mdb->cmd,
183       "UPDATE Job SET JobStatus='%c',EndTime='%s',"
184 "ClientId=%s,JobBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
185 "VolSessionTime=%u,PoolId=%s,FileSetId=%s,JobTDate=%s,"
186 "RealEndTime='%s',PriorJobId=%s WHERE JobId=%s",
187       (char)(jr->JobStatus), dt, ClientId, edit_uint64(jr->JobBytes, ed1),
188       jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
189       PoolId, FileSetId, edit_uint64(JobTDate, ed2), 
190       rdt,
191       PriorJobId,
192       edit_int64(jr->JobId, ed3));
193
194    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
195
196    if (stat && stats_enabled) {
197       Mmsg(mdb->cmd,
198            "INSERT INTO JobStat (SELECT * FROM Job WHERE JobId=%s)",
199            edit_int64(jr->JobId, ed3));
200       INSERT_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
201    }
202    db_unlock(mdb);
203    return stat;
204 }
205
206 /*
207  * Update Client record
208  *   Returns: 0 on failure
209  *            1 on success
210  */
211 int
212 db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
213 {
214    int stat;
215    char ed1[50], ed2[50];
216    CLIENT_DBR tcr;
217
218    db_lock(mdb);
219    memcpy(&tcr, cr, sizeof(tcr));
220    if (!db_create_client_record(jcr, mdb, &tcr)) {
221       db_unlock(mdb);
222       return 0;
223    }
224
225    Mmsg(mdb->cmd,
226 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
227 "Uname='%s' WHERE Name='%s'",
228       cr->AutoPrune,
229       edit_uint64(cr->FileRetention, ed1),
230       edit_uint64(cr->JobRetention, ed2),
231       cr->Uname, cr->Name);
232
233    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
234    db_unlock(mdb);
235    return stat;
236 }
237
238
239 /*
240  * Update Counters record
241  *   Returns: 0 on failure
242  *            1 on success
243  */
244 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
245 {
246    db_lock(mdb);
247
248    Mmsg(mdb->cmd,
249 "UPDATE Counters SET MinValue=%d,MaxValue=%d,CurrentValue=%d,"
250 "WrapCounter='%s' WHERE Counter='%s'",
251       cr->MinValue, cr->MaxValue, cr->CurrentValue,
252       cr->WrapCounter, cr->Counter);
253
254    int stat = UPDATE_DB(jcr, mdb, mdb->cmd);
255    db_unlock(mdb);
256    return stat;
257 }
258
259
260 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
261 {
262    int stat;
263    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
264
265    db_lock(mdb);
266    Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
267       edit_int64(pr->PoolId, ed4));
268    pr->NumVols = get_sql_record_max(jcr, mdb);
269    Dmsg1(400, "NumVols=%d\n", pr->NumVols);
270
271    Mmsg(mdb->cmd,
272 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
273 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
274 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
275 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s WHERE PoolId=%s",
276       pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
277       pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
278       edit_uint64(pr->VolUseDuration, ed2),
279       pr->MaxVolJobs, pr->MaxVolFiles,
280       edit_uint64(pr->MaxVolBytes, ed3),
281       pr->Recycle, pr->AutoPrune, pr->LabelType,
282       pr->LabelFormat, edit_int64(pr->RecyclePoolId,ed5),
283       ed4);
284
285    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
286    db_unlock(mdb);
287    return stat;
288 }
289
290 bool
291 db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
292 {
293    int stat;
294    char ed1[50];
295
296    db_lock(mdb);
297    Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s", 
298       sr->AutoChanger, edit_int64(sr->StorageId, ed1));
299
300    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
301    db_unlock(mdb);
302    return stat;
303 }
304
305
306 /*
307  * Update the Media Record at end of Session
308  *
309  * Returns: 0 on failure
310  *          numrows on success
311  */
312 int
313 db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
314 {
315    char dt[MAX_TIME_LENGTH];
316    time_t ttime;
317    struct tm tm;
318    int stat;
319    char ed1[50], ed2[50],  ed3[50],  ed4[50]; 
320    char ed5[50], ed6[50],  ed7[50],  ed8[50];
321    char ed9[50], ed10[50], ed11[50];
322
323
324    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
325    db_lock(mdb);
326    if (mr->set_first_written) {
327       Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
328       ttime = mr->FirstWritten;
329       (void)localtime_r(&ttime, &tm);
330       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
331       Mmsg(mdb->cmd, "UPDATE Media SET FirstWritten='%s'"
332            " WHERE VolumeName='%s'", dt, mr->VolumeName);
333       stat = UPDATE_DB(jcr, mdb, mdb->cmd);
334       Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
335    }
336
337    /* Label just done? */
338    if (mr->set_label_date) {
339       ttime = mr->LabelDate;
340       if (ttime == 0) {
341          ttime = time(NULL);
342       }
343       (void)localtime_r(&ttime, &tm);
344       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
345       Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
346            "WHERE VolumeName='%s'", dt, mr->VolumeName);
347       UPDATE_DB(jcr, mdb, mdb->cmd);
348    }
349
350    if (mr->LastWritten != 0) {
351       ttime = mr->LastWritten;
352       (void)localtime_r(&ttime, &tm);
353       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
354       Mmsg(mdb->cmd, "UPDATE Media Set LastWritten='%s' "
355            "WHERE VolumeName='%s'", dt, mr->VolumeName);
356       UPDATE_DB(jcr, mdb, mdb->cmd);
357    }
358
359    /* sanity checks for #1066 */
360    if (mr->VolReadTime < 0) {
361       mr->VolReadTime = 0;
362    }
363    if (mr->VolWriteTime < 0) {
364       mr->VolWriteTime = 0;
365    }
366
367    Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
368         "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
369         "VolWrites=%u,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"
374         " WHERE VolumeName='%s'",
375         mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
376         mr->VolMounts, mr->VolErrors, mr->VolWrites,
377         edit_uint64(mr->MaxVolBytes, ed2),
378         mr->VolStatus, mr->Slot, mr->InChanger,
379         edit_int64(mr->VolReadTime, ed3),
380         edit_int64(mr->VolWriteTime, ed4),
381         mr->VolParts,
382         mr->LabelType,
383         edit_int64(mr->StorageId, ed5),
384         edit_int64(mr->PoolId, ed6),
385         edit_uint64(mr->VolRetention, ed7),
386         edit_uint64(mr->VolUseDuration, ed8),
387         mr->MaxVolJobs, mr->MaxVolFiles,
388         mr->Enabled, edit_uint64(mr->LocationId, ed9),
389         edit_uint64(mr->ScratchPoolId, ed10),
390         edit_uint64(mr->RecyclePoolId, ed11),
391         mr->RecycleCount,
392         mr->VolumeName);
393
394    Dmsg1(400, "%s\n", mdb->cmd);
395
396    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
397
398    /* Make sure InChanger is 0 for any record having the same Slot */
399    db_make_inchanger_unique(jcr, mdb, mr);
400
401    db_unlock(mdb);
402    return stat;
403 }
404
405 /*
406  * Update the Media Record Default values from Pool
407  *
408  * Returns: 0 on failure
409  *          numrows on success
410  */
411 int
412 db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
413 {
414    int stat;
415    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
416
417
418    db_lock(mdb);
419    if (mr->VolumeName[0]) {
420       Mmsg(mdb->cmd, "UPDATE Media SET "
421            "Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
422            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
423            " WHERE VolumeName='%s'",
424            mr->Recycle,edit_uint64(mr->VolRetention, ed1),
425            edit_uint64(mr->VolUseDuration, ed2),
426            mr->MaxVolJobs, mr->MaxVolFiles,
427            edit_uint64(mr->MaxVolBytes, ed3),
428            edit_uint64(mr->RecyclePoolId, ed4),
429            mr->VolumeName);
430    } else {
431       Mmsg(mdb->cmd, "UPDATE Media SET "
432            "Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
433            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
434            " WHERE PoolId=%s",
435            mr->Recycle,edit_uint64(mr->VolRetention, ed1),
436            edit_uint64(mr->VolUseDuration, ed2),
437            mr->MaxVolJobs, mr->MaxVolFiles,
438            edit_uint64(mr->MaxVolBytes, ed3),
439            edit_int64(mr->RecyclePoolId, ed4),
440            edit_int64(mr->PoolId, ed5));
441    }
442
443    Dmsg1(400, "%s\n", mdb->cmd);
444
445    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
446
447    db_unlock(mdb);
448    return stat;
449 }
450
451
452 /*
453  * If we have a non-zero InChanger, ensure that no other Media
454  *  record has InChanger set on the same Slot.
455  *
456  * This routine assumes the database is already locked.
457  */
458 void
459 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
460 {
461    char ed1[50], ed2[50];
462    if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0 &&
463        mr->MediaId != 0) {
464       Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0 WHERE "
465            "Slot=%d AND StorageId=%s AND MediaId!=%s",
466             mr->Slot, 
467             edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
468       Dmsg1(400, "%s\n", mdb->cmd);
469       UPDATE_DB(jcr, mdb, mdb->cmd);
470    }
471 }
472
473 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/