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