]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
ebl Apply jobstat patch to add longterm statistics
[bacula/bacula] / bacula / src / cats / sql_update.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 John Walker.
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    Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
360         "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
361         "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
362         "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
363         "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
364         "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
365         "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d"
366         " WHERE VolumeName='%s'",
367         mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
368         mr->VolMounts, mr->VolErrors, mr->VolWrites,
369         edit_uint64(mr->MaxVolBytes, ed2),
370         mr->VolStatus, mr->Slot, mr->InChanger,
371         edit_int64(mr->VolReadTime, ed3),
372         edit_int64(mr->VolWriteTime, ed4),
373         mr->VolParts,
374         mr->LabelType,
375         edit_int64(mr->StorageId, ed5),
376         edit_int64(mr->PoolId, ed6),
377         edit_uint64(mr->VolRetention, ed7),
378         edit_uint64(mr->VolUseDuration, ed8),
379         mr->MaxVolJobs, mr->MaxVolFiles,
380         mr->Enabled, edit_uint64(mr->LocationId, ed9),
381         edit_uint64(mr->ScratchPoolId, ed10),
382         edit_uint64(mr->RecyclePoolId, ed11),
383         mr->RecycleCount,
384         mr->VolumeName);
385
386    Dmsg1(400, "%s\n", mdb->cmd);
387
388    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
389
390    /* Make sure InChanger is 0 for any record having the same Slot */
391    db_make_inchanger_unique(jcr, mdb, mr);
392
393    db_unlock(mdb);
394    return stat;
395 }
396
397 /*
398  * Update the Media Record Default values from Pool
399  *
400  * Returns: 0 on failure
401  *          numrows on success
402  */
403 int
404 db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
405 {
406    int stat;
407    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
408
409
410    db_lock(mdb);
411    if (mr->VolumeName[0]) {
412       Mmsg(mdb->cmd, "UPDATE Media SET "
413            "Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
414            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
415            " WHERE VolumeName='%s'",
416            mr->Recycle,edit_uint64(mr->VolRetention, ed1),
417            edit_uint64(mr->VolUseDuration, ed2),
418            mr->MaxVolJobs, mr->MaxVolFiles,
419            edit_uint64(mr->MaxVolBytes, ed3),
420            edit_uint64(mr->RecyclePoolId, ed4),
421            mr->VolumeName);
422    } else {
423       Mmsg(mdb->cmd, "UPDATE Media SET "
424            "Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
425            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
426            " WHERE PoolId=%s",
427            mr->Recycle,edit_uint64(mr->VolRetention, ed1),
428            edit_uint64(mr->VolUseDuration, ed2),
429            mr->MaxVolJobs, mr->MaxVolFiles,
430            edit_uint64(mr->MaxVolBytes, ed3),
431            edit_int64(mr->RecyclePoolId, ed4),
432            edit_int64(mr->PoolId, ed5));
433    }
434
435    Dmsg1(400, "%s\n", mdb->cmd);
436
437    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
438
439    db_unlock(mdb);
440    return stat;
441 }
442
443
444 /*
445  * If we have a non-zero InChanger, ensure that no other Media
446  *  record has InChanger set on the same Slot.
447  *
448  * This routine assumes the database is already locked.
449  */
450 void
451 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
452 {
453    char ed1[50], ed2[50];
454    if (mr->InChanger != 0 && mr->Slot != 0) {
455       Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0 WHERE "
456            "Slot=%d AND StorageId=%s AND MediaId!=%s",
457             mr->Slot, 
458             edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
459       Dmsg1(400, "%s\n", mdb->cmd);
460       UPDATE_DB(jcr, mdb, mdb->cmd);
461    }
462 }
463
464 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/