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