]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_create.c
3b781bb4ee09e598450587d6df73b5ec3e0bcedf
[bacula/bacula] / bacula / src / cats / sql_create.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
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  *    Version $Id$
34  */
35
36 /* The following is necessary so that we do not include
37  * the dummy external definition of DB.
38  */
39 #define __SQL_C                       /* indicate that this is sql.c */
40
41 #include "bacula.h"
42 #include "cats.h"
43
44 static const int dbglevel = 500;
45
46 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
47
48 /* -----------------------------------------------------------------------
49  *
50  *   Generic Routines (or almost generic)
51  *
52  * -----------------------------------------------------------------------
53  */
54
55 /* Forward referenced subroutines */
56 #ifndef HAVE_BATCH_FILE_INSERT
57 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
58 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
59 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
60 #endif /* HAVE_BATCH_FILE_INSERT */
61
62
63 /* Create a new record for the Job
64  * Returns: false on failure
65  *          true  on success
66  */
67 bool
68 db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
69 {
70    char dt[MAX_TIME_LENGTH];
71    time_t stime;
72    struct tm tm;
73    bool ok;
74    utime_t JobTDate;
75    char ed1[30],ed2[30];
76
77    db_lock(mdb);
78
79    stime = jr->SchedTime;
80    ASSERT(stime != 0);
81
82    (void)localtime_r(&stime, &tm);
83    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
84    JobTDate = (utime_t)stime;
85
86    /* Must create it */
87    Mmsg(mdb->cmd,
88 "INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate,ClientId) "
89 "VALUES ('%s','%s','%c','%c','%c','%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));
93
94    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
95       Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"),
96             mdb->cmd, sql_strerror(mdb));
97       jr->JobId = 0;
98       ok = false;
99    } else {
100       jr->JobId = sql_insert_id(mdb, NT_("Job"));
101       ok = true;
102    }
103    db_unlock(mdb);
104    return ok;
105 }
106
107
108 /* Create a JobMedia record for medium used this job
109  * Returns: false on failure
110  *          true  on success
111  */
112 bool
113 db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
114 {
115    bool ok = true;;
116    int count;
117    char ed1[50], ed2[50];
118
119    db_lock(mdb);
120
121    /* Now get count for VolIndex */
122    Mmsg(mdb->cmd, "SELECT count(*) from JobMedia WHERE JobId=%s",
123         edit_int64(jm->JobId, ed1));
124    count = get_sql_record_max(jcr, mdb);
125    if (count < 0) {
126       count = 0;
127    }
128    count++;
129
130    /* Note, jm->Strip is not used and is not likely to be used
131     * in the near future, so I have removed it from the insert
132     * to save space in the DB. KES June 2006.
133     */
134    Mmsg(mdb->cmd,
135         "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,"
136         "StartFile,EndFile,StartBlock,EndBlock,VolIndex,Copy) "
137         "VALUES (%s,%s,%u,%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         jm->Copy);
143
144    Dmsg0(300, mdb->cmd);
145    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
146       Mmsg2(&mdb->errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), mdb->cmd,
147          sql_strerror(mdb));
148       ok = false;
149    } else {
150       /* Worked, now update the Media record with the EndFile and EndBlock */
151       Mmsg(mdb->cmd,
152            "UPDATE Media SET EndFile=%u, EndBlock=%u WHERE MediaId=%u",
153            jm->EndFile, jm->EndBlock, jm->MediaId);
154       if (!UPDATE_DB(jcr, mdb, mdb->cmd)) {
155          Mmsg2(&mdb->errmsg, _("Update Media record %s failed: ERR=%s\n"), mdb->cmd,
156               sql_strerror(mdb));
157          ok = false;
158       }
159    }
160    db_unlock(mdb);
161    Dmsg0(300, "Return from JobMedia\n");
162    return ok;
163 }
164
165
166
167 /* Create Unique Pool record
168  * Returns: false on failure
169  *          true  on success
170  */
171 bool
172 db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
173 {
174    bool stat;        
175    char ed1[30], ed2[30], ed3[50], ed4[50];
176
177    Dmsg0(200, "In create pool\n");
178    db_lock(mdb);
179    Mmsg(mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", pr->Name);
180    Dmsg1(200, "selectpool: %s\n", mdb->cmd);
181
182    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
183       mdb->num_rows = sql_num_rows(mdb);
184       if (mdb->num_rows > 0) {
185          Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pr->Name);
186          sql_free_result(mdb);
187          db_unlock(mdb);
188          return false;
189       }
190       sql_free_result(mdb);
191    }
192
193    /* Must create it */
194    Mmsg(mdb->cmd,
195 "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog,"
196 "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration,"
197 "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId) "
198 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s)",
199                   pr->Name,
200                   pr->NumVols, pr->MaxVols,
201                   pr->UseOnce, pr->UseCatalog,
202                   pr->AcceptAnyVolume,
203                   pr->AutoPrune, pr->Recycle,
204                   edit_uint64(pr->VolRetention, ed1),
205                   edit_uint64(pr->VolUseDuration, ed2),
206                   pr->MaxVolJobs, pr->MaxVolFiles,
207                   edit_uint64(pr->MaxVolBytes, ed3),
208                   pr->PoolType, pr->LabelType, pr->LabelFormat,
209                   edit_int64(pr->RecyclePoolId,ed4));
210    Dmsg1(200, "Create Pool: %s\n", mdb->cmd);
211    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
212       Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
213             mdb->cmd, sql_strerror(mdb));
214       pr->PoolId = 0;
215       stat = false;
216    } else {
217       pr->PoolId = sql_insert_id(mdb, NT_("Pool"));
218       stat = true;
219    }
220    db_unlock(mdb);
221    return stat;
222 }
223
224 /*
225  * Create Unique Device record
226  * Returns: false on failure
227  *          true  on success
228  */
229 bool
230 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
231 {
232    bool ok;
233    char ed1[30], ed2[30];
234
235    Dmsg0(200, "In create Device\n");
236    db_lock(mdb);
237    Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
238    Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
239
240    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
241       mdb->num_rows = sql_num_rows(mdb);
242       if (mdb->num_rows > 0) {
243          Mmsg1(&mdb->errmsg, _("Device record %s already exists\n"), dr->Name);
244          sql_free_result(mdb);
245          db_unlock(mdb);
246          return false;
247       }
248       sql_free_result(mdb);
249    }
250
251    /* Must create it */
252    Mmsg(mdb->cmd,
253 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
254                   dr->Name,
255                   edit_uint64(dr->MediaTypeId, ed1),
256                   edit_int64(dr->StorageId, ed2));
257    Dmsg1(200, "Create Device: %s\n", mdb->cmd);
258    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
259       Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
260             mdb->cmd, sql_strerror(mdb));
261       dr->DeviceId = 0;
262       ok = false;
263    } else {
264       dr->DeviceId = sql_insert_id(mdb, NT_("Device"));
265       ok = true;
266    }
267    db_unlock(mdb);
268    return ok;
269 }
270
271
272
273 /*
274  * Create a Unique record for Storage -- no duplicates
275  * Returns: false on failure
276  *          true  on success with id in sr->StorageId
277  */
278 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
279 {
280    SQL_ROW row;
281    bool ok;
282
283    db_lock(mdb);
284    Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
285
286    sr->StorageId = 0;
287    sr->created = false;
288    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
289       mdb->num_rows = sql_num_rows(mdb);
290       /* If more than one, report error, but return first row */
291       if (mdb->num_rows > 1) {
292          Mmsg1(&mdb->errmsg, _("More than one Storage record!: %d\n"), (int)(mdb->num_rows));
293          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
294       }
295       if (mdb->num_rows >= 1) {
296          if ((row = sql_fetch_row(mdb)) == NULL) {
297             Mmsg1(&mdb->errmsg, _("error fetching Storage row: %s\n"), sql_strerror(mdb));
298             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
299             sql_free_result(mdb);
300             db_unlock(mdb);
301             return false;
302          }
303          sr->StorageId = str_to_int64(row[0]);
304          sr->AutoChanger = atoi(row[1]);   /* bool */
305          sql_free_result(mdb);
306          db_unlock(mdb);
307          return true;
308       }
309       sql_free_result(mdb);
310    }
311
312    /* Must create it */
313    Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
314         " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
315
316    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
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->StorageId = sql_insert_id(mdb, NT_("Storage"));
323       sr->created = true;
324       ok = true;
325    }
326    db_unlock(mdb);
327    return ok;
328 }
329
330
331 /*
332  * Create Unique MediaType record
333  * Returns: false on failure
334  *          true  on success
335  */
336 bool
337 db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr)
338 {
339    bool stat;        
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       mdb->num_rows = sql_num_rows(mdb);
348       if (mdb->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    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
365       Mmsg2(&mdb->errmsg, _("Create db mediatype record %s failed: ERR=%s\n"),
366             mdb->cmd, sql_strerror(mdb));
367       mr->MediaTypeId = 0;
368       stat = false;
369    } else {
370       mr->MediaTypeId = sql_insert_id(mdb, NT_("MediaType"));
371       stat = true;
372    }
373    db_unlock(mdb);
374    return stat;
375 }
376
377
378 /*
379  * Create Media record. VolumeName and non-zero Slot must be unique
380  *
381  * Returns: 0 on failure
382  *          1 on success
383  */
384 int
385 db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
386 {
387    int stat;
388    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
389    char ed9[50], ed10[50], ed11[50], ed12[50];
390    struct tm tm;
391
392    db_lock(mdb);
393    Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName='%s'",
394            mr->VolumeName);
395    Dmsg1(500, "selectpool: %s\n", mdb->cmd);
396
397    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
398       mdb->num_rows = sql_num_rows(mdb);
399       if (mdb->num_rows > 0) {
400          Mmsg1(&mdb->errmsg, _("Volume \"%s\" already exists.\n"), mr->VolumeName);
401          sql_free_result(mdb);
402          db_unlock(mdb);
403          return 0;
404       }
405       sql_free_result(mdb);
406    }
407
408    /* Must create it */
409    Mmsg(mdb->cmd,
410 "INSERT INTO Media (VolumeName,MediaType,MediaTypeId,PoolId,MaxVolBytes,"
411 "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
412 "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts,"
413 "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId,"
414 "ScratchPoolId,RecyclePoolId,Enabled)"
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)",
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
440           );
441
442
443    Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
444    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
445       Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
446             mdb->cmd, sql_strerror(mdb));
447       stat = 0;
448    } else {
449       mr->MediaId = sql_insert_id(mdb, NT_("Media"));
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
464    /*
465     * Make sure that if InChanger is non-zero any other identical slot
466     *   has InChanger zero.
467     */
468    db_make_inchanger_unique(jcr, mdb, mr);
469
470    db_unlock(mdb);
471    return stat;
472 }
473
474 /*
475  * Create a Unique record for the client -- no duplicates
476  * Returns: 0 on failure
477  *          1 on success with id in cr->ClientId
478  */
479 int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
480 {
481    SQL_ROW row;
482    int stat;
483    char ed1[50], ed2[50];
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       mdb->num_rows = sql_num_rows(mdb);
491       /* If more than one, report error, but return first row */
492       if (mdb->num_rows > 1) {
493          Mmsg1(&mdb->errmsg, _("More than one Client!: %d\n"), (int)(mdb->num_rows));
494          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
495       }
496       if (mdb->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    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
525       Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
526             mdb->cmd, sql_strerror(mdb));
527       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
528       cr->ClientId = 0;
529       stat = 0;
530    } else {
531       cr->ClientId = sql_insert_id(mdb, NT_("Client"));
532       stat = 1;
533    }
534    db_unlock(mdb);
535    return stat;
536 }
537
538
539
540
541
542 /*
543  * Create a Unique record for the counter -- no duplicates
544  * Returns: 0 on failure
545  *          1 on success with counter filled in
546  */
547 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
548 {
549    COUNTER_DBR mcr;
550    int stat;
551
552    db_lock(mdb);
553    memset(&mcr, 0, sizeof(mcr));
554    bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
555    if (db_get_counter_record(jcr, mdb, &mcr)) {
556       memcpy(cr, &mcr, sizeof(COUNTER_DBR));
557       db_unlock(mdb);
558       return 1;
559    }
560
561    /* Must create it */
562    Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue,"
563       "WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
564       cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
565       cr->WrapCounter);
566
567    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
568       Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
569             mdb->cmd, sql_strerror(mdb));
570       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
571       stat = 0;
572    } else {
573       stat = 1;
574    }
575    db_unlock(mdb);
576    return stat;
577 }
578
579
580 /*
581  * Create a FileSet record. This record is unique in the
582  *  name and the MD5 signature of the include/exclude sets.
583  *  Returns: 0 on failure
584  *           1 on success with FileSetId in record
585  */
586 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
587 {
588    SQL_ROW row;
589    bool stat;
590    struct tm tm;
591
592    db_lock(mdb);
593    fsr->created = false;
594    Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
595 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
596
597    fsr->FileSetId = 0;
598    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
599       mdb->num_rows = sql_num_rows(mdb);
600       if (mdb->num_rows > 1) {
601          Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
602          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
603       }
604       if (mdb->num_rows >= 1) {
605          if ((row = sql_fetch_row(mdb)) == NULL) {
606             Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
607             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
608             sql_free_result(mdb);
609             db_unlock(mdb);
610             return false;
611          }
612          fsr->FileSetId = str_to_int64(row[0]);
613          if (row[1] == NULL) {
614             fsr->cCreateTime[0] = 0;
615          } else {
616             bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
617          }
618          sql_free_result(mdb);
619          db_unlock(mdb);
620          return true;
621       }
622       sql_free_result(mdb);
623    }
624
625    if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
626       fsr->CreateTime = time(NULL);
627    }
628    (void)localtime_r(&fsr->CreateTime, &tm);
629    strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
630
631    /* Must create it */
632       Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
633 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
634
635    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
636       Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
637             mdb->cmd, sql_strerror(mdb));
638       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
639       fsr->FileSetId = 0;
640       stat = false;
641    } else {
642       fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet"));
643       fsr->created = true;
644       stat = true;
645    }
646
647    db_unlock(mdb);
648    return stat;
649 }
650
651
652 /*
653  *  struct stat
654  *  {
655  *      dev_t         st_dev;       * device *
656  *      ino_t         st_ino;       * inode *
657  *      mode_t        st_mode;      * protection *
658  *      nlink_t       st_nlink;     * number of hard links *
659  *      uid_t         st_uid;       * user ID of owner *
660  *      gid_t         st_gid;       * group ID of owner *
661  *      dev_t         st_rdev;      * device type (if inode device) *
662  *      off_t         st_size;      * total size, in bytes *
663  *      unsigned long st_blksize;   * blocksize for filesystem I/O *
664  *      unsigned long st_blocks;    * number of blocks allocated *
665  *      time_t        st_atime;     * time of last access *
666  *      time_t        st_mtime;     * time of last modification *
667  *      time_t        st_ctime;     * time of last inode change *
668  *  };
669  */
670
671 #ifdef HAVE_BATCH_FILE_INSERT
672
673 /*  All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path
674  *  tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1"
675  *  in baconfig.h
676  *  
677  *  To sum up :
678  *   - bulk load a temp table
679  *   - insert missing filenames into filename with a single query (lock filenames 
680  *   - table before that to avoid possible duplicate inserts with concurrent update)
681  *   - insert missing paths into path with another single query
682  *   - then insert the join between the temp, filename and path tables into file.
683  */
684
685 /* 
686  * Returns 1 if OK
687  *         0 if failed
688  */
689 bool my_batch_start(JCR *jcr, B_DB *mdb)
690 {
691    bool ok;
692
693    db_lock(mdb);
694    ok =  db_sql_query(mdb,
695              "CREATE TEMPORARY TABLE batch ("
696                 "FileIndex integer,"
697                 "JobId integer,"
698                 "Path blob,"
699                 "Name blob,"
700                 "LStat tinyblob,"
701                 "MD5 tinyblob)",NULL, NULL);
702    db_unlock(mdb);
703    return ok;
704 }
705
706 /* 
707  * Returns 1 if OK
708  *         0 if failed
709  */
710 bool my_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
711 {
712    size_t len;
713    const char *digest;
714    char ed1[50];
715
716    mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
717    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
718
719    mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
720    db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
721
722    if (ar->Digest == NULL || ar->Digest[0] == 0) {
723       digest = "0";
724    } else {
725       digest = ar->Digest;
726    }
727
728    len = Mmsg(mdb->cmd, "INSERT INTO batch VALUES (%u,%s,'%s','%s','%s','%s')",
729               ar->FileIndex, edit_int64(ar->JobId,ed1), mdb->esc_path, 
730               mdb->esc_name, ar->attr, digest);
731
732    return INSERT_DB(jcr, mdb, mdb->cmd);
733 }
734
735 /* set error to something to abort operation */
736 /* 
737  * Returns 1 if OK
738  *         0 if failed
739  */
740 bool my_batch_end(JCR *jcr, B_DB *mdb, const char *error)
741 {
742    
743    Dmsg0(50, "sql_batch_end started\n");
744
745    if (mdb) {
746       mdb->status = 0;
747    }
748    return true;
749 }
750
751 /* 
752  * Returns 1 if OK
753  *         0 if failed
754  */
755 bool db_write_batch_file_records(JCR *jcr)
756 {
757    int JobStatus = jcr->JobStatus;
758
759    if (!jcr->db_batch) {         /* no files to backup ? */
760       Dmsg0(50,"db_create_file_record : no files\n");
761       return true;
762    }
763    if (job_canceled(jcr)) {
764       return false;
765    }
766
767    Dmsg1(50,"db_create_file_record changes=%u\n",jcr->db_batch->changes);
768
769    jcr->JobStatus = JS_AttrInserting;
770    if (!sql_batch_end(jcr, jcr->db_batch, NULL)) {
771       Jmsg1(jcr, M_FATAL, 0, "Batch end %s\n", jcr->db_batch->errmsg);
772       return false;
773    }
774    if (job_canceled(jcr)) {
775       return false;
776    }
777
778
779    /* we have to lock tables */
780    if (!db_sql_query(jcr->db_batch, sql_batch_lock_path_query, NULL, NULL)) {
781       Jmsg1(jcr, M_FATAL, 0, "Lock Path table %s\n", jcr->db_batch->errmsg);
782       return false;
783    }
784
785    if (!db_sql_query(jcr->db_batch, sql_batch_fill_path_query, NULL, NULL)) {
786       Jmsg1(jcr, M_FATAL, 0, "Fill Path table %s\n",jcr->db_batch->errmsg);
787       db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
788       return false;
789    }
790    
791    if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
792       Jmsg1(jcr, M_FATAL, 0, "Unlock Path table %s\n", jcr->db_batch->errmsg);
793       return false;      
794    }
795
796    /* we have to lock tables */
797    if (!db_sql_query(jcr->db_batch,sql_batch_lock_filename_query,NULL, NULL)) {
798       Jmsg1(jcr, M_FATAL, 0, "Lock Filename table %s\n", jcr->db_batch->errmsg);
799       return false;
800    }
801    
802    if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) {
803       Jmsg1(jcr,M_FATAL,0,"Fill Filename table %s\n",jcr->db_batch->errmsg);
804       db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
805       return false;            
806    }
807
808    if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
809       Jmsg1(jcr, M_FATAL, 0, "Unlock Filename table %s\n", jcr->db_batch->errmsg);
810       return false;
811    }
812    
813    if (!db_sql_query(jcr->db_batch, 
814        "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
815          "SELECT batch.FileIndex, batch.JobId, Path.PathId, "
816                 "Filename.FilenameId,batch.LStat, batch.MD5 "
817            "FROM batch "
818            "JOIN Path ON (batch.Path = Path.Path) "
819            "JOIN Filename ON (batch.Name = Filename.Name)",
820                      NULL,NULL))
821    {
822       Jmsg1(jcr, M_FATAL, 0, "Fill File table %s\n", jcr->db_batch->errmsg);
823       return false;
824    }
825
826    db_sql_query(jcr->db_batch, "DROP TABLE batch", NULL,NULL);
827
828    jcr->JobStatus = JobStatus;         /* reset entry status */
829    return true;
830 }
831
832 /*
833  * Create File record in B_DB
834  *
835  *  In order to reduce database size, we store the File attributes,
836  *  the FileName, and the Path separately.  In principle, there
837  *  is a single FileName record and a single Path record, no matter
838  *  how many times it occurs.  This is this subroutine, we separate
839  *  the file and the path and fill temporary tables with this three records.
840  */
841 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
842 {
843    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
844    Dmsg0(dbglevel, "put_file_into_catalog\n");
845
846    if (!jcr->db_batch) {
847       Dmsg2(100, "Opendb attr. Stream=%d fname=%s\n", ar->Stream, ar->fname);
848       jcr->db_batch = db_init_database(jcr, 
849                                       mdb->db_name, 
850                                       mdb->db_user,
851                                       mdb->db_password, 
852                                       mdb->db_address,
853                                       mdb->db_port,
854                                       mdb->db_socket,
855                                       1 /* multi_db = true */);
856       if (!jcr->db_batch) {
857          Mmsg1(&mdb->errmsg, _("Could not init batch database: \"%s\".\n"),
858                         jcr->db->db_name);
859          Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
860          return false;
861       }
862
863       if (!db_open_database(jcr, jcr->db_batch)) {
864          Mmsg2(&mdb->errmsg,  _("Could not open database \"%s\": ERR=%s\n"),
865               jcr->db->db_name, db_strerror(jcr->db_batch));
866          Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
867          return false;
868       }      
869       
870       if (!sql_batch_start(jcr, jcr->db_batch)) {
871          Mmsg1(&mdb->errmsg, 
872               "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
873          Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
874          return false;
875       }
876       Dmsg3(100, "initdb ref=%d connected=%d db=%p\n", jcr->db_batch->ref_count,
877             jcr->db_batch->connected, jcr->db_batch->db);
878    }
879    B_DB *bdb = jcr->db_batch;
880
881    /*
882     * Make sure we have an acceptable attributes record.
883     */
884    if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
885          ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
886       Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
887          ar->Stream);
888       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
889       return false;
890    }
891
892    split_path_and_file(jcr, bdb, ar->fname);
893
894
895 /*
896    if (bdb->changes > 100000) {
897       db_write_batch_file_records(jcr);
898       bdb->changes = 0;
899       sql_batch_start(jcr, bdb);
900    }
901 */
902
903    return sql_batch_insert(jcr, bdb, ar);
904 }
905
906 #else  /* ! HAVE_BATCH_FILE_INSERT */
907
908 /*
909  * Create File record in B_DB
910  *
911  *  In order to reduce database size, we store the File attributes,
912  *  the FileName, and the Path separately.  In principle, there
913  *  is a single FileName record and a single Path record, no matter
914  *  how many times it occurs.  This is this subroutine, we separate
915  *  the file and the path and create three database records.
916  */
917 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
918 {
919    db_lock(mdb);
920    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
921    Dmsg0(dbglevel, "put_file_into_catalog\n");
922    /*
923     * Make sure we have an acceptable attributes record.
924     */
925    if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
926          ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
927       Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
928          ar->Stream);
929       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
930       goto bail_out;
931    }
932
933
934    split_path_and_file(jcr, mdb, ar->fname);
935
936    if (!db_create_filename_record(jcr, mdb, ar)) {
937       goto bail_out;
938    }
939    Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
940
941
942    if (!db_create_path_record(jcr, mdb, ar)) {
943       goto bail_out;
944    }
945    Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
946
947    /* Now create master File record */
948    if (!db_create_file_record(jcr, mdb, ar)) {
949       goto bail_out;
950    }
951    Dmsg0(dbglevel, "db_create_file_record OK\n");
952
953    Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
954    db_unlock(mdb);
955    return true;
956
957 bail_out:
958    db_unlock(mdb);
959    return false;
960 }
961
962
963 /*
964  * This is the master File entry containing the attributes.
965  *  The filename and path records have already been created.
966  */
967 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
968 {
969    int stat;
970    static char *no_digest = "0";
971    char *digest;
972
973    ASSERT(ar->JobId);
974    ASSERT(ar->PathId);
975    ASSERT(ar->FilenameId);
976
977    if (ar->Digest == NULL || ar->Digest[0] == 0) {
978       digest = no_digest;
979    } else {
980       digest = ar->Digest;
981    }
982
983    /* Must create it */
984    Mmsg(mdb->cmd,
985         "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
986         "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
987         ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
988         ar->attr, digest);
989
990    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
991       Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
992          mdb->cmd, sql_strerror(mdb));
993       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
994       ar->FileId = 0;
995       stat = 0;
996    } else {
997       ar->FileId = sql_insert_id(mdb, NT_("File"));
998       stat = 1;
999    }
1000    return stat;
1001 }
1002
1003 /* Create a Unique record for the Path -- no duplicates */
1004 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1005 {
1006    SQL_ROW row;
1007    int stat;
1008
1009    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
1010    db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
1011
1012    if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
1013        strcmp(mdb->cached_path, mdb->path) == 0) {
1014       ar->PathId = mdb->cached_path_id;
1015       return 1;
1016    }
1017
1018    Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
1019
1020    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1021       mdb->num_rows = sql_num_rows(mdb);
1022       if (mdb->num_rows > 1) {
1023          char ed1[30];
1024          Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
1025             edit_uint64(mdb->num_rows, ed1), mdb->path);
1026          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1027       }
1028       /* Even if there are multiple paths, take the first one */
1029       if (mdb->num_rows >= 1) {
1030          if ((row = sql_fetch_row(mdb)) == NULL) {
1031             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
1032             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1033             sql_free_result(mdb);
1034             ar->PathId = 0;
1035             ASSERT(ar->PathId);
1036             return 0;
1037          }
1038          ar->PathId = str_to_int64(row[0]);
1039          sql_free_result(mdb);
1040          /* Cache path */
1041          if (ar->PathId != mdb->cached_path_id) {
1042             mdb->cached_path_id = ar->PathId;
1043             mdb->cached_path_len = mdb->pnl;
1044             pm_strcpy(mdb->cached_path, mdb->path);
1045          }
1046          ASSERT(ar->PathId);
1047          return 1;
1048       }
1049       sql_free_result(mdb);
1050    }
1051
1052    Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
1053
1054    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1055       Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"),
1056          mdb->cmd, sql_strerror(mdb));
1057       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1058       ar->PathId = 0;
1059       stat = 0;
1060    } else {
1061       ar->PathId = sql_insert_id(mdb, NT_("Path"));
1062       stat = 1;
1063    }
1064
1065    /* Cache path */
1066    if (stat && ar->PathId != mdb->cached_path_id) {
1067       mdb->cached_path_id = ar->PathId;
1068       mdb->cached_path_len = mdb->pnl;
1069       pm_strcpy(mdb->cached_path, mdb->path);
1070    }
1071    return stat;
1072 }
1073
1074 /* Create a Unique record for the filename -- no duplicates */
1075 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1076 {
1077    SQL_ROW row;
1078
1079    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
1080    db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1081    
1082    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
1083
1084    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1085       mdb->num_rows = sql_num_rows(mdb);
1086       if (mdb->num_rows > 1) {
1087          char ed1[30];
1088          Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
1089             edit_uint64(mdb->num_rows, ed1), mdb->fname);
1090          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1091       }
1092       if (mdb->num_rows >= 1) {
1093          if ((row = sql_fetch_row(mdb)) == NULL) {
1094             Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
1095                 mdb->fname, sql_strerror(mdb));
1096             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1097             ar->FilenameId = 0;
1098          } else {
1099             ar->FilenameId = str_to_int64(row[0]);
1100          }
1101          sql_free_result(mdb);
1102          return ar->FilenameId > 0;
1103       }
1104       sql_free_result(mdb);
1105    }
1106
1107    Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
1108
1109    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1110       Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
1111             mdb->cmd, sql_strerror(mdb));
1112       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1113       ar->FilenameId = 0;
1114    } else {
1115       ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
1116    }
1117    return ar->FilenameId > 0;
1118 }
1119
1120 bool db_write_batch_file_records(JCR *jcr)
1121 {
1122    return true;
1123 }
1124
1125 #endif /* ! HAVE_BATCH_FILE_INSERT */
1126
1127 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL */