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