2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
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
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.
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
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.
29 * Bacula Catalog Database Create record interface routines
31 * Kern Sibbald, March 2000
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 #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 */
63 /* Create a new record for the Job
64 * Returns: false on failure
68 db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
70 char dt[MAX_TIME_LENGTH];
79 stime = jr->SchedTime;
82 (void)localtime_r(&stime, &tm);
83 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
84 JobTDate = (utime_t)stime;
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));
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));
100 jr->JobId = sql_insert_id(mdb, NT_("Job"));
108 /* Create a JobMedia record for medium used this job
109 * Returns: false on failure
113 db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
117 char ed1[50], ed2[50];
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);
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.
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,
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,
150 /* Worked, now update the Media record with the EndFile and EndBlock */
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,
161 Dmsg0(300, "Return from JobMedia\n");
167 /* Create Unique Pool record
168 * Returns: false on failure
172 db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
175 char ed1[30], ed2[30], ed3[50], ed4[50];
177 Dmsg0(200, "In create pool\n");
179 Mmsg(mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", pr->Name);
180 Dmsg1(200, "selectpool: %s\n", mdb->cmd);
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);
190 sql_free_result(mdb);
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)",
200 pr->NumVols, pr->MaxVols,
201 pr->UseOnce, pr->UseCatalog,
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));
217 pr->PoolId = sql_insert_id(mdb, NT_("Pool"));
225 * Create Unique Device record
226 * Returns: false on failure
230 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
233 char ed1[30], ed2[30];
235 Dmsg0(200, "In create Device\n");
237 Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
238 Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
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);
248 sql_free_result(mdb);
253 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
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));
264 dr->DeviceId = sql_insert_id(mdb, NT_("Device"));
274 * Create a Unique record for Storage -- no duplicates
275 * Returns: false on failure
276 * true on success with id in sr->StorageId
278 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
284 Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
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);
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);
303 sr->StorageId = str_to_int64(row[0]);
304 sr->AutoChanger = atoi(row[1]); /* bool */
305 sql_free_result(mdb);
309 sql_free_result(mdb);
313 Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
314 " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
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);
322 sr->StorageId = sql_insert_id(mdb, NT_("Storage"));
332 * Create Unique MediaType record
333 * Returns: false on failure
337 db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr)
341 Dmsg0(200, "In create mediatype\n");
343 Mmsg(mdb->cmd, "SELECT MediaTypeId,MediaType FROM MediaType WHERE MediaType='%s'", mr->MediaType);
344 Dmsg1(200, "selectmediatype: %s\n", mdb->cmd);
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);
354 sql_free_result(mdb);
359 "INSERT INTO MediaType (MediaType,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));
370 mr->MediaTypeId = sql_insert_id(mdb, NT_("MediaType"));
379 * Create Media record. VolumeName and non-zero Slot must be unique
381 * Returns: 0 on failure
385 db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
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];
393 Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName='%s'",
395 Dmsg1(500, "selectpool: %s\n", mdb->cmd);
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);
405 sql_free_result(mdb);
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,"
418 mr->MediaType, mr->PoolId,
419 edit_uint64(mr->MaxVolBytes,ed1),
420 edit_uint64(mr->VolCapacityBytes, ed2),
422 edit_uint64(mr->VolRetention, ed3),
423 edit_uint64(mr->VolUseDuration, ed4),
428 edit_uint64(mr->VolBytes, ed5),
430 edit_int64(mr->VolReadTime, ed6),
431 edit_int64(mr->VolWriteTime, ed7),
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),
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));
449 mr->MediaId = sql_insert_id(mdb, NT_("Media"));
451 if (mr->set_label_date) {
452 char dt[MAX_TIME_LENGTH];
453 if (mr->LabelDate == 0) {
454 mr->LabelDate = time(NULL);
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);
465 * Make sure that if InChanger is non-zero any other identical slot
466 * has InChanger zero.
468 db_make_inchanger_unique(jcr, mdb, mr);
475 * Create a Unique record for the client -- no duplicates
476 * Returns: 0 on failure
477 * 1 on success with id in cr->ClientId
479 int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
483 char ed1[50], ed2[50];
486 Mmsg(mdb->cmd, "SELECT ClientId,Uname FROM Client WHERE Name='%s'", cr->Name);
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);
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);
504 cr->ClientId = str_to_int64(row[0]);
506 bstrncpy(cr->Uname, row[1], sizeof(cr->Uname));
508 cr->Uname[0] = 0; /* no name */
510 sql_free_result(mdb);
514 sql_free_result(mdb);
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));
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);
531 cr->ClientId = sql_insert_id(mdb, NT_("Client"));
543 * Create a Unique record for the counter -- no duplicates
544 * Returns: 0 on failure
545 * 1 on success with counter filled in
547 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
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));
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,
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);
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
586 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
593 fsr->created = false;
594 Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
595 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
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);
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);
612 fsr->FileSetId = str_to_int64(row[0]);
613 if (row[1] == NULL) {
614 fsr->cCreateTime[0] = 0;
616 bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
618 sql_free_result(mdb);
622 sql_free_result(mdb);
625 if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
626 fsr->CreateTime = time(NULL);
628 (void)localtime_r(&fsr->CreateTime, &tm);
629 strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
632 Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
633 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
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);
642 fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet"));
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 *
671 #ifdef HAVE_BATCH_FILE_INSERT
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"
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.
689 bool my_batch_start(JCR *jcr, B_DB *mdb)
694 ok = db_sql_query(mdb,
695 "CREATE TEMPORARY TABLE batch ("
701 "MD5 tinyblob)",NULL, NULL);
710 bool my_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
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);
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);
722 if (ar->Digest == NULL || ar->Digest[0] == 0) {
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);
732 return INSERT_DB(jcr, mdb, mdb->cmd);
735 /* set error to something to abort operation */
740 bool my_batch_end(JCR *jcr, B_DB *mdb, const char *error)
743 Dmsg0(50, "sql_batch_end started\n");
755 bool db_write_batch_file_records(JCR *jcr)
757 int JobStatus = jcr->JobStatus;
759 if (!jcr->db_batch) { /* no files to backup ? */
760 Dmsg0(50,"db_create_file_record : no files\n");
763 if (job_canceled(jcr)) {
767 Dmsg1(50,"db_create_file_record changes=%u\n",jcr->db_batch->changes);
769 jcr->JobStatus = JS_AttrInserting;
770 if (!sql_batch_end(jcr, jcr->db_batch, NULL)) {
771 Jmsg(jcr, M_FATAL, 0, "Bad batch end %s\n", jcr->db_batch->errmsg);
774 if (job_canceled(jcr)) {
779 /* we have to lock tables */
780 if (!db_sql_query(jcr->db_batch, sql_batch_lock_path_query, NULL, NULL)) {
781 Jmsg(jcr, M_FATAL, 0, "Can't lock Path table %s\n", jcr->db_batch->errmsg);
785 if (!db_sql_query(jcr->db_batch, sql_batch_fill_path_query, NULL, NULL)) {
786 Jmsg(jcr, M_FATAL, 0, "Can't fill Path table %s\n",jcr->db_batch->errmsg);
787 db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
791 if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
792 Jmsg(jcr, M_FATAL, 0, "Can't unlock Path table %s\n", jcr->db_batch->errmsg);
796 /* we have to lock tables */
797 if (!db_sql_query(jcr->db_batch,sql_batch_lock_filename_query,NULL, NULL)) {
798 Jmsg(jcr, M_FATAL, 0, "Can't lock Filename table %s\n", jcr->db_batch->errmsg);
802 if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) {
803 Jmsg(jcr,M_FATAL,0,"Can't fill Filename table %s\n",jcr->db_batch->errmsg);
804 db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
808 if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
809 Jmsg(jcr, M_FATAL, 0, "Can't unlock Filename table %s\n", jcr->db_batch->errmsg);
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 "
818 "JOIN Path ON (batch.Path = Path.Path) "
819 "JOIN Filename ON (batch.Name = Filename.Name)",
822 Jmsg(jcr, M_FATAL, 0, "Can't fill File table %s\n", jcr->db_batch->errmsg);
826 db_sql_query(jcr->db_batch, "DROP TABLE batch", NULL,NULL);
828 jcr->JobStatus = JobStatus; /* reset entry status */
833 * Create File record in B_DB
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.
841 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
843 Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
844 Dmsg0(dbglevel, "put_file_into_catalog\n");
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,
855 1 /* multi_db = true */);
856 if (!jcr->db_batch) {
857 Mmsg1(&mdb->errmsg, _("Could not init batch database: \"%s\".\n"),
859 Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
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);
870 if (!sql_batch_start(jcr, jcr->db_batch)) {
872 "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
873 Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
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);
879 B_DB *bdb = jcr->db_batch;
882 * Make sure we have an acceptable attributes record.
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"),
888 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
892 split_path_and_file(jcr, bdb, ar->fname);
896 if (bdb->changes > 100000) {
897 db_write_batch_file_records(jcr);
899 sql_batch_start(jcr, bdb);
903 return sql_batch_insert(jcr, bdb, ar);
906 #else /* ! HAVE_BATCH_FILE_INSERT */
909 * Create File record in B_DB
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.
917 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
920 Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
921 Dmsg0(dbglevel, "put_file_into_catalog\n");
923 * Make sure we have an acceptable attributes record.
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"),
929 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
934 split_path_and_file(jcr, mdb, ar->fname);
936 if (!db_create_filename_record(jcr, mdb, ar)) {
939 Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
942 if (!db_create_path_record(jcr, mdb, ar)) {
945 Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
947 /* Now create master File record */
948 if (!db_create_file_record(jcr, mdb, ar)) {
951 Dmsg0(dbglevel, "db_create_file_record OK\n");
953 Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
964 * This is the master File entry containing the attributes.
965 * The filename and path records have already been created.
967 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
970 static char *no_digest = "0";
975 ASSERT(ar->FilenameId);
977 if (ar->Digest == NULL || ar->Digest[0] == 0) {
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,
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);
997 ar->FileId = sql_insert_id(mdb, NT_("File"));
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)
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);
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;
1018 Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
1020 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1021 mdb->num_rows = sql_num_rows(mdb);
1022 if (mdb->num_rows > 1) {
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);
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);
1038 ar->PathId = str_to_int64(row[0]);
1039 sql_free_result(mdb);
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);
1049 sql_free_result(mdb);
1052 Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
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);
1061 ar->PathId = sql_insert_id(mdb, NT_("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);
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)
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);
1082 Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
1084 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1085 mdb->num_rows = sql_num_rows(mdb);
1086 if (mdb->num_rows > 1) {
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);
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);
1099 ar->FilenameId = str_to_int64(row[0]);
1101 sql_free_result(mdb);
1102 return ar->FilenameId > 0;
1104 sql_free_result(mdb);
1107 Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
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);
1115 ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
1117 return ar->FilenameId > 0;
1120 bool db_write_batch_file_records(JCR *jcr)
1125 #endif /* ! HAVE_BATCH_FILE_INSERT */
1127 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL */