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