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