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