]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_create.c
Turn off debug code in jobq.c
[bacula/bacula] / bacula / src / cats / sql_create.c
1 /*
2  * Bacula Catalog Database Create record interface routines
3  *
4  *    Kern Sibbald, March 2000
5  *
6  *    Version $Id$
7  */
8 /*
9    Copyright (C) 2000-2006 Kern Sibbald
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License
13    version 2 as amended with additional clauses defined in the
14    file LICENSE in the main source directory.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
19    the file LICENSE for additional details.
20
21  */
22
23 /* The following is necessary so that we do not include
24  * the dummy external definition of DB.
25  */
26 #define __SQL_C                       /* indicate that this is sql.c */
27
28 #include "bacula.h"
29 #include "cats.h"
30
31 static const int dbglevel = 500;
32
33 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
34
35 /* -----------------------------------------------------------------------
36  *
37  *   Generic Routines (or almost generic)
38  *
39  * -----------------------------------------------------------------------
40  */
41
42 /* Forward referenced subroutines */
43 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
44 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
45 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
46
47
48 /* Imported subroutines */
49 extern void print_dashes(B_DB *mdb);
50 extern void print_result(B_DB *mdb);
51 extern int QueryDB(const char *file, int line, JCR *jcr, B_DB *db, char *select_cmd);
52 extern int InsertDB(const char *file, int line, JCR *jcr, B_DB *db, char *select_cmd);
53 extern int UpdateDB(const char *file, int line, JCR *jcr, B_DB *db, char *update_cmd);
54 extern void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname);
55
56
57 /* Create a new record for the Job
58  * Returns: false on failure
59  *          true  on success
60  */
61 bool
62 db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
63 {
64    char dt[MAX_TIME_LENGTH];
65    time_t stime;
66    struct tm tm;
67    bool ok;
68    utime_t JobTDate;
69    char ed1[30];
70
71    db_lock(mdb);
72
73    stime = jr->SchedTime;
74    ASSERT(stime != 0);
75
76    (void)localtime_r(&stime, &tm);
77    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
78    JobTDate = (utime_t)stime;
79
80    /* Must create it */
81    Mmsg(mdb->cmd,
82 "INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate) VALUES "
83 "('%s','%s','%c','%c','%c','%s',%s)",
84            jr->Job, jr->Name, (char)(jr->JobType), (char)(jr->JobLevel),
85            (char)(jr->JobStatus), dt, edit_uint64(JobTDate, ed1));
86
87    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
88       Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"),
89             mdb->cmd, sql_strerror(mdb));
90       jr->JobId = 0;
91       ok = false;
92    } else {
93       jr->JobId = sql_insert_id(mdb, NT_("Job"));
94       ok = true;
95    }
96    db_unlock(mdb);
97    return ok;
98 }
99
100
101 /* Create a JobMedia record for medium used this job
102  * Returns: false on failure
103  *          true  on success
104  */
105 bool
106 db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
107 {
108    bool ok = true;;
109    int count;
110    char ed1[50], ed2[50];
111
112    db_lock(mdb);
113
114    /* Now get count for VolIndex */
115    Mmsg(mdb->cmd, "SELECT count(*) from JobMedia WHERE JobId=%s",
116         edit_int64(jm->JobId, ed1));
117    count = get_sql_record_max(jcr, mdb);
118    if (count < 0) {
119       count = 0;
120    }
121    count++;
122
123    /* Note, jm->Strip is not used and is not likely to be used
124     * in the near future, so I have removed it from the insert
125     * to save space in the DB. KES June 2006.
126     */
127    Mmsg(mdb->cmd,
128         "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,"
129         "StartFile,EndFile,StartBlock,EndBlock,VolIndex,Copy) "
130         "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u,%u)",
131         edit_int64(jm->JobId, ed1),
132         edit_int64(jm->MediaId, ed2),
133         jm->FirstIndex, jm->LastIndex,
134         jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count,
135         jm->Copy);
136
137    Dmsg0(300, mdb->cmd);
138    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
139       Mmsg2(&mdb->errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), mdb->cmd,
140          sql_strerror(mdb));
141       ok = false;
142    } else {
143       /* Worked, now update the Media record with the EndFile and EndBlock */
144       Mmsg(mdb->cmd,
145            "UPDATE Media SET EndFile=%u, EndBlock=%u WHERE MediaId=%u",
146            jm->EndFile, jm->EndBlock, jm->MediaId);
147       if (!UPDATE_DB(jcr, mdb, mdb->cmd)) {
148          Mmsg2(&mdb->errmsg, _("Update Media record %s failed: ERR=%s\n"), mdb->cmd,
149               sql_strerror(mdb));
150          ok = false;
151       }
152    }
153    db_unlock(mdb);
154    Dmsg0(300, "Return from JobMedia\n");
155    return ok;
156 }
157
158
159
160 /* Create Unique Pool record
161  * Returns: false on failure
162  *          true  on success
163  */
164 bool
165 db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
166 {
167    bool stat;        
168    char ed1[30], ed2[30], ed3[50];
169
170    Dmsg0(200, "In create pool\n");
171    db_lock(mdb);
172    Mmsg(mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", pr->Name);
173    Dmsg1(200, "selectpool: %s\n", mdb->cmd);
174
175    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
176       mdb->num_rows = sql_num_rows(mdb);
177       if (mdb->num_rows > 0) {
178          Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pr->Name);
179          sql_free_result(mdb);
180          db_unlock(mdb);
181          return false;
182       }
183       sql_free_result(mdb);
184    }
185
186    /* Must create it */
187    Mmsg(mdb->cmd,
188 "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog,"
189 "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration,"
190 "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat) "
191 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s')",
192                   pr->Name,
193                   pr->NumVols, pr->MaxVols,
194                   pr->UseOnce, pr->UseCatalog,
195                   pr->AcceptAnyVolume,
196                   pr->AutoPrune, pr->Recycle,
197                   edit_uint64(pr->VolRetention, ed1),
198                   edit_uint64(pr->VolUseDuration, ed2),
199                   pr->MaxVolJobs, pr->MaxVolFiles,
200                   edit_uint64(pr->MaxVolBytes, ed3),
201                   pr->PoolType, pr->LabelType, pr->LabelFormat);
202    Dmsg1(200, "Create Pool: %s\n", mdb->cmd);
203    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
204       Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
205             mdb->cmd, sql_strerror(mdb));
206       pr->PoolId = 0;
207       stat = false;
208    } else {
209       pr->PoolId = sql_insert_id(mdb, NT_("Pool"));
210       stat = true;
211    }
212    db_unlock(mdb);
213    return stat;
214 }
215
216 /*
217  * Create Unique Device record
218  * Returns: false on failure
219  *          true  on success
220  */
221 bool
222 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
223 {
224    bool ok;
225    char ed1[30], ed2[30];
226
227    Dmsg0(200, "In create Device\n");
228    db_lock(mdb);
229    Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
230    Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
231
232    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
233       mdb->num_rows = sql_num_rows(mdb);
234       if (mdb->num_rows > 0) {
235          Mmsg1(&mdb->errmsg, _("Device record %s already exists\n"), dr->Name);
236          sql_free_result(mdb);
237          db_unlock(mdb);
238          return false;
239       }
240       sql_free_result(mdb);
241    }
242
243    /* Must create it */
244    Mmsg(mdb->cmd,
245 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
246                   dr->Name,
247                   edit_uint64(dr->MediaTypeId, ed1),
248                   edit_int64(dr->StorageId, ed2));
249    Dmsg1(200, "Create Device: %s\n", mdb->cmd);
250    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
251       Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
252             mdb->cmd, sql_strerror(mdb));
253       dr->DeviceId = 0;
254       ok = false;
255    } else {
256       dr->DeviceId = sql_insert_id(mdb, NT_("Device"));
257       ok = true;
258    }
259    db_unlock(mdb);
260    return ok;
261 }
262
263
264
265 /*
266  * Create a Unique record for Storage -- no duplicates
267  * Returns: false on failure
268  *          true  on success with id in sr->StorageId
269  */
270 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
271 {
272    SQL_ROW row;
273    bool ok;
274
275    db_lock(mdb);
276    Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
277
278    sr->StorageId = 0;
279    sr->created = false;
280    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
281       mdb->num_rows = sql_num_rows(mdb);
282       /* If more than one, report error, but return first row */
283       if (mdb->num_rows > 1) {
284          Mmsg1(&mdb->errmsg, _("More than one Storage record!: %d\n"), (int)(mdb->num_rows));
285          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
286       }
287       if (mdb->num_rows >= 1) {
288          if ((row = sql_fetch_row(mdb)) == NULL) {
289             Mmsg1(&mdb->errmsg, _("error fetching Storage row: %s\n"), sql_strerror(mdb));
290             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
291             sql_free_result(mdb);
292             db_unlock(mdb);
293             return false;
294          }
295          sr->StorageId = str_to_int64(row[0]);
296          sr->AutoChanger = atoi(row[1]);   /* bool */
297          sql_free_result(mdb);
298          db_unlock(mdb);
299          return true;
300       }
301       sql_free_result(mdb);
302    }
303
304    /* Must create it */
305    Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
306         " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
307
308    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
309       Mmsg2(&mdb->errmsg, _("Create DB Storage record %s failed. ERR=%s\n"),
310             mdb->cmd, sql_strerror(mdb));
311       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
312       ok = false;
313    } else {
314       sr->StorageId = sql_insert_id(mdb, NT_("Storage"));
315       sr->created = true;
316       ok = true;
317    }
318    db_unlock(mdb);
319    return ok;
320 }
321
322
323 /*
324  * Create Unique MediaType record
325  * Returns: false on failure
326  *          true  on success
327  */
328 bool
329 db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr)
330 {
331    bool stat;        
332
333    Dmsg0(200, "In create mediatype\n");
334    db_lock(mdb);
335    Mmsg(mdb->cmd, "SELECT MediaTypeId,MediaType FROM MediaType WHERE MediaType='%s'", mr->MediaType);
336    Dmsg1(200, "selectmediatype: %s\n", mdb->cmd);
337
338    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
339       mdb->num_rows = sql_num_rows(mdb);
340       if (mdb->num_rows > 0) {
341          Mmsg1(&mdb->errmsg, _("mediatype record %s already exists\n"), mr->MediaType);
342          sql_free_result(mdb);
343          db_unlock(mdb);
344          return false;
345       }
346       sql_free_result(mdb);
347    }
348
349    /* Must create it */
350    Mmsg(mdb->cmd,
351 "INSERT INTO MediaType (MediaType,ReadOnly) "
352 "VALUES ('%s',%d)",
353                   mr->MediaType,
354                   mr->ReadOnly);
355    Dmsg1(200, "Create mediatype: %s\n", mdb->cmd);
356    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
357       Mmsg2(&mdb->errmsg, _("Create db mediatype record %s failed: ERR=%s\n"),
358             mdb->cmd, sql_strerror(mdb));
359       mr->MediaTypeId = 0;
360       stat = false;
361    } else {
362       mr->MediaTypeId = sql_insert_id(mdb, NT_("MediaType"));
363       stat = true;
364    }
365    db_unlock(mdb);
366    return stat;
367 }
368
369
370 /*
371  * Create Media record. VolumeName and non-zero Slot must be unique
372  *
373  * Returns: 0 on failure
374  *          1 on success
375  */
376 int
377 db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
378 {
379    int stat;
380    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
381    char ed9[50], ed10[50], ed11[50], ed12[50];
382    struct tm tm;
383
384    db_lock(mdb);
385    Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName='%s'",
386            mr->VolumeName);
387    Dmsg1(500, "selectpool: %s\n", mdb->cmd);
388
389    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
390       mdb->num_rows = sql_num_rows(mdb);
391       if (mdb->num_rows > 0) {
392          Mmsg1(&mdb->errmsg, _("Volume \"%s\" already exists.\n"), mr->VolumeName);
393          sql_free_result(mdb);
394          db_unlock(mdb);
395          return 0;
396       }
397       sql_free_result(mdb);
398    }
399
400    /* Must create it */
401    Mmsg(mdb->cmd,
402 "INSERT INTO Media (VolumeName,MediaType,MediaTypeId,PoolId,MaxVolBytes,"
403 "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
404 "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts,"
405 "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId,"
406 "ScratchPoolId,RecyclePoolId,Enabled)"
407 "VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s,"
408 "%s,%s,%s,%s,%d)",
409           mr->VolumeName,
410           mr->MediaType, mr->PoolId,
411           edit_uint64(mr->MaxVolBytes,ed1),
412           edit_uint64(mr->VolCapacityBytes, ed2),
413           mr->Recycle,
414           edit_uint64(mr->VolRetention, ed3),
415           edit_uint64(mr->VolUseDuration, ed4),
416           mr->MaxVolJobs,
417           mr->MaxVolFiles,
418           mr->VolStatus,
419           mr->Slot,
420           edit_uint64(mr->VolBytes, ed5),
421           mr->InChanger,
422           edit_uint64(mr->VolReadTime, ed6),
423           edit_uint64(mr->VolWriteTime, ed7),
424           mr->VolParts,
425           mr->LabelType,
426           edit_int64(mr->StorageId, ed8), 
427           edit_int64(mr->DeviceId, ed9), 
428           edit_int64(mr->LocationId, ed10), 
429           edit_int64(mr->ScratchPoolId, ed11), 
430           edit_int64(mr->RecyclePoolId, ed12), 
431           mr->Enabled
432           );
433
434
435    Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
436    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
437       Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
438             mdb->cmd, sql_strerror(mdb));
439       stat = 0;
440    } else {
441       mr->MediaId = sql_insert_id(mdb, NT_("Media"));
442       stat = 1;
443       if (mr->set_label_date) {
444          char dt[MAX_TIME_LENGTH];
445          if (mr->LabelDate == 0) {
446             mr->LabelDate = time(NULL);
447          }
448          (void)localtime_r(&mr->LabelDate, &tm);
449          strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
450          Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
451               "WHERE MediaId=%d", dt, mr->MediaId);
452          stat = UPDATE_DB(jcr, mdb, mdb->cmd);
453       }
454    }
455
456    /*
457     * Make sure that if InChanger is non-zero any other identical slot
458     *   has InChanger zero.
459     */
460    db_make_inchanger_unique(jcr, mdb, mr);
461
462    db_unlock(mdb);
463    return stat;
464 }
465
466 /*
467  * Create a Unique record for the client -- no duplicates
468  * Returns: 0 on failure
469  *          1 on success with id in cr->ClientId
470  */
471 int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
472 {
473    SQL_ROW row;
474    int stat;
475    char ed1[50], ed2[50];
476
477    db_lock(mdb);
478    Mmsg(mdb->cmd, "SELECT ClientId,Uname FROM Client WHERE Name='%s'", cr->Name);
479
480    cr->ClientId = 0;
481    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
482       mdb->num_rows = sql_num_rows(mdb);
483       /* If more than one, report error, but return first row */
484       if (mdb->num_rows > 1) {
485          Mmsg1(&mdb->errmsg, _("More than one Client!: %d\n"), (int)(mdb->num_rows));
486          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
487       }
488       if (mdb->num_rows >= 1) {
489          if ((row = sql_fetch_row(mdb)) == NULL) {
490             Mmsg1(&mdb->errmsg, _("error fetching Client row: %s\n"), sql_strerror(mdb));
491             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
492             sql_free_result(mdb);
493             db_unlock(mdb);
494             return 0;
495          }
496          cr->ClientId = str_to_int64(row[0]);
497          if (row[1]) {
498             bstrncpy(cr->Uname, row[1], sizeof(cr->Uname));
499          } else {
500             cr->Uname[0] = 0;         /* no name */
501          }
502          sql_free_result(mdb);
503          db_unlock(mdb);
504          return 1;
505       }
506       sql_free_result(mdb);
507    }
508
509    /* Must create it */
510    Mmsg(mdb->cmd, "INSERT INTO Client (Name,Uname,AutoPrune,"
511 "FileRetention,JobRetention) VALUES "
512 "('%s','%s',%d,%s,%s)", cr->Name, cr->Uname, cr->AutoPrune,
513       edit_uint64(cr->FileRetention, ed1),
514       edit_uint64(cr->JobRetention, ed2));
515
516    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
517       Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
518             mdb->cmd, sql_strerror(mdb));
519       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
520       cr->ClientId = 0;
521       stat = 0;
522    } else {
523       cr->ClientId = sql_insert_id(mdb, NT_("Client"));
524       stat = 1;
525    }
526    db_unlock(mdb);
527    return stat;
528 }
529
530
531
532
533
534 /*
535  * Create a Unique record for the counter -- no duplicates
536  * Returns: 0 on failure
537  *          1 on success with counter filled in
538  */
539 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
540 {
541    COUNTER_DBR mcr;
542    int stat;
543
544    db_lock(mdb);
545    memset(&mcr, 0, sizeof(mcr));
546    bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
547    if (db_get_counter_record(jcr, mdb, &mcr)) {
548       memcpy(cr, &mcr, sizeof(COUNTER_DBR));
549       db_unlock(mdb);
550       return 1;
551    }
552
553    /* Must create it */
554    Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue,"
555       "WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
556       cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
557       cr->WrapCounter);
558
559    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
560       Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
561             mdb->cmd, sql_strerror(mdb));
562       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
563       stat = 0;
564    } else {
565       stat = 1;
566    }
567    db_unlock(mdb);
568    return stat;
569 }
570
571
572 /*
573  * Create a FileSet record. This record is unique in the
574  *  name and the MD5 signature of the include/exclude sets.
575  *  Returns: 0 on failure
576  *           1 on success with FileSetId in record
577  */
578 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
579 {
580    SQL_ROW row;
581    bool stat;
582    struct tm tm;
583
584    db_lock(mdb);
585    fsr->created = false;
586    Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
587 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
588
589    fsr->FileSetId = 0;
590    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
591       mdb->num_rows = sql_num_rows(mdb);
592       if (mdb->num_rows > 1) {
593          Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
594          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
595       }
596       if (mdb->num_rows >= 1) {
597          if ((row = sql_fetch_row(mdb)) == NULL) {
598             Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
599             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
600             sql_free_result(mdb);
601             db_unlock(mdb);
602             return false;
603          }
604          fsr->FileSetId = str_to_int64(row[0]);
605          if (row[1] == NULL) {
606             fsr->cCreateTime[0] = 0;
607          } else {
608             bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
609          }
610          sql_free_result(mdb);
611          db_unlock(mdb);
612          return true;
613       }
614       sql_free_result(mdb);
615    }
616
617    if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
618       fsr->CreateTime = time(NULL);
619    }
620    (void)localtime_r(&fsr->CreateTime, &tm);
621    strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
622
623    /* Must create it */
624       Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
625 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
626
627    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
628       Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
629             mdb->cmd, sql_strerror(mdb));
630       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
631       fsr->FileSetId = 0;
632       stat = false;
633    } else {
634       fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet"));
635       fsr->created = true;
636       stat = true;
637    }
638
639    db_unlock(mdb);
640    return stat;
641 }
642
643
644 /*
645  *  struct stat
646  *  {
647  *      dev_t         st_dev;       * device *
648  *      ino_t         st_ino;       * inode *
649  *      mode_t        st_mode;      * protection *
650  *      nlink_t       st_nlink;     * number of hard links *
651  *      uid_t         st_uid;       * user ID of owner *
652  *      gid_t         st_gid;       * group ID of owner *
653  *      dev_t         st_rdev;      * device type (if inode device) *
654  *      off_t         st_size;      * total size, in bytes *
655  *      unsigned long st_blksize;   * blocksize for filesystem I/O *
656  *      unsigned long st_blocks;    * number of blocks allocated *
657  *      time_t        st_atime;     * time of last access *
658  *      time_t        st_mtime;     * time of last modification *
659  *      time_t        st_ctime;     * time of last inode change *
660  *  };
661  */
662
663
664
665 /*
666  * Create File record in B_DB
667  *
668  *  In order to reduce database size, we store the File attributes,
669  *  the FileName, and the Path separately.  In principle, there
670  *  is a single FileName record and a single Path record, no matter
671  *  how many times it occurs.  This is this subroutine, we separate
672  *  the file and the path and create three database records.
673  */
674 int db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
675 {
676
677    db_lock(mdb);
678    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
679    Dmsg0(dbglevel, "put_file_into_catalog\n");
680    /*
681     * Make sure we have an acceptable attributes record.
682     */
683    if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
684          ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
685       Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
686          ar->Stream);
687       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
688       goto bail_out;
689    }
690
691
692    split_path_and_file(jcr, mdb, ar->fname);
693
694    if (!db_create_filename_record(jcr, mdb, ar)) {
695       goto bail_out;
696    }
697    Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
698
699
700    if (!db_create_path_record(jcr, mdb, ar)) {
701       goto bail_out;
702    }
703    Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
704
705    /* Now create master File record */
706    if (!db_create_file_record(jcr, mdb, ar)) {
707       goto bail_out;
708    }
709    Dmsg0(dbglevel, "db_create_file_record OK\n");
710
711    Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
712    db_unlock(mdb);
713    return 1;
714
715 bail_out:
716    db_unlock(mdb);
717    return 0;
718 }
719
720 /*
721  * This is the master File entry containing the attributes.
722  *  The filename and path records have already been created.
723  */
724 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
725 {
726    int stat;
727    static char *no_digest = "0";
728    char *digest;
729
730    ASSERT(ar->JobId);
731    ASSERT(ar->PathId);
732    ASSERT(ar->FilenameId);
733
734    if (ar->Digest == NULL || ar->Digest[0] == 0) {
735       digest = no_digest;
736    } else {
737       digest = ar->Digest;
738    }
739
740    /* Must create it */
741    Mmsg(mdb->cmd,
742         "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
743         "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
744         ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
745         ar->attr, digest);
746
747    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
748       Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
749          mdb->cmd, sql_strerror(mdb));
750       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
751       ar->FileId = 0;
752       stat = 0;
753    } else {
754       ar->FileId = sql_insert_id(mdb, NT_("File"));
755       stat = 1;
756    }
757    return stat;
758 }
759
760 /* Create a Unique record for the Path -- no duplicates */
761 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
762 {
763    SQL_ROW row;
764    int stat;
765
766    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
767    db_escape_string(mdb->esc_name, mdb->path, mdb->pnl);
768
769    if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
770        strcmp(mdb->cached_path, mdb->path) == 0) {
771       ar->PathId = mdb->cached_path_id;
772       return 1;
773    }
774
775    Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
776
777    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
778       mdb->num_rows = sql_num_rows(mdb);
779       if (mdb->num_rows > 1) {
780          char ed1[30];
781          Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
782             edit_uint64(mdb->num_rows, ed1), mdb->path);
783          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
784       }
785       /* Even if there are multiple paths, take the first one */
786       if (mdb->num_rows >= 1) {
787          if ((row = sql_fetch_row(mdb)) == NULL) {
788             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
789             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
790             sql_free_result(mdb);
791             ar->PathId = 0;
792             ASSERT(ar->PathId);
793             return 0;
794          }
795          ar->PathId = str_to_int64(row[0]);
796          sql_free_result(mdb);
797          /* Cache path */
798          if (ar->PathId != mdb->cached_path_id) {
799             mdb->cached_path_id = ar->PathId;
800             mdb->cached_path_len = mdb->pnl;
801             pm_strcpy(mdb->cached_path, mdb->path);
802          }
803          ASSERT(ar->PathId);
804          return 1;
805       }
806       sql_free_result(mdb);
807    }
808
809    Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
810
811    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
812       Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"),
813          mdb->cmd, sql_strerror(mdb));
814       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
815       ar->PathId = 0;
816       stat = 0;
817    } else {
818       ar->PathId = sql_insert_id(mdb, NT_("Path"));
819       stat = 1;
820    }
821
822    /* Cache path */
823    if (stat && ar->PathId != mdb->cached_path_id) {
824       mdb->cached_path_id = ar->PathId;
825       mdb->cached_path_len = mdb->pnl;
826       pm_strcpy(mdb->cached_path, mdb->path);
827    }
828    return stat;
829 }
830
831 /* Create a Unique record for the filename -- no duplicates */
832 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
833 {
834    SQL_ROW row;
835
836    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
837    db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl);
838
839    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
840
841    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
842       mdb->num_rows = sql_num_rows(mdb);
843       if (mdb->num_rows > 1) {
844          char ed1[30];
845          Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
846             edit_uint64(mdb->num_rows, ed1), mdb->fname);
847          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
848       }
849       if (mdb->num_rows >= 1) {
850          if ((row = sql_fetch_row(mdb)) == NULL) {
851             Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
852                 mdb->fname, sql_strerror(mdb));
853             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
854             ar->FilenameId = 0;
855          } else {
856             ar->FilenameId = str_to_int64(row[0]);
857          }
858          sql_free_result(mdb);
859          return ar->FilenameId > 0;
860       }
861       sql_free_result(mdb);
862    }
863
864    Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
865
866    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
867       Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
868             mdb->cmd, sql_strerror(mdb));
869       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
870       ar->FilenameId = 0;
871    } else {
872       ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
873    }
874    return ar->FilenameId > 0;
875 }
876
877 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL */