2 * Bacula Catalog Database Create record interface routines
4 * Kern Sibbald, March 2000
9 Bacula® - The Network Backup Solution
11 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
13 The main author of Bacula is Kern Sibbald, with contributions from
14 many others, a complete list can be found in the file AUTHORS.
15 This program is Free Software; you can redistribute it and/or
16 modify it under the terms of version two of the GNU General Public
17 License as published by the Free Software Foundation plus additions
18 that are listed in the file LICENSE.
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 Bacula® is a registered trademark of John Walker.
31 The licensor of Bacula is the Free Software Foundation Europe
32 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33 Switzerland, email:ftf@fsfeurope.org.
36 /* The following is necessary so that we do not include
37 * the dummy external definition of DB.
39 #define __SQL_C /* indicate that this is sql.c */
44 static const int dbglevel = 500;
46 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
48 /* -----------------------------------------------------------------------
50 * Generic Routines (or almost generic)
52 * -----------------------------------------------------------------------
55 /* Forward referenced subroutines */
56 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
57 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
58 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
61 /* Create a new record for the Job
62 * Returns: false on failure
66 db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
68 char dt[MAX_TIME_LENGTH];
77 stime = jr->SchedTime;
80 (void)localtime_r(&stime, &tm);
81 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
82 JobTDate = (utime_t)stime;
86 "INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate,ClientId) "
87 "VALUES ('%s','%s','%c','%c','%c','%s',%s,%s)",
88 jr->Job, jr->Name, (char)(jr->JobType), (char)(jr->JobLevel),
89 (char)(jr->JobStatus), dt, edit_uint64(JobTDate, ed1),
90 edit_int64(jr->ClientId, ed2));
92 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
93 Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"),
94 mdb->cmd, sql_strerror(mdb));
98 jr->JobId = sql_insert_id(mdb, NT_("Job"));
106 /* Create a JobMedia record for medium used this job
107 * Returns: false on failure
111 db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
115 char ed1[50], ed2[50];
119 /* Now get count for VolIndex */
120 Mmsg(mdb->cmd, "SELECT count(*) from JobMedia WHERE JobId=%s",
121 edit_int64(jm->JobId, ed1));
122 count = get_sql_record_max(jcr, mdb);
128 /* Note, jm->Strip is not used and is not likely to be used
129 * in the near future, so I have removed it from the insert
130 * to save space in the DB. KES June 2006.
133 "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,"
134 "StartFile,EndFile,StartBlock,EndBlock,VolIndex,Copy) "
135 "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u,%u)",
136 edit_int64(jm->JobId, ed1),
137 edit_int64(jm->MediaId, ed2),
138 jm->FirstIndex, jm->LastIndex,
139 jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count,
142 Dmsg0(300, mdb->cmd);
143 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
144 Mmsg2(&mdb->errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), mdb->cmd,
148 /* Worked, now update the Media record with the EndFile and EndBlock */
150 "UPDATE Media SET EndFile=%u, EndBlock=%u WHERE MediaId=%u",
151 jm->EndFile, jm->EndBlock, jm->MediaId);
152 if (!UPDATE_DB(jcr, mdb, mdb->cmd)) {
153 Mmsg2(&mdb->errmsg, _("Update Media record %s failed: ERR=%s\n"), mdb->cmd,
159 Dmsg0(300, "Return from JobMedia\n");
165 /* Create Unique Pool record
166 * Returns: false on failure
170 db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
173 char ed1[30], ed2[30], ed3[50], ed4[50];
175 Dmsg0(200, "In create pool\n");
177 Mmsg(mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", pr->Name);
178 Dmsg1(200, "selectpool: %s\n", mdb->cmd);
180 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
181 mdb->num_rows = sql_num_rows(mdb);
182 if (mdb->num_rows > 0) {
183 Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pr->Name);
184 sql_free_result(mdb);
188 sql_free_result(mdb);
193 "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog,"
194 "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration,"
195 "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId) "
196 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s)",
198 pr->NumVols, pr->MaxVols,
199 pr->UseOnce, pr->UseCatalog,
201 pr->AutoPrune, pr->Recycle,
202 edit_uint64(pr->VolRetention, ed1),
203 edit_uint64(pr->VolUseDuration, ed2),
204 pr->MaxVolJobs, pr->MaxVolFiles,
205 edit_uint64(pr->MaxVolBytes, ed3),
206 pr->PoolType, pr->LabelType, pr->LabelFormat,
207 edit_int64(pr->RecyclePoolId,ed4));
208 Dmsg1(200, "Create Pool: %s\n", mdb->cmd);
209 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
210 Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
211 mdb->cmd, sql_strerror(mdb));
215 pr->PoolId = sql_insert_id(mdb, NT_("Pool"));
223 * Create Unique Device record
224 * Returns: false on failure
228 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
231 char ed1[30], ed2[30];
233 Dmsg0(200, "In create Device\n");
235 Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
236 Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
238 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
239 mdb->num_rows = sql_num_rows(mdb);
240 if (mdb->num_rows > 0) {
241 Mmsg1(&mdb->errmsg, _("Device record %s already exists\n"), dr->Name);
242 sql_free_result(mdb);
246 sql_free_result(mdb);
251 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
253 edit_uint64(dr->MediaTypeId, ed1),
254 edit_int64(dr->StorageId, ed2));
255 Dmsg1(200, "Create Device: %s\n", mdb->cmd);
256 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
257 Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
258 mdb->cmd, sql_strerror(mdb));
262 dr->DeviceId = sql_insert_id(mdb, NT_("Device"));
272 * Create a Unique record for Storage -- no duplicates
273 * Returns: false on failure
274 * true on success with id in sr->StorageId
276 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
282 Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
286 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
287 mdb->num_rows = sql_num_rows(mdb);
288 /* If more than one, report error, but return first row */
289 if (mdb->num_rows > 1) {
290 Mmsg1(&mdb->errmsg, _("More than one Storage record!: %d\n"), (int)(mdb->num_rows));
291 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
293 if (mdb->num_rows >= 1) {
294 if ((row = sql_fetch_row(mdb)) == NULL) {
295 Mmsg1(&mdb->errmsg, _("error fetching Storage row: %s\n"), sql_strerror(mdb));
296 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
297 sql_free_result(mdb);
301 sr->StorageId = str_to_int64(row[0]);
302 sr->AutoChanger = atoi(row[1]); /* bool */
303 sql_free_result(mdb);
307 sql_free_result(mdb);
311 Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
312 " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
314 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
315 Mmsg2(&mdb->errmsg, _("Create DB Storage record %s failed. ERR=%s\n"),
316 mdb->cmd, sql_strerror(mdb));
317 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
320 sr->StorageId = sql_insert_id(mdb, NT_("Storage"));
330 * Create Unique MediaType record
331 * Returns: false on failure
335 db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr)
339 Dmsg0(200, "In create mediatype\n");
341 Mmsg(mdb->cmd, "SELECT MediaTypeId,MediaType FROM MediaType WHERE MediaType='%s'", mr->MediaType);
342 Dmsg1(200, "selectmediatype: %s\n", mdb->cmd);
344 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
345 mdb->num_rows = sql_num_rows(mdb);
346 if (mdb->num_rows > 0) {
347 Mmsg1(&mdb->errmsg, _("mediatype record %s already exists\n"), mr->MediaType);
348 sql_free_result(mdb);
352 sql_free_result(mdb);
357 "INSERT INTO MediaType (MediaType,ReadOnly) "
361 Dmsg1(200, "Create mediatype: %s\n", mdb->cmd);
362 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
363 Mmsg2(&mdb->errmsg, _("Create db mediatype record %s failed: ERR=%s\n"),
364 mdb->cmd, sql_strerror(mdb));
368 mr->MediaTypeId = sql_insert_id(mdb, NT_("MediaType"));
377 * Create Media record. VolumeName and non-zero Slot must be unique
379 * Returns: 0 on failure
383 db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
386 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
387 char ed9[50], ed10[50], ed11[50], ed12[50];
391 Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName='%s'",
393 Dmsg1(500, "selectpool: %s\n", mdb->cmd);
395 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
396 mdb->num_rows = sql_num_rows(mdb);
397 if (mdb->num_rows > 0) {
398 Mmsg1(&mdb->errmsg, _("Volume \"%s\" already exists.\n"), mr->VolumeName);
399 sql_free_result(mdb);
403 sql_free_result(mdb);
408 "INSERT INTO Media (VolumeName,MediaType,MediaTypeId,PoolId,MaxVolBytes,"
409 "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
410 "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts,"
411 "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId,"
412 "ScratchPoolId,RecyclePoolId,Enabled)"
413 "VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s,"
416 mr->MediaType, mr->PoolId,
417 edit_uint64(mr->MaxVolBytes,ed1),
418 edit_uint64(mr->VolCapacityBytes, ed2),
420 edit_uint64(mr->VolRetention, ed3),
421 edit_uint64(mr->VolUseDuration, ed4),
426 edit_uint64(mr->VolBytes, ed5),
428 edit_int64(mr->VolReadTime, ed6),
429 edit_int64(mr->VolWriteTime, ed7),
432 edit_int64(mr->StorageId, ed8),
433 edit_int64(mr->DeviceId, ed9),
434 edit_int64(mr->LocationId, ed10),
435 edit_int64(mr->ScratchPoolId, ed11),
436 edit_int64(mr->RecyclePoolId, ed12),
441 Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
442 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
443 Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
444 mdb->cmd, sql_strerror(mdb));
447 mr->MediaId = sql_insert_id(mdb, NT_("Media"));
449 if (mr->set_label_date) {
450 char dt[MAX_TIME_LENGTH];
451 if (mr->LabelDate == 0) {
452 mr->LabelDate = time(NULL);
454 (void)localtime_r(&mr->LabelDate, &tm);
455 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
456 Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
457 "WHERE MediaId=%d", dt, mr->MediaId);
458 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
463 * Make sure that if InChanger is non-zero any other identical slot
464 * has InChanger zero.
466 db_make_inchanger_unique(jcr, mdb, mr);
473 * Create a Unique record for the client -- no duplicates
474 * Returns: 0 on failure
475 * 1 on success with id in cr->ClientId
477 int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
481 char ed1[50], ed2[50];
484 Mmsg(mdb->cmd, "SELECT ClientId,Uname FROM Client WHERE Name='%s'", cr->Name);
487 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
488 mdb->num_rows = sql_num_rows(mdb);
489 /* If more than one, report error, but return first row */
490 if (mdb->num_rows > 1) {
491 Mmsg1(&mdb->errmsg, _("More than one Client!: %d\n"), (int)(mdb->num_rows));
492 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
494 if (mdb->num_rows >= 1) {
495 if ((row = sql_fetch_row(mdb)) == NULL) {
496 Mmsg1(&mdb->errmsg, _("error fetching Client row: %s\n"), sql_strerror(mdb));
497 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
498 sql_free_result(mdb);
502 cr->ClientId = str_to_int64(row[0]);
504 bstrncpy(cr->Uname, row[1], sizeof(cr->Uname));
506 cr->Uname[0] = 0; /* no name */
508 sql_free_result(mdb);
512 sql_free_result(mdb);
516 Mmsg(mdb->cmd, "INSERT INTO Client (Name,Uname,AutoPrune,"
517 "FileRetention,JobRetention) VALUES "
518 "('%s','%s',%d,%s,%s)", cr->Name, cr->Uname, cr->AutoPrune,
519 edit_uint64(cr->FileRetention, ed1),
520 edit_uint64(cr->JobRetention, ed2));
522 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
523 Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
524 mdb->cmd, sql_strerror(mdb));
525 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
529 cr->ClientId = sql_insert_id(mdb, NT_("Client"));
541 * Create a Unique record for the counter -- no duplicates
542 * Returns: 0 on failure
543 * 1 on success with counter filled in
545 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
551 memset(&mcr, 0, sizeof(mcr));
552 bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
553 if (db_get_counter_record(jcr, mdb, &mcr)) {
554 memcpy(cr, &mcr, sizeof(COUNTER_DBR));
560 Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue,"
561 "WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
562 cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
565 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
566 Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
567 mdb->cmd, sql_strerror(mdb));
568 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
579 * Create a FileSet record. This record is unique in the
580 * name and the MD5 signature of the include/exclude sets.
581 * Returns: 0 on failure
582 * 1 on success with FileSetId in record
584 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
591 fsr->created = false;
592 Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
593 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
596 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
597 mdb->num_rows = sql_num_rows(mdb);
598 if (mdb->num_rows > 1) {
599 Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
600 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
602 if (mdb->num_rows >= 1) {
603 if ((row = sql_fetch_row(mdb)) == NULL) {
604 Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
605 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
606 sql_free_result(mdb);
610 fsr->FileSetId = str_to_int64(row[0]);
611 if (row[1] == NULL) {
612 fsr->cCreateTime[0] = 0;
614 bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
616 sql_free_result(mdb);
620 sql_free_result(mdb);
623 if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
624 fsr->CreateTime = time(NULL);
626 (void)localtime_r(&fsr->CreateTime, &tm);
627 strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
630 Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
631 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
633 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
634 Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
635 mdb->cmd, sql_strerror(mdb));
636 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
640 fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet"));
653 * dev_t st_dev; * device *
654 * ino_t st_ino; * inode *
655 * mode_t st_mode; * protection *
656 * nlink_t st_nlink; * number of hard links *
657 * uid_t st_uid; * user ID of owner *
658 * gid_t st_gid; * group ID of owner *
659 * dev_t st_rdev; * device type (if inode device) *
660 * off_t st_size; * total size, in bytes *
661 * unsigned long st_blksize; * blocksize for filesystem I/O *
662 * unsigned long st_blocks; * number of blocks allocated *
663 * time_t st_atime; * time of last access *
664 * time_t st_mtime; * time of last modification *
665 * time_t st_ctime; * time of last inode change *
669 /* All db_batch_* functions are used to do bulk batch insert in File/Filename/Path
670 * tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1"
674 * - bulk load a temp table
675 * - insert missing filenames into filename with a single query (lock filenames
676 * - table before that to avoid possible duplicate inserts with concurrent update)
677 * - insert missing paths into path with another single query
678 * - then insert the join between the temp, filename and path tables into file.
681 int db_batch_start(B_DB *mdb)
683 return sql_query(mdb,
684 " CREATE TEMPORARY TABLE batch "
685 " (fileindex integer, "
693 int db_batch_insert(B_DB *mdb, ATTR_DBR *ar)
699 mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
700 db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl);
702 mdb->esc_name2 = check_pool_memory_size(mdb->esc_name2, mdb->pnl*2+1);
703 db_escape_string(mdb->esc_name2, mdb->path, mdb->pnl);
705 if (ar->Digest == NULL || ar->Digest[0] == 0) {
711 len = Mmsg(mdb->cmd, "INSERT INTO batch VALUES (%u,%s,'%s','%s','%s','%s')",
712 ar->FileIndex, edit_int64(ar->JobId,ed1), mdb->path,
713 mdb->fname, ar->attr, digest);
715 sql_query(mdb, mdb->cmd);
720 /* set error to something to abort operation */
721 int db_batch_end(B_DB *mdb, const char *error)
724 Dmsg0(50, "db_batch_end started");
733 int db_create_batch_file_record(JCR *jcr)
735 Dmsg0(50,"db_create_file_record : no files");
737 if (!jcr->db_batch) { /* no files to backup ? */
738 Dmsg0(50,"db_create_file_record : no files\n");
742 if (sql_batch_end(jcr->db_batch, NULL)) {
743 Jmsg(jcr, M_FATAL, 0, "Bad batch end %s\n", jcr->db_batch->errmsg);
747 /* we have to lock tables */
748 if (sql_query(jcr->db_batch, sql_batch_lock_path_query))
750 Jmsg(jcr, M_FATAL, 0, "Can't lock Path table %s\n", jcr->db_batch->errmsg);
754 if (sql_query(jcr->db_batch, sql_batch_fill_path_query))
756 Jmsg(jcr, M_FATAL, 0, "Can't fill Path table %s\n",jcr->db_batch->errmsg);
757 sql_query(jcr->db_batch, sql_batch_unlock_tables_query);
761 if (sql_query(jcr->db_batch, sql_batch_unlock_tables_query))
763 Jmsg(jcr, M_FATAL, 0, "Can't unlock Path table %s\n", jcr->db_batch->errmsg);
767 /* we have to lock tables */
768 if (sql_query(jcr->db_batch, sql_batch_lock_filename_query))
770 Jmsg(jcr, M_FATAL, 0, "Can't lock Filename table %s\n", jcr->db_batch->errmsg);
774 if (sql_query(jcr->db_batch, sql_batch_fill_filename_query))
776 Jmsg(jcr,M_FATAL,0,"Can't fill Filename table %s\n",jcr->db_batch->errmsg);
777 sql_query(jcr->db_batch, sql_batch_unlock_tables_query);
781 if (sql_query(jcr->db_batch, sql_batch_unlock_tables_query)) {
782 Jmsg(jcr, M_FATAL, 0, "Can't unlock Filename table %s\n", jcr->db_batch->errmsg);
786 if (sql_query(jcr->db_batch,
787 " INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
788 " SELECT batch.FileIndex, batch.JobId, Path.PathId, "
789 " Filename.FilenameId,batch.LStat, batch.MD5 "
791 " JOIN Path ON (batch.Path = Path.Path) "
792 " JOIN Filename ON (batch.Name = Filename.Name) "))
794 Jmsg(jcr, M_FATAL, 0, "Can't fill File table %s\n", jcr->db_batch->errmsg);
798 sql_query(jcr->db_batch, "DROP TABLE batch");
803 #ifdef HAVE_BATCH_FILE_INSERT
805 * Create File record in B_DB
807 * In order to reduce database size, we store the File attributes,
808 * the FileName, and the Path separately. In principle, there
809 * is a single FileName record and a single Path record, no matter
810 * how many times it occurs. This is this subroutine, we separate
811 * the file and the path and fill temporary tables with this three records.
813 int db_create_file_attributes_record(JCR *jcr, B_DB *_mdb, ATTR_DBR *ar)
816 Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
817 Dmsg0(dbglevel, "put_file_into_catalog\n");
819 if (!jcr->db_batch) {
820 jcr->db_batch = db_init_database(jcr,
823 jcr->db->db_password,
827 1 /* multi_db = true */);
829 if (!jcr->db_batch || !db_open_database(jcr, jcr->db_batch)) {
830 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
833 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db_batch));
838 sql_batch_start(jcr->db_batch);
841 B_DB *mdb = jcr->db_batch;
844 * Make sure we have an acceptable attributes record.
846 if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
847 ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
848 Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
850 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
854 split_path_and_file(jcr, mdb, ar->fname);
858 if (jcr->changes > 100000) {
859 sql_batch_end(mdb, NULL);
860 sql_batch_start(mdb);
865 return (sql_batch_insert(mdb, ar) == 0);
868 #else /* ! HAVE_BATCH_FILE_INSERT */
871 * Create File record in B_DB
873 * In order to reduce database size, we store the File attributes,
874 * the FileName, and the Path separately. In principle, there
875 * is a single FileName record and a single Path record, no matter
876 * how many times it occurs. This is this subroutine, we separate
877 * the file and the path and create three database records.
879 int db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
883 Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
884 Dmsg0(dbglevel, "put_file_into_catalog\n");
886 * Make sure we have an acceptable attributes record.
888 if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
889 ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
890 Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
892 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
897 split_path_and_file(jcr, mdb, ar->fname);
899 if (!db_create_filename_record(jcr, mdb, ar)) {
902 Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
905 if (!db_create_path_record(jcr, mdb, ar)) {
908 Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
910 /* Now create master File record */
911 if (!db_create_file_record(jcr, mdb, ar)) {
914 Dmsg0(dbglevel, "db_create_file_record OK\n");
916 Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
925 #endif /* ! HAVE_BATCH_FILE_INSERT */
928 * This is the master File entry containing the attributes.
929 * The filename and path records have already been created.
931 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
934 static char *no_digest = "0";
939 ASSERT(ar->FilenameId);
941 if (ar->Digest == NULL || ar->Digest[0] == 0) {
949 "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
950 "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
951 ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
954 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
955 Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
956 mdb->cmd, sql_strerror(mdb));
957 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
961 ar->FileId = sql_insert_id(mdb, NT_("File"));
967 /* Create a Unique record for the Path -- no duplicates */
968 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
973 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
974 db_escape_string(mdb->esc_name, mdb->path, mdb->pnl);
976 if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
977 strcmp(mdb->cached_path, mdb->path) == 0) {
978 ar->PathId = mdb->cached_path_id;
982 Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
984 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
985 mdb->num_rows = sql_num_rows(mdb);
986 if (mdb->num_rows > 1) {
988 Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
989 edit_uint64(mdb->num_rows, ed1), mdb->path);
990 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
992 /* Even if there are multiple paths, take the first one */
993 if (mdb->num_rows >= 1) {
994 if ((row = sql_fetch_row(mdb)) == NULL) {
995 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
996 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
997 sql_free_result(mdb);
1002 ar->PathId = str_to_int64(row[0]);
1003 sql_free_result(mdb);
1005 if (ar->PathId != mdb->cached_path_id) {
1006 mdb->cached_path_id = ar->PathId;
1007 mdb->cached_path_len = mdb->pnl;
1008 pm_strcpy(mdb->cached_path, mdb->path);
1013 sql_free_result(mdb);
1016 Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
1018 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1019 Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"),
1020 mdb->cmd, sql_strerror(mdb));
1021 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1025 ar->PathId = sql_insert_id(mdb, NT_("Path"));
1030 if (stat && ar->PathId != mdb->cached_path_id) {
1031 mdb->cached_path_id = ar->PathId;
1032 mdb->cached_path_len = mdb->pnl;
1033 pm_strcpy(mdb->cached_path, mdb->path);
1038 /* Create a Unique record for the filename -- no duplicates */
1039 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1043 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
1044 db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl);
1046 Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
1048 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1049 mdb->num_rows = sql_num_rows(mdb);
1050 if (mdb->num_rows > 1) {
1052 Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
1053 edit_uint64(mdb->num_rows, ed1), mdb->fname);
1054 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1056 if (mdb->num_rows >= 1) {
1057 if ((row = sql_fetch_row(mdb)) == NULL) {
1058 Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
1059 mdb->fname, sql_strerror(mdb));
1060 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1063 ar->FilenameId = str_to_int64(row[0]);
1065 sql_free_result(mdb);
1066 return ar->FilenameId > 0;
1068 sql_free_result(mdb);
1071 Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
1073 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1074 Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
1075 mdb->cmd, sql_strerror(mdb));
1076 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1079 ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
1081 return ar->FilenameId > 0;
1084 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL */