]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_create.c
1998aebec74814f00270b3d6aee166e7cb231dd4
[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 three of the GNU Affero 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 Affero 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    Mmsg(mdb->cmd,
135         "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,"
136         "StartFile,EndFile,StartBlock,EndBlock,VolIndex) "
137         "VALUES (%s,%s,%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
143    Dmsg0(300, mdb->cmd);
144    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
145       Mmsg2(&mdb->errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), mdb->cmd,
146          sql_strerror(mdb));
147       ok = false;
148    } else {
149       /* Worked, now update the Media record with the EndFile and EndBlock */
150       Mmsg(mdb->cmd,
151            "UPDATE Media SET EndFile=%u, EndBlock=%u WHERE MediaId=%u",
152            jm->EndFile, jm->EndBlock, jm->MediaId);
153       if (!UPDATE_DB(jcr, mdb, mdb->cmd)) {
154          Mmsg2(&mdb->errmsg, _("Update Media record %s failed: ERR=%s\n"), mdb->cmd,
155               sql_strerror(mdb));
156          ok = false;
157       }
158    }
159    db_unlock(mdb);
160    Dmsg0(300, "Return from JobMedia\n");
161    return ok;
162 }
163
164 /** Create Unique Pool record
165  *  Returns: false on failure
166  *          true  on success
167  */
168 bool
169 db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
170 {
171    bool stat;        
172    char ed1[30], ed2[30], ed3[50], ed4[50], ed5[50];
173
174    Dmsg0(200, "In create pool\n");
175    db_lock(mdb);
176    Mmsg(mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", pr->Name);
177    Dmsg1(200, "selectpool: %s\n", mdb->cmd);
178
179    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
180       mdb->num_rows = sql_num_rows(mdb);
181       if (mdb->num_rows > 0) {
182          Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pr->Name);
183          sql_free_result(mdb);
184          db_unlock(mdb);
185          return false;
186       }
187       sql_free_result(mdb);
188    }
189
190    /* Must create it */
191    Mmsg(mdb->cmd,
192 "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog,"
193 "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration,"
194 "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat,"
195 "RecyclePoolId,ScratchPoolId,ActionOnPurge) "
196 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s,%s,%d)",
197                   pr->Name,
198                   pr->NumVols, pr->MaxVols,
199                   pr->UseOnce, pr->UseCatalog,
200                   pr->AcceptAnyVolume,
201                   pr->AutoPrune, pr->Recycle,
202                   edit_uint64(pr->VolRetention, ed1),
203                   edit_uint64(pr->VolUseDuration, ed2),
204                   pr->MaxVolJobs, pr->MaxVolFiles,
205                   edit_uint64(pr->MaxVolBytes, ed3),
206                   pr->PoolType, pr->LabelType, pr->LabelFormat,
207                   edit_int64(pr->RecyclePoolId,ed4),
208                   edit_int64(pr->ScratchPoolId,ed5),
209                   pr->ActionOnPurge
210       );
211    Dmsg1(200, "Create Pool: %s\n", mdb->cmd);
212    pr->PoolId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Pool"));
213    if (pr->PoolId == 0) {
214       Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
215             mdb->cmd, sql_strerror(mdb));
216       stat = false;
217    } else {
218       stat = true;
219    }
220    db_unlock(mdb);
221    Dmsg0(500, "Create Pool: done\n");
222    return stat;
223 }
224
225 /**
226  * Create Unique Device record
227  * Returns: false on failure
228  *          true  on success
229  */
230 bool
231 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
232 {
233    bool ok;
234    char ed1[30], ed2[30];
235
236    Dmsg0(200, "In create Device\n");
237    db_lock(mdb);
238    Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
239    Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
240
241    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
242       mdb->num_rows = sql_num_rows(mdb);
243       if (mdb->num_rows > 0) {
244          Mmsg1(&mdb->errmsg, _("Device record %s already exists\n"), dr->Name);
245          sql_free_result(mdb);
246          db_unlock(mdb);
247          return false;
248       }
249       sql_free_result(mdb);
250    }
251
252    /* Must create it */
253    Mmsg(mdb->cmd,
254 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
255                   dr->Name,
256                   edit_uint64(dr->MediaTypeId, ed1),
257                   edit_int64(dr->StorageId, ed2));
258    Dmsg1(200, "Create Device: %s\n", mdb->cmd);
259    dr->DeviceId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Device"));
260    if (dr->DeviceId == 0) {
261       Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
262             mdb->cmd, sql_strerror(mdb));
263       ok = false;
264    } else {
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    /* Check if it already exists */
289    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
290       mdb->num_rows = sql_num_rows(mdb);
291       /* If more than one, report error, but return first row */
292       if (mdb->num_rows > 1) {
293          Mmsg1(&mdb->errmsg, _("More than one Storage record!: %d\n"), (int)(mdb->num_rows));
294          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
295       }
296       if (mdb->num_rows >= 1) {
297          if ((row = sql_fetch_row(mdb)) == NULL) {
298             Mmsg1(&mdb->errmsg, _("error fetching Storage row: %s\n"), sql_strerror(mdb));
299             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
300             sql_free_result(mdb);
301             db_unlock(mdb);
302             return false;
303          }
304          sr->StorageId = str_to_int64(row[0]);
305          sr->AutoChanger = atoi(row[1]);   /* bool */
306          sql_free_result(mdb);
307          db_unlock(mdb);
308          return true;
309       }
310       sql_free_result(mdb);
311    }
312
313    /* Must create it */
314    Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
315         " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
316
317    sr->StorageId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Storage"));
318    if (sr->StorageId == 0) {
319       Mmsg2(&mdb->errmsg, _("Create DB Storage record %s failed. ERR=%s\n"),
320             mdb->cmd, sql_strerror(mdb));
321       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
322       ok = false;
323    } else {
324       sr->created = true;
325       ok = true;
326    }
327    db_unlock(mdb);
328    return ok;
329 }
330
331
332 /**
333  * Create Unique MediaType record
334  * Returns: false on failure
335  *          true  on success
336  */
337 bool
338 db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr)
339 {
340    bool stat;        
341
342    Dmsg0(200, "In create mediatype\n");
343    db_lock(mdb);
344    Mmsg(mdb->cmd, "SELECT MediaTypeId,MediaType FROM MediaType WHERE MediaType='%s'", mr->MediaType);
345    Dmsg1(200, "selectmediatype: %s\n", mdb->cmd);
346
347    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
348       mdb->num_rows = sql_num_rows(mdb);
349       if (mdb->num_rows > 0) {
350          Mmsg1(&mdb->errmsg, _("mediatype record %s already exists\n"), mr->MediaType);
351          sql_free_result(mdb);
352          db_unlock(mdb);
353          return false;
354       }
355       sql_free_result(mdb);
356    }
357
358    /* Must create it */
359    Mmsg(mdb->cmd,
360 "INSERT INTO MediaType (MediaType,ReadOnly) "
361 "VALUES ('%s',%d)",
362                   mr->MediaType,
363                   mr->ReadOnly);
364    Dmsg1(200, "Create mediatype: %s\n", mdb->cmd);
365    mr->MediaTypeId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("MediaType"));
366    if (mr->MediaTypeId == 0) {
367       Mmsg2(&mdb->errmsg, _("Create db mediatype record %s failed: ERR=%s\n"),
368             mdb->cmd, sql_strerror(mdb));
369       stat = false;
370    } else {
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,ActionOnPurge)"
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,%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, mr->ActionOnPurge
440           );
441
442
443    Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
444    mr->MediaId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Media"));
445    if (mr->MediaId == 0) {
446       Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
447             mdb->cmd, sql_strerror(mdb));
448       stat = 0;
449    } else {
450       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    cr->ClientId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Client"));
524    if (cr->ClientId == 0) {
525       Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
526             mdb->cmd, sql_strerror(mdb));
527       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
528       stat = 0;
529    } else {
530       stat = 1;
531    }
532    db_unlock(mdb);
533    return stat;
534 }
535
536
537 /** Create a Unique record for the Path -- no duplicates */
538 int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
539 {
540    SQL_ROW row;
541    int stat;
542
543    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
544    db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
545
546    if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
547        strcmp(mdb->cached_path, mdb->path) == 0) {
548       ar->PathId = mdb->cached_path_id;
549       return 1;
550    }
551
552    Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
553
554    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
555       mdb->num_rows = sql_num_rows(mdb);
556       if (mdb->num_rows > 1) {
557          char ed1[30];
558          Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
559             edit_uint64(mdb->num_rows, ed1), mdb->path);
560          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
561       }
562       /* Even if there are multiple paths, take the first one */
563       if (mdb->num_rows >= 1) {
564          if ((row = sql_fetch_row(mdb)) == NULL) {
565             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
566             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
567             sql_free_result(mdb);
568             ar->PathId = 0;
569             ASSERT(ar->PathId);
570             return 0;
571          }
572          ar->PathId = str_to_int64(row[0]);
573          sql_free_result(mdb);
574          /* Cache path */
575          if (ar->PathId != mdb->cached_path_id) {
576             mdb->cached_path_id = ar->PathId;
577             mdb->cached_path_len = mdb->pnl;
578             pm_strcpy(mdb->cached_path, mdb->path);
579          }
580          ASSERT(ar->PathId);
581          return 1;
582       }
583       sql_free_result(mdb);
584    }
585
586    Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
587
588    ar->PathId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Path"));
589    if (ar->PathId == 0) {
590       Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"),
591          mdb->cmd, sql_strerror(mdb));
592       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
593       ar->PathId = 0;
594       stat = 0;
595    } else {
596       stat = 1;
597    }
598
599    /* Cache path */
600    if (stat && ar->PathId != mdb->cached_path_id) {
601       mdb->cached_path_id = ar->PathId;
602       mdb->cached_path_len = mdb->pnl;
603       pm_strcpy(mdb->cached_path, mdb->path);
604    }
605    return stat;
606 }
607
608 /**
609  * Create a Unique record for the counter -- no duplicates
610  * Returns: 0 on failure
611  *          1 on success with counter filled in
612  */
613 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
614 {
615    COUNTER_DBR mcr;
616    int stat;
617
618    db_lock(mdb);
619    memset(&mcr, 0, sizeof(mcr));
620    bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
621    if (db_get_counter_record(jcr, mdb, &mcr)) {
622       memcpy(cr, &mcr, sizeof(COUNTER_DBR));
623       db_unlock(mdb);
624       return 1;
625    }
626
627    /* Must create it */
628    Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,\"MinValue\",\"MaxValue\",CurrentValue,"
629       "WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
630       cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
631       cr->WrapCounter);
632
633    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
634       Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
635             mdb->cmd, sql_strerror(mdb));
636       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
637       stat = 0;
638    } else {
639       stat = 1;
640    }
641    db_unlock(mdb);
642    return stat;
643 }
644
645
646 /**
647  * Create a FileSet record. This record is unique in the
648  *  name and the MD5 signature of the include/exclude sets.
649  *  Returns: 0 on failure
650  *           1 on success with FileSetId in record
651  */
652 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
653 {
654    SQL_ROW row;
655    bool stat;
656    struct tm tm;
657
658    db_lock(mdb);
659    fsr->created = false;
660    Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
661 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
662
663    fsr->FileSetId = 0;
664    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
665       mdb->num_rows = sql_num_rows(mdb);
666       if (mdb->num_rows > 1) {
667          Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
668          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
669       }
670       if (mdb->num_rows >= 1) {
671          if ((row = sql_fetch_row(mdb)) == NULL) {
672             Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
673             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
674             sql_free_result(mdb);
675             db_unlock(mdb);
676             return false;
677          }
678          fsr->FileSetId = str_to_int64(row[0]);
679          if (row[1] == NULL) {
680             fsr->cCreateTime[0] = 0;
681          } else {
682             bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
683          }
684          sql_free_result(mdb);
685          db_unlock(mdb);
686          return true;
687       }
688       sql_free_result(mdb);
689    }
690
691    if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
692       fsr->CreateTime = time(NULL);
693    }
694    (void)localtime_r(&fsr->CreateTime, &tm);
695    strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
696
697    /* Must create it */
698       Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
699 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
700
701    fsr->FileSetId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("FileSet"));
702    if (fsr->FileSetId == 0) {
703       Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
704             mdb->cmd, sql_strerror(mdb));
705       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
706       stat = false;
707    } else {
708       fsr->created = true;
709       stat = true;
710    }
711
712    db_unlock(mdb);
713    return stat;
714 }
715
716
717 /**
718  *  struct stat
719  *  {
720  *      dev_t         st_dev;       * device *
721  *      ino_t         st_ino;       * inode *
722  *      mode_t        st_mode;      * protection *
723  *      nlink_t       st_nlink;     * number of hard links *
724  *      uid_t         st_uid;       * user ID of owner *
725  *      gid_t         st_gid;       * group ID of owner *
726  *      dev_t         st_rdev;      * device type (if inode device) *
727  *      off_t         st_size;      * total size, in bytes *
728  *      unsigned long st_blksize;   * blocksize for filesystem I/O *
729  *      unsigned long st_blocks;    * number of blocks allocated *
730  *      time_t        st_atime;     * time of last access *
731  *      time_t        st_mtime;     * time of last modification *
732  *      time_t        st_ctime;     * time of last inode change *
733  *  };
734  */
735
736 #ifdef HAVE_BATCH_FILE_INSERT
737
738 /** All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path
739  *  tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1"
740  *  in baconfig.h
741  *  
742  *  To sum up :
743  *   - bulk load a temp table
744  *   - insert missing filenames into filename with a single query (lock filenames 
745  *   - table before that to avoid possible duplicate inserts with concurrent update)
746  *   - insert missing paths into path with another single query
747  *   - then insert the join between the temp, filename and path tables into file.
748  */
749
750 /* 
751  * Returns 1 if OK
752  *         0 if failed
753  */
754 bool my_batch_start(JCR *jcr, B_DB *mdb)
755 {
756    bool ok;
757
758    db_lock(mdb);
759    ok =  db_sql_query(mdb,
760              "CREATE TEMPORARY TABLE batch ("
761                 "FileIndex integer,"
762                 "JobId integer,"
763                 "Path blob,"
764                 "Name blob,"
765                 "LStat tinyblob,"
766                 "MD5 tinyblob,"
767                 "MarkId integer)",NULL, NULL);
768    db_unlock(mdb);
769    return ok;
770 }
771
772 /* 
773  * Returns 1 if OK
774  *         0 if failed
775  */
776 bool my_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
777 {
778    size_t len;
779    const char *digest;
780    char ed1[50];
781
782    mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
783    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
784
785    mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
786    db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
787
788    if (ar->Digest == NULL || ar->Digest[0] == 0) {
789       digest = "0";
790    } else {
791       digest = ar->Digest;
792    }
793
794    len = Mmsg(mdb->cmd, "INSERT INTO batch VALUES "
795                          "(%u,%s,'%s','%s','%s','%s',%u)",
796               ar->FileIndex, edit_int64(ar->JobId,ed1), mdb->esc_path, 
797               mdb->esc_name, ar->attr, digest, ar->DeltaSeq);
798
799    return INSERT_DB(jcr, mdb, mdb->cmd);
800 }
801
802 /* set error to something to abort operation */
803 /* 
804  * Returns 1 if OK
805  *         0 if failed
806  */
807 bool my_batch_end(JCR *jcr, B_DB *mdb, const char *error)
808 {
809    
810    Dmsg0(50, "sql_batch_end started\n");
811
812    if (mdb) {
813 #ifdef HAVE_DBI 
814       mdb->status = (dbi_error_flag)0;
815 #else
816       mdb->status = 0;
817 #endif
818    }
819    return true;
820 }
821
822 /* 
823  * Returns true if OK
824  *         false if failed
825  */
826 bool db_write_batch_file_records(JCR *jcr)
827 {
828    bool retval = false;
829    int JobStatus = jcr->JobStatus;
830
831    if (!jcr->batch_started) {         /* no files to backup ? */
832       Dmsg0(50,"db_create_file_record : no files\n");
833       return true;
834    }
835    if (job_canceled(jcr)) {
836       goto bail_out;
837    }
838
839    Dmsg1(50,"db_create_file_record changes=%u\n",jcr->db_batch->changes);
840
841    jcr->JobStatus = JS_AttrInserting;
842    if (!sql_batch_end(jcr, jcr->db_batch, NULL)) {
843       Jmsg1(jcr, M_FATAL, 0, "Batch end %s\n", jcr->db_batch->errmsg);
844       goto bail_out;
845    }
846    if (job_canceled(jcr)) {
847       goto bail_out;
848    }
849
850    /*
851     * We have to lock tables
852     */
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       goto bail_out;
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       goto bail_out;
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       goto bail_out;
867    }
868
869    /*
870     * We have to lock tables
871     */
872    if (!db_sql_query(jcr->db_batch,sql_batch_lock_filename_query,NULL, NULL)) {
873       Jmsg1(jcr, M_FATAL, 0, "Lock Filename table %s\n", jcr->db_batch->errmsg);
874       goto bail_out;
875    }
876    
877    if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) {
878       Jmsg1(jcr,M_FATAL,0,"Fill Filename table %s\n",jcr->db_batch->errmsg);
879       db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
880       goto bail_out;
881    }
882
883    if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
884       Jmsg1(jcr, M_FATAL, 0, "Unlock Filename table %s\n", jcr->db_batch->errmsg);
885       goto bail_out;
886    }
887    
888    if (!db_sql_query(jcr->db_batch, 
889   "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5, MarkId) "
890     "SELECT batch.FileIndex, batch.JobId, Path.PathId, "
891            "Filename.FilenameId,batch.LStat, batch.MD5, batch.MarkId "
892       "FROM batch "
893       "JOIN Path ON (batch.Path = Path.Path) "
894       "JOIN Filename ON (batch.Name = Filename.Name)",
895                      NULL,NULL))
896    {
897       Jmsg1(jcr, M_FATAL, 0, "Fill File table %s\n", jcr->db_batch->errmsg);
898       goto bail_out;
899    }
900
901    jcr->JobStatus = JobStatus;         /* reset entry status */
902    retval = true;
903
904 bail_out:
905    db_sql_query(jcr->db_batch, "DROP TABLE batch", NULL,NULL);
906
907    return retval;
908 }
909
910 /**
911  * Create File record in B_DB
912  *
913  *  In order to reduce database size, we store the File attributes,
914  *  the FileName, and the Path separately.  In principle, there
915  *  is a single FileName record and a single Path record, no matter
916  *  how many times it occurs.  This is this subroutine, we separate
917  *  the file and the path and fill temporary tables with this three records.
918  *
919  *  Note: all routines that call this expect to be able to call
920  *    db_strerror(mdb) to get the error message, so the error message
921  *    MUST be edited into mdb->errmsg before returning an error status.
922  */
923 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
924 {
925    ASSERT(ar->FileType != FT_BASE);
926
927    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
928    Dmsg0(dbglevel, "put_file_into_catalog\n");
929
930    /* Open the dedicated connexion */
931    if (!jcr->batch_started) {
932       if (!db_open_batch_connexion(jcr, mdb)) {
933          return false;     /* error already printed */
934       }
935       if (!sql_batch_start(jcr, jcr->db_batch)) {
936          Mmsg1(&mdb->errmsg, 
937               "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
938          Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
939          return false;
940       }
941       jcr->batch_started = true;
942    }
943    B_DB *bdb = jcr->db_batch;
944
945    split_path_and_file(jcr, bdb, ar->fname);
946
947
948 /*
949  * if (bdb->changes > 100000) {
950  *    db_write_batch_file_records(jcr);
951  *    bdb->changes = 0;
952  *     sql_batch_start(jcr, bdb);
953  * }
954  */
955
956    return sql_batch_insert(jcr, bdb, ar);
957 }
958
959 #else  /* ! HAVE_BATCH_FILE_INSERT */
960
961 /**
962  * Create File record in B_DB
963  *
964  *  In order to reduce database size, we store the File attributes,
965  *  the FileName, and the Path separately.  In principle, there
966  *  is a single FileName record and a single Path record, no matter
967  *  how many times it occurs.  This is this subroutine, we separate
968  *  the file and the path and create three database records.
969  */
970 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
971 {
972    db_lock(mdb);
973    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
974    Dmsg0(dbglevel, "put_file_into_catalog\n");
975
976    split_path_and_file(jcr, mdb, ar->fname);
977
978    if (!db_create_filename_record(jcr, mdb, ar)) {
979       goto bail_out;
980    }
981    Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
982
983
984    if (!db_create_path_record(jcr, mdb, ar)) {
985       goto bail_out;
986    }
987    Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
988
989    /* Now create master File record */
990    if (!db_create_file_record(jcr, mdb, ar)) {
991       goto bail_out;
992    }
993    Dmsg0(dbglevel, "db_create_file_record OK\n");
994
995    Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
996    db_unlock(mdb);
997    return true;
998
999 bail_out:
1000    db_unlock(mdb);
1001    return false;
1002 }
1003
1004
1005 /**
1006  * This is the master File entry containing the attributes.
1007  *  The filename and path records have already been created.
1008  */
1009 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1010 {
1011    int stat;
1012    static const char *no_digest = "0";
1013    const char *digest;
1014
1015    ASSERT(ar->JobId);
1016    ASSERT(ar->PathId);
1017    ASSERT(ar->FilenameId);
1018
1019    if (ar->Digest == NULL || ar->Digest[0] == 0) {
1020       digest = no_digest;
1021    } else {
1022       digest = ar->Digest;
1023    }
1024
1025    /* Must create it */
1026    Mmsg(mdb->cmd,
1027         "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
1028         "LStat,MD5,MarkId) VALUES (%u,%u,%u,%u,'%s','%s',%u)",
1029         ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
1030         ar->attr, digest, ar->DeltaSeq);
1031
1032    ar->FileId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("File"));
1033    if (ar->FileId == 0) {
1034       Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
1035          mdb->cmd, sql_strerror(mdb));
1036       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1037       stat = 0;
1038    } else {
1039       stat = 1;
1040    }
1041    return stat;
1042 }
1043
1044 /** Create a Unique record for the filename -- no duplicates */
1045 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1046 {
1047    SQL_ROW row;
1048
1049    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
1050    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1051    
1052    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
1053
1054    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1055       mdb->num_rows = sql_num_rows(mdb);
1056       if (mdb->num_rows > 1) {
1057          char ed1[30];
1058          Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
1059             edit_uint64(mdb->num_rows, ed1), mdb->fname);
1060          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1061       }
1062       if (mdb->num_rows >= 1) {
1063          if ((row = sql_fetch_row(mdb)) == NULL) {
1064             Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
1065                 mdb->fname, sql_strerror(mdb));
1066             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1067             ar->FilenameId = 0;
1068          } else {
1069             ar->FilenameId = str_to_int64(row[0]);
1070          }
1071          sql_free_result(mdb);
1072          return ar->FilenameId > 0;
1073       }
1074       sql_free_result(mdb);
1075    }
1076
1077    Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
1078
1079    ar->FilenameId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Filename"));
1080    if (ar->FilenameId == 0) {
1081       Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
1082             mdb->cmd, sql_strerror(mdb));
1083       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1084    }
1085    return ar->FilenameId > 0;
1086 }
1087
1088 bool db_write_batch_file_records(JCR *jcr)
1089 {
1090    return true;
1091 }
1092
1093 #endif /* ! HAVE_BATCH_FILE_INSERT */
1094
1095 /** 
1096  * Create file attributes record, or base file attributes record
1097  */
1098 bool db_create_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1099 {
1100    bool ret;
1101
1102    /*
1103     * Make sure we have an acceptable attributes record.
1104     */
1105    if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
1106          ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
1107       Jmsg(jcr, M_FATAL, 0, _("Attempt to put non-attributes into catalog. Stream=%d\n"));
1108       return false;
1109    }
1110
1111    if (ar->FileType != FT_BASE) {
1112       ret = db_create_file_attributes_record(jcr, mdb, ar);
1113
1114    } else if (jcr->HasBase) {
1115       ret = db_create_base_file_attributes_record(jcr, mdb, ar);
1116
1117    } else {
1118       Jmsg0(jcr, M_FATAL, 0, _("Can't Copy/Migrate job using BaseJob"));
1119       ret = true;               /* in copy/migration what do we do ? */
1120    }
1121
1122    return ret;
1123 }
1124
1125 /**
1126  * Create Base File record in B_DB
1127  *
1128  */
1129 bool db_create_base_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1130 {
1131    bool ret;
1132    Dmsg1(dbglevel, "create_base_file Fname=%s\n", ar->fname);
1133    Dmsg0(dbglevel, "put_base_file_into_catalog\n");
1134
1135    db_lock(mdb); 
1136    split_path_and_file(jcr, mdb, ar->fname);
1137    
1138    mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
1139    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1140    
1141    mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
1142    db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
1143    
1144    Mmsg(mdb->cmd, "INSERT INTO basefile%lld (Path, Name) VALUES ('%s','%s')",
1145         (uint64_t)jcr->JobId, mdb->esc_path, mdb->esc_name);
1146
1147    ret = INSERT_DB(jcr, mdb, mdb->cmd);
1148    db_unlock(mdb);
1149
1150    return ret;
1151 }
1152
1153 /** 
1154  * Cleanup the base file temporary tables
1155  */
1156 static void db_cleanup_base_file(JCR *jcr, B_DB *mdb)
1157 {
1158    POOL_MEM buf(PM_MESSAGE);
1159    Mmsg(buf, "DROP TABLE new_basefile%lld", (uint64_t) jcr->JobId);
1160    db_sql_query(mdb, buf.c_str(), NULL, NULL);
1161
1162    Mmsg(buf, "DROP TABLE basefile%lld", (uint64_t) jcr->JobId);
1163    db_sql_query(mdb, buf.c_str(), NULL, NULL);
1164 }
1165
1166 /**
1167  * Put all base file seen in the backup to the BaseFile table
1168  * and cleanup temporary tables
1169  */
1170 bool db_commit_base_file_attributes_record(JCR *jcr, B_DB *mdb)
1171 {
1172    bool ret;
1173    char ed1[50];
1174
1175    db_lock(mdb);
1176
1177    Mmsg(mdb->cmd, 
1178   "INSERT INTO BaseFiles (BaseJobId, JobId, FileId, FileIndex) "
1179    "SELECT B.JobId AS BaseJobId, %s AS JobId, "
1180           "B.FileId, B.FileIndex "
1181      "FROM basefile%s AS A, new_basefile%s AS B "
1182     "WHERE A.Path = B.Path "
1183       "AND A.Name = B.Name "
1184     "ORDER BY B.FileId", 
1185         edit_uint64(jcr->JobId, ed1), ed1, ed1);
1186    ret = db_sql_query(mdb, mdb->cmd, NULL, NULL);
1187    jcr->nb_base_files_used = sql_affected_rows(mdb);
1188    db_cleanup_base_file(jcr, mdb);
1189
1190    db_unlock(mdb);
1191    return ret;
1192 }
1193
1194 /**
1195  * Find the last "accurate" backup state with Base jobs
1196  * 1) Get all files with jobid in list (F subquery) 
1197  * 2) Take only the last version of each file (Temp subquery) => accurate list is ok
1198  * 3) Put the result in a temporary table for the end of job
1199  *
1200  */
1201 bool db_create_base_file_list(JCR *jcr, B_DB *mdb, char *jobids)
1202 {
1203    POOL_MEM buf;
1204    bool ret=false;
1205
1206    db_lock(mdb);   
1207
1208    if (!*jobids) {
1209       Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n"));
1210       goto bail_out;
1211    }
1212
1213    Mmsg(mdb->cmd, create_temp_basefile[db_type], (uint64_t) jcr->JobId);
1214    if (!db_sql_query(mdb, mdb->cmd, NULL, NULL)) {
1215       goto bail_out;
1216    }
1217    Mmsg(buf, select_recent_version[db_type], jobids, jobids);
1218    Mmsg(mdb->cmd, create_temp_new_basefile[db_type], (uint64_t)jcr->JobId, buf.c_str());
1219
1220    ret = db_sql_query(mdb, mdb->cmd, NULL, NULL);
1221 bail_out:
1222    db_unlock(mdb);
1223    return ret;
1224 }
1225
1226 /**
1227  * Create Restore Object record in B_DB
1228  *
1229  */
1230 bool db_create_restore_object_record(JCR *jcr, B_DB *mdb, ROBJECT_DBR *ro)
1231 {
1232    bool stat;
1233    int plug_name_len;
1234    POOLMEM *esc_plug_name = get_pool_memory(PM_MESSAGE);
1235
1236    db_lock(mdb);
1237
1238    Dmsg1(dbglevel, "Oname=%s\n", ro->object_name);
1239    Dmsg0(dbglevel, "put_object_into_catalog\n");
1240
1241    mdb->fnl = strlen(ro->object_name);
1242    mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
1243    db_escape_string(jcr, mdb, mdb->esc_name, ro->object_name, mdb->fnl);
1244    
1245    db_escape_object(jcr, mdb, ro->object, ro->object_len);
1246
1247    plug_name_len = strlen(ro->plugin_name);
1248    esc_plug_name = check_pool_memory_size(esc_plug_name, plug_name_len*2+1);
1249    db_escape_string(jcr, mdb, esc_plug_name, ro->plugin_name, plug_name_len);
1250
1251    Mmsg(mdb->cmd,
1252         "INSERT INTO RestoreObject (ObjectName,PluginName,RestoreObject,"
1253         "ObjectLength,ObjectFullLength,ObjectIndex,ObjectType,"
1254         "ObjectCompression,FileIndex,JobId) "
1255         "VALUES ('%s','%s','%s',%d,%d,%d,%d,%d,%d,%u)",
1256         mdb->esc_name, esc_plug_name, mdb->esc_obj,
1257         ro->object_len, ro->object_full_len, ro->object_index, 
1258         FT_RESTORE_FIRST, ro->object_compression, ro->FileIndex, ro->JobId);
1259
1260    ro->RestoreObjectId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("RestoreObject"));
1261    if (ro->RestoreObjectId == 0) {
1262       Mmsg2(&mdb->errmsg, _("Create db Object record %s failed. ERR=%s"),
1263          mdb->cmd, sql_strerror(mdb));
1264       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1265       stat = false;
1266    } else {
1267       stat = true;
1268    }
1269    db_unlock(mdb);
1270    free_pool_memory(esc_plug_name);
1271    return stat;
1272 }
1273
1274
1275 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */