]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_create.c
Merge branch 'master' into basejobv3
[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 = 100;
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,ActionOnPurge) "
196 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s,%s,%d)",
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                   pr->ActionOnPurge
210       );
211    Dmsg1(200, "Create Pool: %s\n", mdb->cmd);
212    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
213       Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
214             mdb->cmd, sql_strerror(mdb));
215       pr->PoolId = 0;
216       stat = false;
217    } else {
218       pr->PoolId = sql_insert_id(mdb, NT_("Pool"));
219       stat = true;
220    }
221    db_unlock(mdb);
222    return stat;
223 }
224
225 /*
226  * Create Unique Device record
227  * Returns: false on failure
228  *          true  on success
229  */
230 bool
231 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
232 {
233    bool ok;
234    char ed1[30], ed2[30];
235
236    Dmsg0(200, "In create Device\n");
237    db_lock(mdb);
238    Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
239    Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
240
241    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
242       mdb->num_rows = sql_num_rows(mdb);
243       if (mdb->num_rows > 0) {
244          Mmsg1(&mdb->errmsg, _("Device record %s already exists\n"), dr->Name);
245          sql_free_result(mdb);
246          db_unlock(mdb);
247          return false;
248       }
249       sql_free_result(mdb);
250    }
251
252    /* Must create it */
253    Mmsg(mdb->cmd,
254 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
255                   dr->Name,
256                   edit_uint64(dr->MediaTypeId, ed1),
257                   edit_int64(dr->StorageId, ed2));
258    Dmsg1(200, "Create Device: %s\n", mdb->cmd);
259    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
260       Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
261             mdb->cmd, sql_strerror(mdb));
262       dr->DeviceId = 0;
263       ok = false;
264    } else {
265       dr->DeviceId = sql_insert_id(mdb, NT_("Device"));
266       ok = true;
267    }
268    db_unlock(mdb);
269    return ok;
270 }
271
272
273
274 /*
275  * Create a Unique record for Storage -- no duplicates
276  * Returns: false on failure
277  *          true  on success with id in sr->StorageId
278  */
279 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
280 {
281    SQL_ROW row;
282    bool ok;
283
284    db_lock(mdb);
285    Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
286
287    sr->StorageId = 0;
288    sr->created = false;
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 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
914 {
915    ASSERT(ar->FileType != FT_BASE);
916
917    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
918    Dmsg0(dbglevel, "put_file_into_catalog\n");
919
920    /* Open the dedicated connexion */
921    if (!jcr->batch_started) {
922
923       if (!db_open_batch_connexion(jcr, mdb)) {
924          return false;
925       }
926       if (!sql_batch_start(jcr, jcr->db_batch)) {
927          Mmsg1(&mdb->errmsg, 
928               "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
929          Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
930          return false;
931       }
932       jcr->batch_started = true;
933    }
934    B_DB *bdb = jcr->db_batch;
935
936    split_path_and_file(jcr, bdb, ar->fname);
937
938
939 /*
940  * if (bdb->changes > 100000) {
941  *    db_write_batch_file_records(jcr);
942  *    bdb->changes = 0;
943  *     sql_batch_start(jcr, bdb);
944  * }
945  */
946
947    return sql_batch_insert(jcr, bdb, ar);
948 }
949
950 #else  /* ! HAVE_BATCH_FILE_INSERT */
951
952 /*
953  * Create File record in B_DB
954  *
955  *  In order to reduce database size, we store the File attributes,
956  *  the FileName, and the Path separately.  In principle, there
957  *  is a single FileName record and a single Path record, no matter
958  *  how many times it occurs.  This is this subroutine, we separate
959  *  the file and the path and create three database records.
960  */
961 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
962 {
963    db_lock(mdb);
964    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
965    Dmsg0(dbglevel, "put_file_into_catalog\n");
966
967    split_path_and_file(jcr, mdb, ar->fname);
968
969    if (!db_create_filename_record(jcr, mdb, ar)) {
970       goto bail_out;
971    }
972    Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
973
974
975    if (!db_create_path_record(jcr, mdb, ar)) {
976       goto bail_out;
977    }
978    Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
979
980    /* Now create master File record */
981    if (!db_create_file_record(jcr, mdb, ar)) {
982       goto bail_out;
983    }
984    Dmsg0(dbglevel, "db_create_file_record OK\n");
985
986    Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
987    db_unlock(mdb);
988    return true;
989
990 bail_out:
991    db_unlock(mdb);
992    return false;
993 }
994
995
996 /*
997  * This is the master File entry containing the attributes.
998  *  The filename and path records have already been created.
999  */
1000 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1001 {
1002    int stat;
1003    static const char *no_digest = "0";
1004    const char *digest;
1005
1006    ASSERT(ar->JobId);
1007    ASSERT(ar->PathId);
1008    ASSERT(ar->FilenameId);
1009
1010    if (ar->Digest == NULL || ar->Digest[0] == 0) {
1011       digest = no_digest;
1012    } else {
1013       digest = ar->Digest;
1014    }
1015
1016    /* Must create it */
1017    Mmsg(mdb->cmd,
1018         "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
1019         "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
1020         ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
1021         ar->attr, digest);
1022
1023    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1024       Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
1025          mdb->cmd, sql_strerror(mdb));
1026       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1027       ar->FileId = 0;
1028       stat = 0;
1029    } else {
1030       ar->FileId = sql_insert_id(mdb, NT_("File"));
1031       stat = 1;
1032    }
1033    return stat;
1034 }
1035
1036 /* Create a Unique record for the filename -- no duplicates */
1037 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1038 {
1039    SQL_ROW row;
1040
1041    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
1042    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1043    
1044    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
1045
1046    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1047       mdb->num_rows = sql_num_rows(mdb);
1048       if (mdb->num_rows > 1) {
1049          char ed1[30];
1050          Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
1051             edit_uint64(mdb->num_rows, ed1), mdb->fname);
1052          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1053       }
1054       if (mdb->num_rows >= 1) {
1055          if ((row = sql_fetch_row(mdb)) == NULL) {
1056             Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
1057                 mdb->fname, sql_strerror(mdb));
1058             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1059             ar->FilenameId = 0;
1060          } else {
1061             ar->FilenameId = str_to_int64(row[0]);
1062          }
1063          sql_free_result(mdb);
1064          return ar->FilenameId > 0;
1065       }
1066       sql_free_result(mdb);
1067    }
1068
1069    Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
1070
1071    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1072       Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
1073             mdb->cmd, sql_strerror(mdb));
1074       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1075       ar->FilenameId = 0;
1076    } else {
1077       ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
1078    }
1079    return ar->FilenameId > 0;
1080 }
1081
1082 bool db_write_batch_file_records(JCR *jcr)
1083 {
1084    return true;
1085 }
1086
1087 #endif /* ! HAVE_BATCH_FILE_INSERT */
1088
1089
1090 /* List of SQL commands to create temp table and indicies  */
1091 const char *create_temp_basefile[4] = {
1092    /* MySQL */
1093    "CREATE TEMPORARY TABLE basefile%lld ("
1094 //   "CREATE TABLE basefile%lld ("
1095    "Path BLOB NOT NULL,"
1096    "Name BLOB NOT NULL)",
1097
1098    /* Postgresql */
1099    "CREATE TEMPORARY TABLE basefile%lld (" 
1100 //   "CREATE TABLE basefile%lld (" 
1101    "Path TEXT,"
1102    "Name TEXT)",
1103
1104    /* SQLite */
1105    "CREATE TEMPORARY TABLE basefile%lld (" 
1106    "Path TEXT,"
1107    "Name TEXT)",
1108
1109    /* SQLite3 */
1110    "CREATE TEMPORARY TABLE basefile%lld (" 
1111    "Path TEXT,"
1112    "Name TEXT)"
1113 };
1114
1115 /* 
1116  * Create file attributes record, or base file attributes record
1117  */
1118 bool db_create_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1119 {
1120    bool ret;
1121
1122    /*
1123     * Make sure we have an acceptable attributes record.
1124     */
1125    if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
1126          ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
1127       Jmsg(jcr, M_FATAL, 0, _("Attempt to put non-attributes into catalog. Stream=%d\n"));
1128       return false;
1129    }
1130
1131    if (ar->FileType != FT_BASE) {
1132       ret = db_create_file_attributes_record(jcr, mdb, ar);
1133
1134    } else if (jcr->HasBase) {
1135       ret = db_create_base_file_attributes_record(jcr, mdb, ar);
1136
1137    } else {
1138       Jmsg0(jcr, M_FATAL, 0, _("Can't Copy/Migrate job using BaseJob"));
1139       ret = true;               /* in copy/migration what do we do ? */
1140    }
1141
1142    return ret;
1143 }
1144
1145 /*
1146  * Create Base File record in B_DB
1147  *
1148  */
1149 bool db_create_base_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1150 {
1151    bool ret;
1152    Dmsg1(dbglevel, "create_base_file Fname=%s\n", ar->fname);
1153    Dmsg0(dbglevel, "put_base_file_into_catalog\n");
1154
1155    db_lock(mdb); 
1156    split_path_and_file(jcr, mdb, ar->fname);
1157    
1158    mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
1159    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1160    
1161    mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
1162    db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
1163    
1164    Mmsg(mdb->cmd, "INSERT INTO basefile%lld (Path, Name) VALUES ('%s','%s')",
1165         (uint64_t)jcr->JobId, mdb->esc_path, mdb->esc_name);
1166
1167    ret = INSERT_DB(jcr, mdb, mdb->cmd);
1168    db_unlock(mdb);
1169
1170    return ret;
1171 }
1172
1173 /* 
1174  * Cleanup the base file temporary tables
1175  */
1176 static void db_cleanup_base_file(JCR *jcr, B_DB *mdb)
1177 {
1178    POOL_MEM buf(PM_MESSAGE);
1179    Mmsg(buf, "DROP TABLE new_basefile%lld", (uint64_t) jcr->JobId);
1180    db_sql_query(mdb, buf.c_str(), NULL, NULL);
1181
1182    Mmsg(buf, "DROP TABLE basefile%lld", (uint64_t) jcr->JobId);
1183    db_sql_query(mdb, buf.c_str(), NULL, NULL);
1184 }
1185
1186 /*
1187  * Put all base file seen in the backup to the BaseFile table
1188  * and cleanup temporary tables
1189  */
1190 bool db_commit_base_file_attributes_record(JCR *jcr, B_DB *mdb)
1191 {
1192    bool ret;
1193    char ed1[50];
1194
1195    db_lock(mdb);
1196
1197    Mmsg(mdb->cmd, 
1198   "INSERT INTO BaseFiles (BaseJobId, JobId, FileId, FileIndex) "
1199    "SELECT B.JobId AS BaseJobId, %s AS JobId, "
1200           "B.FileId, B.FileIndex "
1201      "FROM basefile%s AS A, new_basefile%s AS B "
1202     "WHERE A.Path = B.Path "
1203       "AND A.Name = B.Name "
1204     "ORDER BY B.FileId", 
1205         edit_uint64(jcr->JobId, ed1), ed1, ed1);
1206    ret = QUERY_DB(jcr, mdb, mdb->cmd);
1207    jcr->nb_base_files_used = sql_affected_rows(mdb);
1208    db_cleanup_base_file(jcr, mdb);
1209
1210    db_unlock(mdb);
1211    return ret;
1212 }
1213
1214 /*
1215  * Find the last "accurate" backup state with Base jobs
1216  * 1) Get all files with jobid in list (F subquery) 
1217  * 2) Take only the last version of each file (Temp subquery) => accurate list is ok
1218  * 3) Put the result in a temporary table for the end of job
1219  *
1220  */
1221 bool db_create_base_file_list(JCR *jcr, B_DB *mdb, char *jobids)
1222 {
1223    POOL_MEM buf;
1224    bool ret=false;
1225
1226    db_lock(mdb);   
1227
1228    if (!*jobids) {
1229       Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
1230       goto bail_out;
1231    }
1232
1233    Mmsg(mdb->cmd, create_temp_basefile[db_type], (uint64_t) jcr->JobId);
1234    if (!db_sql_query(mdb, mdb->cmd, NULL, NULL)) {
1235       goto bail_out;
1236    }
1237    Mmsg(buf, select_recent_version[db_type], jobids, jobids);
1238    Mmsg(mdb->cmd,
1239 "CREATE TEMPORARY TABLE new_basefile%lld AS  "
1240 //"CREATE TABLE new_basefile%lld AS "
1241   "SELECT Path.Path AS Path, Filename.Name AS Name, Temp.FileIndex AS FileIndex,"
1242          "Temp.JobId AS JobId, Temp.LStat AS LStat, Temp.FileId AS FileId, "
1243          "Temp.MD5 AS MD5 "
1244   "FROM ( %s ) AS Temp "
1245   "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
1246   "JOIN Path ON (Path.PathId = Temp.PathId) "
1247  "WHERE Temp.FileIndex > 0",
1248         (uint64_t)jcr->JobId, buf.c_str());
1249
1250    ret = db_sql_query(mdb, mdb->cmd, NULL, NULL);
1251 bail_out:
1252    db_unlock(mdb);
1253    return ret;
1254 }
1255
1256 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */