2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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 Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
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 || HAVE_DBI
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");
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);
461 * Make sure that if InChanger is non-zero any other identical slot
462 * has InChanger zero.
464 db_make_inchanger_unique(jcr, mdb, mr);
472 * Create a Unique record for the client -- no duplicates
473 * Returns: 0 on failure
474 * 1 on success with id in cr->ClientId
476 int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
480 char ed1[50], ed2[50];
483 Mmsg(mdb->cmd, "SELECT ClientId,Uname FROM Client WHERE Name='%s'", cr->Name);
486 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
487 mdb->num_rows = sql_num_rows(mdb);
488 /* If more than one, report error, but return first row */
489 if (mdb->num_rows > 1) {
490 Mmsg1(&mdb->errmsg, _("More than one Client!: %d\n"), (int)(mdb->num_rows));
491 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
493 if (mdb->num_rows >= 1) {
494 if ((row = sql_fetch_row(mdb)) == NULL) {
495 Mmsg1(&mdb->errmsg, _("error fetching Client row: %s\n"), sql_strerror(mdb));
496 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
497 sql_free_result(mdb);
501 cr->ClientId = str_to_int64(row[0]);
503 bstrncpy(cr->Uname, row[1], sizeof(cr->Uname));
505 cr->Uname[0] = 0; /* no name */
507 sql_free_result(mdb);
511 sql_free_result(mdb);
515 Mmsg(mdb->cmd, "INSERT INTO Client (Name,Uname,AutoPrune,"
516 "FileRetention,JobRetention) VALUES "
517 "('%s','%s',%d,%s,%s)", cr->Name, cr->Uname, cr->AutoPrune,
518 edit_uint64(cr->FileRetention, ed1),
519 edit_uint64(cr->JobRetention, ed2));
521 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
522 Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
523 mdb->cmd, sql_strerror(mdb));
524 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
528 cr->ClientId = sql_insert_id(mdb, NT_("Client"));
540 * Create a Unique record for the counter -- no duplicates
541 * Returns: 0 on failure
542 * 1 on success with counter filled in
544 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
550 memset(&mcr, 0, sizeof(mcr));
551 bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
552 if (db_get_counter_record(jcr, mdb, &mcr)) {
553 memcpy(cr, &mcr, sizeof(COUNTER_DBR));
559 Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue,"
560 "WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
561 cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
564 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
565 Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
566 mdb->cmd, sql_strerror(mdb));
567 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
578 * Create a FileSet record. This record is unique in the
579 * name and the MD5 signature of the include/exclude sets.
580 * Returns: 0 on failure
581 * 1 on success with FileSetId in record
583 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
590 fsr->created = false;
591 Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
592 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
595 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
596 mdb->num_rows = sql_num_rows(mdb);
597 if (mdb->num_rows > 1) {
598 Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
599 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
601 if (mdb->num_rows >= 1) {
602 if ((row = sql_fetch_row(mdb)) == NULL) {
603 Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
604 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
605 sql_free_result(mdb);
609 fsr->FileSetId = str_to_int64(row[0]);
610 if (row[1] == NULL) {
611 fsr->cCreateTime[0] = 0;
613 bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
615 sql_free_result(mdb);
619 sql_free_result(mdb);
622 if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
623 fsr->CreateTime = time(NULL);
625 (void)localtime_r(&fsr->CreateTime, &tm);
626 strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
629 Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
630 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
632 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
633 Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
634 mdb->cmd, sql_strerror(mdb));
635 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
639 fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet"));
652 * dev_t st_dev; * device *
653 * ino_t st_ino; * inode *
654 * mode_t st_mode; * protection *
655 * nlink_t st_nlink; * number of hard links *
656 * uid_t st_uid; * user ID of owner *
657 * gid_t st_gid; * group ID of owner *
658 * dev_t st_rdev; * device type (if inode device) *
659 * off_t st_size; * total size, in bytes *
660 * unsigned long st_blksize; * blocksize for filesystem I/O *
661 * unsigned long st_blocks; * number of blocks allocated *
662 * time_t st_atime; * time of last access *
663 * time_t st_mtime; * time of last modification *
664 * time_t st_ctime; * time of last inode change *
668 #ifdef HAVE_BATCH_FILE_INSERT
670 /* All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path
671 * tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1"
675 * - bulk load a temp table
676 * - insert missing filenames into filename with a single query (lock filenames
677 * - table before that to avoid possible duplicate inserts with concurrent update)
678 * - insert missing paths into path with another single query
679 * - then insert the join between the temp, filename and path tables into file.
686 bool my_batch_start(JCR *jcr, B_DB *mdb)
691 ok = db_sql_query(mdb,
692 "CREATE TEMPORARY TABLE batch ("
698 "MD5 tinyblob)",NULL, NULL);
707 bool my_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
713 mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
714 db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
716 mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
717 db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
719 if (ar->Digest == NULL || ar->Digest[0] == 0) {
725 len = Mmsg(mdb->cmd, "INSERT INTO batch VALUES (%u,%s,'%s','%s','%s','%s')",
726 ar->FileIndex, edit_int64(ar->JobId,ed1), mdb->esc_path,
727 mdb->esc_name, ar->attr, digest);
729 return INSERT_DB(jcr, mdb, mdb->cmd);
732 /* set error to something to abort operation */
737 bool my_batch_end(JCR *jcr, B_DB *mdb, const char *error)
740 Dmsg0(50, "sql_batch_end started\n");
744 mdb->status = (dbi_error_flag)0;
756 bool db_write_batch_file_records(JCR *jcr)
758 int JobStatus = jcr->JobStatus;
760 if (!jcr->batch_started) { /* no files to backup ? */
761 Dmsg0(50,"db_create_file_record : no files\n");
764 if (job_canceled(jcr)) {
768 Dmsg1(50,"db_create_file_record changes=%u\n",jcr->db_batch->changes);
770 jcr->JobStatus = JS_AttrInserting;
771 if (!sql_batch_end(jcr, jcr->db_batch, NULL)) {
772 Jmsg1(jcr, M_FATAL, 0, "Batch end %s\n", jcr->db_batch->errmsg);
775 if (job_canceled(jcr)) {
780 /* we have to lock tables */
781 if (!db_sql_query(jcr->db_batch, sql_batch_lock_path_query, NULL, NULL)) {
782 Jmsg1(jcr, M_FATAL, 0, "Lock Path table %s\n", jcr->db_batch->errmsg);
786 if (!db_sql_query(jcr->db_batch, sql_batch_fill_path_query, NULL, NULL)) {
787 Jmsg1(jcr, M_FATAL, 0, "Fill Path table %s\n",jcr->db_batch->errmsg);
788 db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
792 if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
793 Jmsg1(jcr, M_FATAL, 0, "Unlock Path table %s\n", jcr->db_batch->errmsg);
797 /* we have to lock tables */
798 if (!db_sql_query(jcr->db_batch,sql_batch_lock_filename_query,NULL, NULL)) {
799 Jmsg1(jcr, M_FATAL, 0, "Lock Filename table %s\n", jcr->db_batch->errmsg);
803 if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) {
804 Jmsg1(jcr,M_FATAL,0,"Fill Filename table %s\n",jcr->db_batch->errmsg);
805 db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
809 if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
810 Jmsg1(jcr, M_FATAL, 0, "Unlock Filename table %s\n", jcr->db_batch->errmsg);
814 if (!db_sql_query(jcr->db_batch,
815 "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
816 "SELECT batch.FileIndex, batch.JobId, Path.PathId, "
817 "Filename.FilenameId,batch.LStat, batch.MD5 "
819 "JOIN Path ON (batch.Path = Path.Path) "
820 "JOIN Filename ON (batch.Name = Filename.Name)",
823 Jmsg1(jcr, M_FATAL, 0, "Fill File table %s\n", jcr->db_batch->errmsg);
827 db_sql_query(jcr->db_batch, "DROP TABLE batch", NULL,NULL);
829 jcr->JobStatus = JobStatus; /* reset entry status */
834 * Create File record in B_DB
836 * In order to reduce database size, we store the File attributes,
837 * the FileName, and the Path separately. In principle, there
838 * is a single FileName record and a single Path record, no matter
839 * how many times it occurs. This is this subroutine, we separate
840 * the file and the path and fill temporary tables with this three records.
842 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
844 Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
845 Dmsg0(dbglevel, "put_file_into_catalog\n");
847 /* Open the dedicated connexion */
848 if (!jcr->batch_started) {
850 if (!db_open_batch_connexion(jcr, mdb)) {
853 if (!sql_batch_start(jcr, jcr->db_batch)) {
855 "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
856 Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
859 jcr->batch_started = true;
861 B_DB *bdb = jcr->db_batch;
864 * Make sure we have an acceptable attributes record.
866 if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
867 ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
868 Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
870 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
874 split_path_and_file(jcr, bdb, ar->fname);
878 * if (bdb->changes > 100000) {
879 * db_write_batch_file_records(jcr);
881 * sql_batch_start(jcr, bdb);
885 return sql_batch_insert(jcr, bdb, ar);
888 #else /* ! HAVE_BATCH_FILE_INSERT */
891 * Create File record in B_DB
893 * In order to reduce database size, we store the File attributes,
894 * the FileName, and the Path separately. In principle, there
895 * is a single FileName record and a single Path record, no matter
896 * how many times it occurs. This is this subroutine, we separate
897 * the file and the path and create three database records.
899 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
902 Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
903 Dmsg0(dbglevel, "put_file_into_catalog\n");
905 * Make sure we have an acceptable attributes record.
907 if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
908 ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
909 Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
911 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
916 split_path_and_file(jcr, mdb, ar->fname);
918 if (!db_create_filename_record(jcr, mdb, ar)) {
921 Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
924 if (!db_create_path_record(jcr, mdb, ar)) {
927 Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
929 /* Now create master File record */
930 if (!db_create_file_record(jcr, mdb, ar)) {
933 Dmsg0(dbglevel, "db_create_file_record OK\n");
935 Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
946 * This is the master File entry containing the attributes.
947 * The filename and path records have already been created.
949 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
952 static const char *no_digest = "0";
957 ASSERT(ar->FilenameId);
959 if (ar->Digest == NULL || ar->Digest[0] == 0) {
967 "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
968 "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
969 ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
972 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
973 Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
974 mdb->cmd, sql_strerror(mdb));
975 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
979 ar->FileId = sql_insert_id(mdb, NT_("File"));
985 /* Create a Unique record for the Path -- no duplicates */
986 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
991 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
992 db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
994 if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
995 strcmp(mdb->cached_path, mdb->path) == 0) {
996 ar->PathId = mdb->cached_path_id;
1000 Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
1002 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1003 mdb->num_rows = sql_num_rows(mdb);
1004 if (mdb->num_rows > 1) {
1006 Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
1007 edit_uint64(mdb->num_rows, ed1), mdb->path);
1008 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1010 /* Even if there are multiple paths, take the first one */
1011 if (mdb->num_rows >= 1) {
1012 if ((row = sql_fetch_row(mdb)) == NULL) {
1013 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
1014 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1015 sql_free_result(mdb);
1020 ar->PathId = str_to_int64(row[0]);
1021 sql_free_result(mdb);
1023 if (ar->PathId != mdb->cached_path_id) {
1024 mdb->cached_path_id = ar->PathId;
1025 mdb->cached_path_len = mdb->pnl;
1026 pm_strcpy(mdb->cached_path, mdb->path);
1031 sql_free_result(mdb);
1034 Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
1036 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1037 Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"),
1038 mdb->cmd, sql_strerror(mdb));
1039 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1043 ar->PathId = sql_insert_id(mdb, NT_("Path"));
1048 if (stat && ar->PathId != mdb->cached_path_id) {
1049 mdb->cached_path_id = ar->PathId;
1050 mdb->cached_path_len = mdb->pnl;
1051 pm_strcpy(mdb->cached_path, mdb->path);
1056 /* Create a Unique record for the filename -- no duplicates */
1057 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1061 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
1062 db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1064 Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
1066 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1067 mdb->num_rows = sql_num_rows(mdb);
1068 if (mdb->num_rows > 1) {
1070 Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
1071 edit_uint64(mdb->num_rows, ed1), mdb->fname);
1072 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1074 if (mdb->num_rows >= 1) {
1075 if ((row = sql_fetch_row(mdb)) == NULL) {
1076 Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
1077 mdb->fname, sql_strerror(mdb));
1078 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1081 ar->FilenameId = str_to_int64(row[0]);
1083 sql_free_result(mdb);
1084 return ar->FilenameId > 0;
1086 sql_free_result(mdb);
1089 Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
1091 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1092 Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
1093 mdb->cmd, sql_strerror(mdb));
1094 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1097 ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
1099 return ar->FilenameId > 0;
1102 bool db_write_batch_file_records(JCR *jcr)
1107 #endif /* ! HAVE_BATCH_FILE_INSERT */
1109 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */