]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_create.c
e3d4f744971204c94ba1db0aaabeb169a8f77b30
[bacula/bacula] / bacula / src / cats / sql_create.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 Create record interface routines
30  *
31  *    Kern Sibbald, March 2000
32  *
33  *    Version $Id: sql_create.c 8407 2009-01-28 10:47:21Z ricozz $
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 static const int dbglevel = 100;
45
46 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
47
48 /* -----------------------------------------------------------------------
49  *
50  *   Generic Routines (or almost generic)
51  *
52  * -----------------------------------------------------------------------
53  */
54
55 /* Forward referenced subroutines */
56 #ifndef HAVE_BATCH_FILE_INSERT
57 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
58 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
59 #endif /* HAVE_BATCH_FILE_INSERT */
60
61
62 /* Create a new record for the Job
63  * Returns: false on failure
64  *          true  on success
65  */
66 bool
67 db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
68 {
69    char dt[MAX_TIME_LENGTH];
70    time_t stime;
71    struct tm tm;
72    bool ok;
73    utime_t JobTDate;
74    char ed1[30],ed2[30];
75
76    db_lock(mdb);
77
78    stime = jr->SchedTime;
79    ASSERT(stime != 0);
80
81    (void)localtime_r(&stime, &tm);
82    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
83    JobTDate = (utime_t)stime;
84
85    /* Must create it */
86    Mmsg(mdb->cmd,
87 "INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate,ClientId) "
88 "VALUES ('%s','%s','%c','%c','%c','%s',%s,%s)",
89            jr->Job, jr->Name, (char)(jr->JobType), (char)(jr->JobLevel),
90            (char)(jr->JobStatus), dt, edit_uint64(JobTDate, ed1),
91            edit_int64(jr->ClientId, ed2));
92
93    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
94       Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"),
95             mdb->cmd, sql_strerror(mdb));
96       jr->JobId = 0;
97       ok = false;
98    } else {
99       jr->JobId = sql_insert_id(mdb, NT_("Job"));
100       ok = true;
101    }
102    db_unlock(mdb);
103    return ok;
104 }
105
106
107 /* Create a JobMedia record for medium used this job
108  * Returns: false on failure
109  *          true  on success
110  */
111 bool
112 db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
113 {
114    bool ok = true;
115    int count;
116    char ed1[50], ed2[50];
117
118    db_lock(mdb);
119
120    /* Now get count for VolIndex */
121    Mmsg(mdb->cmd, "SELECT count(*) from JobMedia WHERE JobId=%s",
122         edit_int64(jm->JobId, ed1));
123    count = get_sql_record_max(jcr, mdb);
124    if (count < 0) {
125       count = 0;
126    }
127    count++;
128
129    /* Note, jm->Strip is not used and is not likely to be used
130     * in the near future, so I have removed it from the insert
131     * to save space in the DB. KES June 2006.
132     */
133    Mmsg(mdb->cmd,
134         "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,"
135         "StartFile,EndFile,StartBlock,EndBlock,VolIndex) "
136         "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u)",
137         edit_int64(jm->JobId, ed1),
138         edit_int64(jm->MediaId, ed2),
139         jm->FirstIndex, jm->LastIndex,
140         jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count);
141
142    Dmsg0(300, mdb->cmd);
143    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
144       Mmsg2(&mdb->errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), mdb->cmd,
145          sql_strerror(mdb));
146       ok = false;
147    } else {
148       /* Worked, now update the Media record with the EndFile and EndBlock */
149       Mmsg(mdb->cmd,
150            "UPDATE Media SET EndFile=%u, EndBlock=%u WHERE MediaId=%u",
151            jm->EndFile, jm->EndBlock, jm->MediaId);
152       if (!UPDATE_DB(jcr, mdb, mdb->cmd)) {
153          Mmsg2(&mdb->errmsg, _("Update Media record %s failed: ERR=%s\n"), mdb->cmd,
154               sql_strerror(mdb));
155          ok = false;
156       }
157    }
158    db_unlock(mdb);
159    Dmsg0(300, "Return from JobMedia\n");
160    return ok;
161 }
162
163 /* Create Unique Pool record
164  * Returns: false on failure
165  *          true  on success
166  */
167 bool
168 db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
169 {
170    bool stat;        
171    char ed1[30], ed2[30], ed3[50], ed4[50], ed5[50];
172
173    Dmsg0(200, "In create pool\n");
174    db_lock(mdb);
175    Mmsg(mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", pr->Name);
176    Dmsg1(200, "selectpool: %s\n", mdb->cmd);
177
178    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
179       mdb->num_rows = sql_num_rows(mdb);
180       if (mdb->num_rows > 0) {
181          Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pr->Name);
182          sql_free_result(mdb);
183          db_unlock(mdb);
184          return false;
185       }
186       sql_free_result(mdb);
187    }
188
189    /* Must create it */
190    Mmsg(mdb->cmd,
191 "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog,"
192 "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration,"
193 "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat,"
194 "RecyclePoolId,ScratchPoolId,ActionOnPurge) "
195 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s,%s,%d)",
196                   pr->Name,
197                   pr->NumVols, pr->MaxVols,
198                   pr->UseOnce, pr->UseCatalog,
199                   pr->AcceptAnyVolume,
200                   pr->AutoPrune, pr->Recycle,
201                   edit_uint64(pr->VolRetention, ed1),
202                   edit_uint64(pr->VolUseDuration, ed2),
203                   pr->MaxVolJobs, pr->MaxVolFiles,
204                   edit_uint64(pr->MaxVolBytes, ed3),
205                   pr->PoolType, pr->LabelType, pr->LabelFormat,
206                   edit_int64(pr->RecyclePoolId,ed4),
207                   edit_int64(pr->ScratchPoolId,ed5),
208                   pr->ActionOnPurge
209       );
210    Dmsg1(200, "Create Pool: %s\n", mdb->cmd);
211    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
212       Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
213             mdb->cmd, sql_strerror(mdb));
214       pr->PoolId = 0;
215       stat = false;
216    } else {
217       pr->PoolId = sql_insert_id(mdb, NT_("Pool"));
218       stat = true;
219    }
220    db_unlock(mdb);
221    return stat;
222 }
223
224 /*
225  * Create Unique Device record
226  * Returns: false on failure
227  *          true  on success
228  */
229 bool
230 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
231 {
232    bool ok;
233    char ed1[30], ed2[30];
234
235    Dmsg0(200, "In create Device\n");
236    db_lock(mdb);
237    Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
238    Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
239
240    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
241       mdb->num_rows = sql_num_rows(mdb);
242       if (mdb->num_rows > 0) {
243          Mmsg1(&mdb->errmsg, _("Device record %s already exists\n"), dr->Name);
244          sql_free_result(mdb);
245          db_unlock(mdb);
246          return false;
247       }
248       sql_free_result(mdb);
249    }
250
251    /* Must create it */
252    Mmsg(mdb->cmd,
253 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
254                   dr->Name,
255                   edit_uint64(dr->MediaTypeId, ed1),
256                   edit_int64(dr->StorageId, ed2));
257    Dmsg1(200, "Create Device: %s\n", mdb->cmd);
258    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
259       Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
260             mdb->cmd, sql_strerror(mdb));
261       dr->DeviceId = 0;
262       ok = false;
263    } else {
264       dr->DeviceId = sql_insert_id(mdb, NT_("Device"));
265       ok = true;
266    }
267    db_unlock(mdb);
268    return ok;
269 }
270
271
272
273 /*
274  * Create a Unique record for Storage -- no duplicates
275  * Returns: false on failure
276  *          true  on success with id in sr->StorageId
277  */
278 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
279 {
280    SQL_ROW row;
281    bool ok;
282
283    db_lock(mdb);
284    Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
285
286    sr->StorageId = 0;
287    sr->created = false;
288    /* Check if it already exists */
289    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
290       mdb->num_rows = sql_num_rows(mdb);
291       /* If more than one, report error, but return first row */
292       if (mdb->num_rows > 1) {
293          Mmsg1(&mdb->errmsg, _("More than one Storage record!: %d\n"), (int)(mdb->num_rows));
294          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
295       }
296       if (mdb->num_rows >= 1) {
297          if ((row = sql_fetch_row(mdb)) == NULL) {
298             Mmsg1(&mdb->errmsg, _("error fetching Storage row: %s\n"), sql_strerror(mdb));
299             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
300             sql_free_result(mdb);
301             db_unlock(mdb);
302             return false;
303          }
304          sr->StorageId = str_to_int64(row[0]);
305          sr->AutoChanger = atoi(row[1]);   /* bool */
306          sql_free_result(mdb);
307          db_unlock(mdb);
308          return true;
309       }
310       sql_free_result(mdb);
311    }
312
313    /* Must create it */
314    Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
315         " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
316
317    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
318       Mmsg2(&mdb->errmsg, _("Create DB Storage record %s failed. ERR=%s\n"),
319             mdb->cmd, sql_strerror(mdb));
320       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
321       ok = false;
322    } else {
323       sr->StorageId = sql_insert_id(mdb, NT_("Storage"));
324       sr->created = true;
325       ok = true;
326    }
327    db_unlock(mdb);
328    return ok;
329 }
330
331
332 /*
333  * Create Unique MediaType record
334  * Returns: false on failure
335  *          true  on success
336  */
337 bool
338 db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr)
339 {
340    bool stat;        
341
342    Dmsg0(200, "In create mediatype\n");
343    db_lock(mdb);
344    Mmsg(mdb->cmd, "SELECT MediaTypeId,MediaType FROM MediaType WHERE MediaType='%s'", mr->MediaType);
345    Dmsg1(200, "selectmediatype: %s\n", mdb->cmd);
346
347    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
348       mdb->num_rows = sql_num_rows(mdb);
349       if (mdb->num_rows > 0) {
350          Mmsg1(&mdb->errmsg, _("mediatype record %s already exists\n"), mr->MediaType);
351          sql_free_result(mdb);
352          db_unlock(mdb);
353          return false;
354       }
355       sql_free_result(mdb);
356    }
357
358    /* Must create it */
359    Mmsg(mdb->cmd,
360 "INSERT INTO MediaType (MediaType,ReadOnly) "
361 "VALUES ('%s',%d)",
362                   mr->MediaType,
363                   mr->ReadOnly);
364    Dmsg1(200, "Create mediatype: %s\n", mdb->cmd);
365    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
366       Mmsg2(&mdb->errmsg, _("Create db mediatype record %s failed: ERR=%s\n"),
367             mdb->cmd, sql_strerror(mdb));
368       mr->MediaTypeId = 0;
369       stat = false;
370    } else {
371       mr->MediaTypeId = sql_insert_id(mdb, NT_("MediaType"));
372       stat = true;
373    }
374    db_unlock(mdb);
375    return stat;
376 }
377
378
379 /*
380  * Create Media record. VolumeName and non-zero Slot must be unique
381  *
382  * Returns: 0 on failure
383  *          1 on success
384  */
385 int
386 db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
387 {
388    int stat;
389    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
390    char ed9[50], ed10[50], ed11[50], ed12[50];
391    struct tm tm;
392
393    db_lock(mdb);
394    Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName='%s'",
395            mr->VolumeName);
396    Dmsg1(500, "selectpool: %s\n", mdb->cmd);
397
398    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
399       mdb->num_rows = sql_num_rows(mdb);
400       if (mdb->num_rows > 0) {
401          Mmsg1(&mdb->errmsg, _("Volume \"%s\" already exists.\n"), mr->VolumeName);
402          sql_free_result(mdb);
403          db_unlock(mdb);
404          return 0;
405       }
406       sql_free_result(mdb);
407    }
408
409    /* Must create it */
410    Mmsg(mdb->cmd,
411 "INSERT INTO Media (VolumeName,MediaType,MediaTypeId,PoolId,MaxVolBytes,"
412 "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
413 "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts,"
414 "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId,"
415 "ScratchPoolId,RecyclePoolId,Enabled,ActionOnPurge)"
416 "VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s,"
417 "%s,%s,%s,%s,%d,%d)",
418           mr->VolumeName,
419           mr->MediaType, mr->PoolId,
420           edit_uint64(mr->MaxVolBytes,ed1),
421           edit_uint64(mr->VolCapacityBytes, ed2),
422           mr->Recycle,
423           edit_uint64(mr->VolRetention, ed3),
424           edit_uint64(mr->VolUseDuration, ed4),
425           mr->MaxVolJobs,
426           mr->MaxVolFiles,
427           mr->VolStatus,
428           mr->Slot,
429           edit_uint64(mr->VolBytes, ed5),
430           mr->InChanger,
431           edit_int64(mr->VolReadTime, ed6),
432           edit_int64(mr->VolWriteTime, ed7),
433           mr->VolParts,
434           mr->LabelType,
435           edit_int64(mr->StorageId, ed8), 
436           edit_int64(mr->DeviceId, ed9), 
437           edit_int64(mr->LocationId, ed10), 
438           edit_int64(mr->ScratchPoolId, ed11), 
439           edit_int64(mr->RecyclePoolId, ed12), 
440           mr->Enabled, mr->ActionOnPurge
441           );
442
443
444    Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
445    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
446       Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
447             mdb->cmd, sql_strerror(mdb));
448       stat = 0;
449    } else {
450       mr->MediaId = sql_insert_id(mdb, NT_("Media"));
451       stat = 1;
452       if (mr->set_label_date) {
453          char dt[MAX_TIME_LENGTH];
454          if (mr->LabelDate == 0) {
455             mr->LabelDate = time(NULL);
456          }
457          (void)localtime_r(&mr->LabelDate, &tm);
458          strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
459          Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
460               "WHERE MediaId=%d", dt, mr->MediaId);
461          stat = UPDATE_DB(jcr, mdb, mdb->cmd);
462       }
463       /*
464        * Make sure that if InChanger is non-zero any other identical slot
465        *   has InChanger zero.
466        */
467       db_make_inchanger_unique(jcr, mdb, mr);
468    }
469
470    db_unlock(mdb);
471    return stat;
472 }
473
474 /*
475  * Create a Unique record for the client -- no duplicates
476  * Returns: 0 on failure
477  *          1 on success with id in cr->ClientId
478  */
479 int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
480 {
481    SQL_ROW row;
482    int stat;
483    char ed1[50], ed2[50];
484
485    db_lock(mdb);
486    Mmsg(mdb->cmd, "SELECT ClientId,Uname FROM Client WHERE Name='%s'", cr->Name);
487
488    cr->ClientId = 0;
489    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
490       mdb->num_rows = sql_num_rows(mdb);
491       /* If more than one, report error, but return first row */
492       if (mdb->num_rows > 1) {
493          Mmsg1(&mdb->errmsg, _("More than one Client!: %d\n"), (int)(mdb->num_rows));
494          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
495       }
496       if (mdb->num_rows >= 1) {
497          if ((row = sql_fetch_row(mdb)) == NULL) {
498             Mmsg1(&mdb->errmsg, _("error fetching Client row: %s\n"), sql_strerror(mdb));
499             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
500             sql_free_result(mdb);
501             db_unlock(mdb);
502             return 0;
503          }
504          cr->ClientId = str_to_int64(row[0]);
505          if (row[1]) {
506             bstrncpy(cr->Uname, row[1], sizeof(cr->Uname));
507          } else {
508             cr->Uname[0] = 0;         /* no name */
509          }
510          sql_free_result(mdb);
511          db_unlock(mdb);
512          return 1;
513       }
514       sql_free_result(mdb);
515    }
516
517    /* Must create it */
518    Mmsg(mdb->cmd, "INSERT INTO Client (Name,Uname,AutoPrune,"
519 "FileRetention,JobRetention) VALUES "
520 "('%s','%s',%d,%s,%s)", cr->Name, cr->Uname, cr->AutoPrune,
521       edit_uint64(cr->FileRetention, ed1),
522       edit_uint64(cr->JobRetention, ed2));
523
524    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
525       Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
526             mdb->cmd, sql_strerror(mdb));
527       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
528       cr->ClientId = 0;
529       stat = 0;
530    } else {
531       cr->ClientId = sql_insert_id(mdb, NT_("Client"));
532       stat = 1;
533    }
534    db_unlock(mdb);
535    return stat;
536 }
537
538
539 /* Create a Unique record for the Path -- no duplicates */
540 int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
541 {
542    SQL_ROW row;
543    int stat;
544
545    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
546    db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
547
548    if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
549        strcmp(mdb->cached_path, mdb->path) == 0) {
550       ar->PathId = mdb->cached_path_id;
551       return 1;
552    }
553
554    Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
555
556    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
557       mdb->num_rows = sql_num_rows(mdb);
558       if (mdb->num_rows > 1) {
559          char ed1[30];
560          Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
561             edit_uint64(mdb->num_rows, ed1), mdb->path);
562          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
563       }
564       /* Even if there are multiple paths, take the first one */
565       if (mdb->num_rows >= 1) {
566          if ((row = sql_fetch_row(mdb)) == NULL) {
567             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
568             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
569             sql_free_result(mdb);
570             ar->PathId = 0;
571             ASSERT(ar->PathId);
572             return 0;
573          }
574          ar->PathId = str_to_int64(row[0]);
575          sql_free_result(mdb);
576          /* Cache path */
577          if (ar->PathId != mdb->cached_path_id) {
578             mdb->cached_path_id = ar->PathId;
579             mdb->cached_path_len = mdb->pnl;
580             pm_strcpy(mdb->cached_path, mdb->path);
581          }
582          ASSERT(ar->PathId);
583          return 1;
584       }
585       sql_free_result(mdb);
586    }
587
588    Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
589
590    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
591       Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"),
592          mdb->cmd, sql_strerror(mdb));
593       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
594       ar->PathId = 0;
595       stat = 0;
596    } else {
597       ar->PathId = sql_insert_id(mdb, NT_("Path"));
598       stat = 1;
599    }
600
601    /* Cache path */
602    if (stat && ar->PathId != mdb->cached_path_id) {
603       mdb->cached_path_id = ar->PathId;
604       mdb->cached_path_len = mdb->pnl;
605       pm_strcpy(mdb->cached_path, mdb->path);
606    }
607    return stat;
608 }
609
610 /*
611  * Create a Unique record for the counter -- no duplicates
612  * Returns: 0 on failure
613  *          1 on success with counter filled in
614  */
615 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
616 {
617    COUNTER_DBR mcr;
618    int stat;
619
620    db_lock(mdb);
621    memset(&mcr, 0, sizeof(mcr));
622    bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
623    if (db_get_counter_record(jcr, mdb, &mcr)) {
624       memcpy(cr, &mcr, sizeof(COUNTER_DBR));
625       db_unlock(mdb);
626       return 1;
627    }
628
629    /* Must create it */
630    Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue,"
631       "WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
632       cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
633       cr->WrapCounter);
634
635    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
636       Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
637             mdb->cmd, sql_strerror(mdb));
638       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
639       stat = 0;
640    } else {
641       stat = 1;
642    }
643    db_unlock(mdb);
644    return stat;
645 }
646
647
648 /*
649  * Create a FileSet record. This record is unique in the
650  *  name and the MD5 signature of the include/exclude sets.
651  *  Returns: 0 on failure
652  *           1 on success with FileSetId in record
653  */
654 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
655 {
656    SQL_ROW row;
657    bool stat;
658    struct tm tm;
659
660    db_lock(mdb);
661    fsr->created = false;
662    Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
663 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
664
665    fsr->FileSetId = 0;
666    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
667       mdb->num_rows = sql_num_rows(mdb);
668       if (mdb->num_rows > 1) {
669          Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
670          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
671       }
672       if (mdb->num_rows >= 1) {
673          if ((row = sql_fetch_row(mdb)) == NULL) {
674             Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
675             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
676             sql_free_result(mdb);
677             db_unlock(mdb);
678             return false;
679          }
680          fsr->FileSetId = str_to_int64(row[0]);
681          if (row[1] == NULL) {
682             fsr->cCreateTime[0] = 0;
683          } else {
684             bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
685          }
686          sql_free_result(mdb);
687          db_unlock(mdb);
688          return true;
689       }
690       sql_free_result(mdb);
691    }
692
693    if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
694       fsr->CreateTime = time(NULL);
695    }
696    (void)localtime_r(&fsr->CreateTime, &tm);
697    strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
698
699    /* Must create it */
700       Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
701 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
702
703    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
704       Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
705             mdb->cmd, sql_strerror(mdb));
706       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
707       fsr->FileSetId = 0;
708       stat = false;
709    } else {
710       fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet"));
711       fsr->created = true;
712       stat = true;
713    }
714
715    db_unlock(mdb);
716    return stat;
717 }
718
719
720 /*
721  *  struct stat
722  *  {
723  *      dev_t         st_dev;       * device *
724  *      ino_t         st_ino;       * inode *
725  *      mode_t        st_mode;      * protection *
726  *      nlink_t       st_nlink;     * number of hard links *
727  *      uid_t         st_uid;       * user ID of owner *
728  *      gid_t         st_gid;       * group ID of owner *
729  *      dev_t         st_rdev;      * device type (if inode device) *
730  *      off_t         st_size;      * total size, in bytes *
731  *      unsigned long st_blksize;   * blocksize for filesystem I/O *
732  *      unsigned long st_blocks;    * number of blocks allocated *
733  *      time_t        st_atime;     * time of last access *
734  *      time_t        st_mtime;     * time of last modification *
735  *      time_t        st_ctime;     * time of last inode change *
736  *  };
737  */
738
739 #ifdef HAVE_BATCH_FILE_INSERT
740
741 /*  All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path
742  *  tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1"
743  *  in baconfig.h
744  *  
745  *  To sum up :
746  *   - bulk load a temp table
747  *   - insert missing filenames into filename with a single query (lock filenames 
748  *   - table before that to avoid possible duplicate inserts with concurrent update)
749  *   - insert missing paths into path with another single query
750  *   - then insert the join between the temp, filename and path tables into file.
751  */
752
753 /* 
754  * Returns 1 if OK
755  *         0 if failed
756  */
757 bool my_batch_start(JCR *jcr, B_DB *mdb)
758 {
759    bool ok;
760
761    db_lock(mdb);
762    ok =  db_sql_query(mdb,
763              "CREATE TEMPORARY TABLE batch ("
764                 "FileIndex integer,"
765                 "JobId integer,"
766                 "Path blob,"
767                 "Name blob,"
768                 "LStat tinyblob,"
769                 "MD5 tinyblob)",NULL, NULL);
770    db_unlock(mdb);
771    return ok;
772 }
773
774 /* 
775  * Returns 1 if OK
776  *         0 if failed
777  */
778 bool my_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
779 {
780    size_t len;
781    const char *digest;
782    char ed1[50];
783
784    mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
785    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
786
787    mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
788    db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
789
790    if (ar->Digest == NULL || ar->Digest[0] == 0) {
791       digest = "0";
792    } else {
793       digest = ar->Digest;
794    }
795
796    len = Mmsg(mdb->cmd, "INSERT INTO batch VALUES (%u,%s,'%s','%s','%s','%s')",
797               ar->FileIndex, edit_int64(ar->JobId,ed1), mdb->esc_path, 
798               mdb->esc_name, ar->attr, digest);
799
800    return INSERT_DB(jcr, mdb, mdb->cmd);
801 }
802
803 /* set error to something to abort operation */
804 /* 
805  * Returns 1 if OK
806  *         0 if failed
807  */
808 bool my_batch_end(JCR *jcr, B_DB *mdb, const char *error)
809 {
810    
811    Dmsg0(50, "sql_batch_end started\n");
812
813    if (mdb) {
814 #ifdef HAVE_DBI 
815       mdb->status = (dbi_error_flag)0;
816 #else
817       mdb->status = 0;
818 #endif
819    }
820    return true;
821 }
822
823 /* 
824  * Returns 1 if OK
825  *         0 if failed
826  */
827 bool db_write_batch_file_records(JCR *jcr)
828 {
829    int JobStatus = jcr->JobStatus;
830
831    if (!jcr->batch_started) {         /* no files to backup ? */
832       Dmsg0(50,"db_create_file_record : no files\n");
833       return true;
834    }
835    if (job_canceled(jcr)) {
836       return false;
837    }
838
839    Dmsg1(50,"db_create_file_record changes=%u\n",jcr->db_batch->changes);
840
841    jcr->JobStatus = JS_AttrInserting;
842    if (!sql_batch_end(jcr, jcr->db_batch, NULL)) {
843       Jmsg1(jcr, M_FATAL, 0, "Batch end %s\n", jcr->db_batch->errmsg);
844       return false;
845    }
846    if (job_canceled(jcr)) {
847       return false;
848    }
849
850
851    /* we have to lock tables */
852    if (!db_sql_query(jcr->db_batch, sql_batch_lock_path_query, NULL, NULL)) {
853       Jmsg1(jcr, M_FATAL, 0, "Lock Path table %s\n", jcr->db_batch->errmsg);
854       return false;
855    }
856
857    if (!db_sql_query(jcr->db_batch, sql_batch_fill_path_query, NULL, NULL)) {
858       Jmsg1(jcr, M_FATAL, 0, "Fill Path table %s\n",jcr->db_batch->errmsg);
859       db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
860       return false;
861    }
862    
863    if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
864       Jmsg1(jcr, M_FATAL, 0, "Unlock Path table %s\n", jcr->db_batch->errmsg);
865       return false;      
866    }
867
868    /* we have to lock tables */
869    if (!db_sql_query(jcr->db_batch,sql_batch_lock_filename_query,NULL, NULL)) {
870       Jmsg1(jcr, M_FATAL, 0, "Lock Filename table %s\n", jcr->db_batch->errmsg);
871       return false;
872    }
873    
874    if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) {
875       Jmsg1(jcr,M_FATAL,0,"Fill Filename table %s\n",jcr->db_batch->errmsg);
876       db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
877       return false;            
878    }
879
880    if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
881       Jmsg1(jcr, M_FATAL, 0, "Unlock Filename table %s\n", jcr->db_batch->errmsg);
882       return false;
883    }
884    
885    if (!db_sql_query(jcr->db_batch, 
886        "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
887          "SELECT batch.FileIndex, batch.JobId, Path.PathId, "
888                 "Filename.FilenameId,batch.LStat, batch.MD5 "
889            "FROM batch "
890            "JOIN Path ON (batch.Path = Path.Path) "
891            "JOIN Filename ON (batch.Name = Filename.Name)",
892                      NULL,NULL))
893    {
894       Jmsg1(jcr, M_FATAL, 0, "Fill File table %s\n", jcr->db_batch->errmsg);
895       return false;
896    }
897
898    db_sql_query(jcr->db_batch, "DROP TABLE batch", NULL,NULL);
899
900    jcr->JobStatus = JobStatus;         /* reset entry status */
901    return true;
902 }
903
904 /*
905  * Create File record in B_DB
906  *
907  *  In order to reduce database size, we store the File attributes,
908  *  the FileName, and the Path separately.  In principle, there
909  *  is a single FileName record and a single Path record, no matter
910  *  how many times it occurs.  This is this subroutine, we separate
911  *  the file and the path and fill temporary tables with this three records.
912  *
913  *  Note: all routines that call this expect to be able to call
914  *    db_strerror(mdb) to get the error message, so the error message
915  *    MUST be edited into mdb->errmsg before returning an error status.
916  */
917 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
918 {
919    ASSERT(ar->FileType != FT_BASE);
920
921    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
922    Dmsg0(dbglevel, "put_file_into_catalog\n");
923
924    /* Open the dedicated connexion */
925    if (!jcr->batch_started) {
926       if (!db_open_batch_connexion(jcr, mdb)) {
927          return false;     /* error already printed */
928       }
929       if (!sql_batch_start(jcr, jcr->db_batch)) {
930          Mmsg1(&mdb->errmsg, 
931               "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
932          Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
933          return false;
934       }
935       jcr->batch_started = true;
936    }
937    B_DB *bdb = jcr->db_batch;
938
939    split_path_and_file(jcr, bdb, ar->fname);
940
941
942 /*
943  * if (bdb->changes > 100000) {
944  *    db_write_batch_file_records(jcr);
945  *    bdb->changes = 0;
946  *     sql_batch_start(jcr, bdb);
947  * }
948  */
949
950    return sql_batch_insert(jcr, bdb, ar);
951 }
952
953 #else  /* ! HAVE_BATCH_FILE_INSERT */
954
955 /*
956  * Create File record in B_DB
957  *
958  *  In order to reduce database size, we store the File attributes,
959  *  the FileName, and the Path separately.  In principle, there
960  *  is a single FileName record and a single Path record, no matter
961  *  how many times it occurs.  This is this subroutine, we separate
962  *  the file and the path and create three database records.
963  */
964 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
965 {
966    db_lock(mdb);
967    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
968    Dmsg0(dbglevel, "put_file_into_catalog\n");
969
970    split_path_and_file(jcr, mdb, ar->fname);
971
972    if (!db_create_filename_record(jcr, mdb, ar)) {
973       goto bail_out;
974    }
975    Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
976
977
978    if (!db_create_path_record(jcr, mdb, ar)) {
979       goto bail_out;
980    }
981    Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
982
983    /* Now create master File record */
984    if (!db_create_file_record(jcr, mdb, ar)) {
985       goto bail_out;
986    }
987    Dmsg0(dbglevel, "db_create_file_record OK\n");
988
989    Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
990    db_unlock(mdb);
991    return true;
992
993 bail_out:
994    db_unlock(mdb);
995    return false;
996 }
997
998
999 /*
1000  * This is the master File entry containing the attributes.
1001  *  The filename and path records have already been created.
1002  */
1003 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1004 {
1005    int stat;
1006    static const char *no_digest = "0";
1007    const char *digest;
1008
1009    ASSERT(ar->JobId);
1010    ASSERT(ar->PathId);
1011    ASSERT(ar->FilenameId);
1012
1013    if (ar->Digest == NULL || ar->Digest[0] == 0) {
1014       digest = no_digest;
1015    } else {
1016       digest = ar->Digest;
1017    }
1018
1019    /* Must create it */
1020    Mmsg(mdb->cmd,
1021         "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
1022         "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
1023         ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
1024         ar->attr, digest);
1025
1026    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1027       Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
1028          mdb->cmd, sql_strerror(mdb));
1029       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1030       ar->FileId = 0;
1031       stat = 0;
1032    } else {
1033       ar->FileId = sql_insert_id(mdb, NT_("File"));
1034       stat = 1;
1035    }
1036    return stat;
1037 }
1038
1039 /* Create a Unique record for the filename -- no duplicates */
1040 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1041 {
1042    SQL_ROW row;
1043
1044    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
1045    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1046    
1047    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
1048
1049    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1050       mdb->num_rows = sql_num_rows(mdb);
1051       if (mdb->num_rows > 1) {
1052          char ed1[30];
1053          Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
1054             edit_uint64(mdb->num_rows, ed1), mdb->fname);
1055          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1056       }
1057       if (mdb->num_rows >= 1) {
1058          if ((row = sql_fetch_row(mdb)) == NULL) {
1059             Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
1060                 mdb->fname, sql_strerror(mdb));
1061             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1062             ar->FilenameId = 0;
1063          } else {
1064             ar->FilenameId = str_to_int64(row[0]);
1065          }
1066          sql_free_result(mdb);
1067          return ar->FilenameId > 0;
1068       }
1069       sql_free_result(mdb);
1070    }
1071
1072    Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
1073
1074    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1075       Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
1076             mdb->cmd, sql_strerror(mdb));
1077       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1078       ar->FilenameId = 0;
1079    } else {
1080       ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
1081    }
1082    return ar->FilenameId > 0;
1083 }
1084
1085 bool db_write_batch_file_records(JCR *jcr)
1086 {
1087    return true;
1088 }
1089
1090 #endif /* ! HAVE_BATCH_FILE_INSERT */
1091
1092
1093 /* List of SQL commands to create temp table and indicies  */
1094 const char *create_temp_basefile[5] = {
1095    /* MySQL */
1096    "CREATE TEMPORARY TABLE basefile%lld ("
1097 //   "CREATE TABLE basefile%lld ("
1098    "Path BLOB NOT NULL,"
1099    "Name BLOB NOT NULL)",
1100
1101    /* Postgresql */
1102    "CREATE TEMPORARY TABLE basefile%lld (" 
1103 //   "CREATE TABLE basefile%lld (" 
1104    "Path TEXT,"
1105    "Name TEXT)",
1106
1107    /* SQLite */
1108    "CREATE TEMPORARY TABLE basefile%lld (" 
1109    "Path TEXT,"
1110    "Name TEXT)",
1111
1112    /* SQLite3 */
1113    "CREATE TEMPORARY TABLE basefile%lld (" 
1114    "Path TEXT,"
1115    "Name TEXT)",
1116
1117    /* Ingres */
1118    "DECLARE GLOBAL TEMPORARY TABLE basefile%lld (" 
1119    "Path TEXT NOT NULL,"
1120    "Name TEXT NOT NULL)"
1121    "ON COMMIT PRESERVE ROWS WITH NORECOVERY"
1122 };
1123
1124 /* 
1125  * Create file attributes record, or base file attributes record
1126  */
1127 bool db_create_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1128 {
1129    bool ret;
1130
1131    /*
1132     * Make sure we have an acceptable attributes record.
1133     */
1134    if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
1135          ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
1136       Jmsg(jcr, M_FATAL, 0, _("Attempt to put non-attributes into catalog. Stream=%d\n"));
1137       return false;
1138    }
1139
1140    if (ar->FileType != FT_BASE) {
1141       ret = db_create_file_attributes_record(jcr, mdb, ar);
1142
1143    } else if (jcr->HasBase) {
1144       ret = db_create_base_file_attributes_record(jcr, mdb, ar);
1145
1146    } else {
1147       Jmsg0(jcr, M_FATAL, 0, _("Can't Copy/Migrate job using BaseJob"));
1148       ret = true;               /* in copy/migration what do we do ? */
1149    }
1150
1151    return ret;
1152 }
1153
1154 /*
1155  * Create Base File record in B_DB
1156  *
1157  */
1158 bool db_create_base_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1159 {
1160    bool ret;
1161    Dmsg1(dbglevel, "create_base_file Fname=%s\n", ar->fname);
1162    Dmsg0(dbglevel, "put_base_file_into_catalog\n");
1163
1164    db_lock(mdb); 
1165    split_path_and_file(jcr, mdb, ar->fname);
1166    
1167    mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
1168    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1169    
1170    mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
1171    db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
1172    
1173    Mmsg(mdb->cmd, "INSERT INTO basefile%lld (Path, Name) VALUES ('%s','%s')",
1174         (uint64_t)jcr->JobId, mdb->esc_path, mdb->esc_name);
1175
1176    ret = INSERT_DB(jcr, mdb, mdb->cmd);
1177    db_unlock(mdb);
1178
1179    return ret;
1180 }
1181
1182 /* 
1183  * Cleanup the base file temporary tables
1184  */
1185 static void db_cleanup_base_file(JCR *jcr, B_DB *mdb)
1186 {
1187    POOL_MEM buf(PM_MESSAGE);
1188    Mmsg(buf, "DROP TABLE new_basefile%lld", (uint64_t) jcr->JobId);
1189    db_sql_query(mdb, buf.c_str(), NULL, NULL);
1190
1191    Mmsg(buf, "DROP TABLE basefile%lld", (uint64_t) jcr->JobId);
1192    db_sql_query(mdb, buf.c_str(), NULL, NULL);
1193 }
1194
1195 /*
1196  * Put all base file seen in the backup to the BaseFile table
1197  * and cleanup temporary tables
1198  */
1199 bool db_commit_base_file_attributes_record(JCR *jcr, B_DB *mdb)
1200 {
1201    bool ret;
1202    char ed1[50];
1203
1204    db_lock(mdb);
1205
1206    Mmsg(mdb->cmd, 
1207   "INSERT INTO BaseFiles (BaseJobId, JobId, FileId, FileIndex) "
1208    "SELECT B.JobId AS BaseJobId, %s AS JobId, "
1209           "B.FileId, B.FileIndex "
1210      "FROM basefile%s AS A, new_basefile%s AS B "
1211     "WHERE A.Path = B.Path "
1212       "AND A.Name = B.Name "
1213     "ORDER BY B.FileId", 
1214         edit_uint64(jcr->JobId, ed1), ed1, ed1);
1215    ret = db_sql_query(mdb, mdb->cmd, NULL, NULL);
1216    jcr->nb_base_files_used = sql_affected_rows(mdb);
1217    db_cleanup_base_file(jcr, mdb);
1218
1219    db_unlock(mdb);
1220    return ret;
1221 }
1222
1223 /*
1224  * Find the last "accurate" backup state with Base jobs
1225  * 1) Get all files with jobid in list (F subquery) 
1226  * 2) Take only the last version of each file (Temp subquery) => accurate list is ok
1227  * 3) Put the result in a temporary table for the end of job
1228  *
1229  */
1230 bool db_create_base_file_list(JCR *jcr, B_DB *mdb, char *jobids)
1231 {
1232    POOL_MEM buf;
1233    bool ret=false;
1234
1235    db_lock(mdb);   
1236
1237    if (!*jobids) {
1238       Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
1239       goto bail_out;
1240    }
1241
1242    Mmsg(mdb->cmd, create_temp_basefile[db_type], (uint64_t) jcr->JobId);
1243    if (!db_sql_query(mdb, mdb->cmd, NULL, NULL)) {
1244       goto bail_out;
1245    }
1246    /* Quick and dirty fix for MySQL and Bacula 5.0.1 */
1247 #ifdef HAVE_MYSQL
1248    Mmsg(mdb->cmd, 
1249         "CREATE INDEX basefile%lld_idx ON basefile%lld (Path(255), Name(255))", 
1250         (uint64_t) jcr->JobId, (uint64_t) jcr->JobId);
1251    if (!db_sql_query(mdb, mdb->cmd, NULL, NULL)) {
1252       goto bail_out;
1253    }
1254 #endif
1255    Mmsg(buf, select_recent_version[db_type], jobids, jobids);
1256    Mmsg(mdb->cmd,
1257 "CREATE TEMPORARY TABLE new_basefile%lld AS  "
1258 //"CREATE TABLE new_basefile%lld AS "
1259   "SELECT Path.Path AS Path, Filename.Name AS Name, Temp.FileIndex AS FileIndex,"
1260          "Temp.JobId AS JobId, Temp.LStat AS LStat, Temp.FileId AS FileId, "
1261          "Temp.MD5 AS MD5 "
1262   "FROM ( %s ) AS Temp "
1263   "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
1264   "JOIN Path ON (Path.PathId = Temp.PathId) "
1265  "WHERE Temp.FileIndex > 0",
1266         (uint64_t)jcr->JobId, buf.c_str());
1267
1268    ret = db_sql_query(mdb, mdb->cmd, NULL, NULL);
1269 bail_out:
1270    db_unlock(mdb);
1271    return ret;
1272 }
1273
1274 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */