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