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