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 #endif /* HAVE_BATCH_FILE_INSERT */
62 /* Create a new record for the Job
63 * Returns: false on failure
67 db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
69 char dt[MAX_TIME_LENGTH];
78 stime = jr->SchedTime;
81 (void)localtime_r(&stime, &tm);
82 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
83 JobTDate = (utime_t)stime;
87 "INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate,ClientId) "
88 "VALUES ('%s','%s','%c','%c','%c','%s',%s,%s)",
89 jr->Job, jr->Name, (char)(jr->JobType), (char)(jr->JobLevel),
90 (char)(jr->JobStatus), dt, edit_uint64(JobTDate, ed1),
91 edit_int64(jr->ClientId, ed2));
93 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
94 Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"),
95 mdb->cmd, sql_strerror(mdb));
99 jr->JobId = sql_insert_id(mdb, NT_("Job"));
107 /* Create a JobMedia record for medium used this job
108 * Returns: false on failure
112 db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
116 char ed1[50], ed2[50];
120 /* Now get count for VolIndex */
121 Mmsg(mdb->cmd, "SELECT count(*) from JobMedia WHERE JobId=%s",
122 edit_int64(jm->JobId, ed1));
123 count = get_sql_record_max(jcr, mdb);
129 /* Note, jm->Strip is not used and is not likely to be used
130 * in the near future, so I have removed it from the insert
131 * to save space in the DB. KES June 2006.
134 "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,"
135 "StartFile,EndFile,StartBlock,EndBlock,VolIndex,Copy) "
136 "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u,%u)",
137 edit_int64(jm->JobId, ed1),
138 edit_int64(jm->MediaId, ed2),
139 jm->FirstIndex, jm->LastIndex,
140 jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count,
143 Dmsg0(300, mdb->cmd);
144 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
145 Mmsg2(&mdb->errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), mdb->cmd,
149 /* Worked, now update the Media record with the EndFile and EndBlock */
151 "UPDATE Media SET EndFile=%u, EndBlock=%u WHERE MediaId=%u",
152 jm->EndFile, jm->EndBlock, jm->MediaId);
153 if (!UPDATE_DB(jcr, mdb, mdb->cmd)) {
154 Mmsg2(&mdb->errmsg, _("Update Media record %s failed: ERR=%s\n"), mdb->cmd,
160 Dmsg0(300, "Return from JobMedia\n");
164 /* Create Unique Pool record
165 * Returns: false on failure
169 db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
172 char ed1[30], ed2[30], ed3[50], ed4[50], ed5[50];
174 Dmsg0(200, "In create pool\n");
176 Mmsg(mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", pr->Name);
177 Dmsg1(200, "selectpool: %s\n", mdb->cmd);
179 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
180 mdb->num_rows = sql_num_rows(mdb);
181 if (mdb->num_rows > 0) {
182 Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pr->Name);
183 sql_free_result(mdb);
187 sql_free_result(mdb);
192 "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog,"
193 "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration,"
194 "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat,"
195 "RecyclePoolId,ScratchPoolId) "
196 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%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 edit_int64(pr->ScratchPoolId,ed5));
209 Dmsg1(200, "Create Pool: %s\n", mdb->cmd);
210 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
211 Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
212 mdb->cmd, sql_strerror(mdb));
216 pr->PoolId = sql_insert_id(mdb, NT_("Pool"));
224 * Create Unique Device record
225 * Returns: false on failure
229 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
232 char ed1[30], ed2[30];
234 Dmsg0(200, "In create Device\n");
236 Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
237 Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
239 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
240 mdb->num_rows = sql_num_rows(mdb);
241 if (mdb->num_rows > 0) {
242 Mmsg1(&mdb->errmsg, _("Device record %s already exists\n"), dr->Name);
243 sql_free_result(mdb);
247 sql_free_result(mdb);
252 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
254 edit_uint64(dr->MediaTypeId, ed1),
255 edit_int64(dr->StorageId, ed2));
256 Dmsg1(200, "Create Device: %s\n", mdb->cmd);
257 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
258 Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
259 mdb->cmd, sql_strerror(mdb));
263 dr->DeviceId = sql_insert_id(mdb, NT_("Device"));
273 * Create a Unique record for Storage -- no duplicates
274 * Returns: false on failure
275 * true on success with id in sr->StorageId
277 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
283 Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
287 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
288 mdb->num_rows = sql_num_rows(mdb);
289 /* If more than one, report error, but return first row */
290 if (mdb->num_rows > 1) {
291 Mmsg1(&mdb->errmsg, _("More than one Storage record!: %d\n"), (int)(mdb->num_rows));
292 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
294 if (mdb->num_rows >= 1) {
295 if ((row = sql_fetch_row(mdb)) == NULL) {
296 Mmsg1(&mdb->errmsg, _("error fetching Storage row: %s\n"), sql_strerror(mdb));
297 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
298 sql_free_result(mdb);
302 sr->StorageId = str_to_int64(row[0]);
303 sr->AutoChanger = atoi(row[1]); /* bool */
304 sql_free_result(mdb);
308 sql_free_result(mdb);
312 Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
313 " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
315 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
316 Mmsg2(&mdb->errmsg, _("Create DB Storage record %s failed. ERR=%s\n"),
317 mdb->cmd, sql_strerror(mdb));
318 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
321 sr->StorageId = sql_insert_id(mdb, NT_("Storage"));
331 * Create Unique MediaType record
332 * Returns: false on failure
336 db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr)
340 Dmsg0(200, "In create mediatype\n");
342 Mmsg(mdb->cmd, "SELECT MediaTypeId,MediaType FROM MediaType WHERE MediaType='%s'", mr->MediaType);
343 Dmsg1(200, "selectmediatype: %s\n", mdb->cmd);
345 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
346 mdb->num_rows = sql_num_rows(mdb);
347 if (mdb->num_rows > 0) {
348 Mmsg1(&mdb->errmsg, _("mediatype record %s already exists\n"), mr->MediaType);
349 sql_free_result(mdb);
353 sql_free_result(mdb);
358 "INSERT INTO MediaType (MediaType,ReadOnly) "
362 Dmsg1(200, "Create mediatype: %s\n", mdb->cmd);
363 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
364 Mmsg2(&mdb->errmsg, _("Create db mediatype record %s failed: ERR=%s\n"),
365 mdb->cmd, sql_strerror(mdb));
369 mr->MediaTypeId = sql_insert_id(mdb, NT_("MediaType"));
378 * Create Media record. VolumeName and non-zero Slot must be unique
380 * Returns: 0 on failure
384 db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
387 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
388 char ed9[50], ed10[50], ed11[50], ed12[50];
392 Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName='%s'",
394 Dmsg1(500, "selectpool: %s\n", mdb->cmd);
396 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
397 mdb->num_rows = sql_num_rows(mdb);
398 if (mdb->num_rows > 0) {
399 Mmsg1(&mdb->errmsg, _("Volume \"%s\" already exists.\n"), mr->VolumeName);
400 sql_free_result(mdb);
404 sql_free_result(mdb);
409 "INSERT INTO Media (VolumeName,MediaType,MediaTypeId,PoolId,MaxVolBytes,"
410 "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
411 "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts,"
412 "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId,"
413 "ScratchPoolId,RecyclePoolId,Enabled)"
414 "VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s,"
417 mr->MediaType, mr->PoolId,
418 edit_uint64(mr->MaxVolBytes,ed1),
419 edit_uint64(mr->VolCapacityBytes, ed2),
421 edit_uint64(mr->VolRetention, ed3),
422 edit_uint64(mr->VolUseDuration, ed4),
427 edit_uint64(mr->VolBytes, ed5),
429 edit_int64(mr->VolReadTime, ed6),
430 edit_int64(mr->VolWriteTime, ed7),
433 edit_int64(mr->StorageId, ed8),
434 edit_int64(mr->DeviceId, ed9),
435 edit_int64(mr->LocationId, ed10),
436 edit_int64(mr->ScratchPoolId, ed11),
437 edit_int64(mr->RecyclePoolId, ed12),
442 Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
443 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
444 Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
445 mdb->cmd, sql_strerror(mdb));
448 mr->MediaId = sql_insert_id(mdb, NT_("Media"));
450 if (mr->set_label_date) {
451 char dt[MAX_TIME_LENGTH];
452 if (mr->LabelDate == 0) {
453 mr->LabelDate = time(NULL);
455 (void)localtime_r(&mr->LabelDate, &tm);
456 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
457 Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
458 "WHERE MediaId=%d", dt, mr->MediaId);
459 stat = UPDATE_DB(jcr, mdb, mdb->cmd);
462 * Make sure that if InChanger is non-zero any other identical slot
463 * has InChanger zero.
465 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"));
537 /* Create a Unique record for the Path -- no duplicates */
538 int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
543 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
544 db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl);
546 if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
547 strcmp(mdb->cached_path, mdb->path) == 0) {
548 ar->PathId = mdb->cached_path_id;
552 Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
554 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
555 mdb->num_rows = sql_num_rows(mdb);
556 if (mdb->num_rows > 1) {
558 Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
559 edit_uint64(mdb->num_rows, ed1), mdb->path);
560 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
562 /* Even if there are multiple paths, take the first one */
563 if (mdb->num_rows >= 1) {
564 if ((row = sql_fetch_row(mdb)) == NULL) {
565 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
566 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
567 sql_free_result(mdb);
572 ar->PathId = str_to_int64(row[0]);
573 sql_free_result(mdb);
575 if (ar->PathId != mdb->cached_path_id) {
576 mdb->cached_path_id = ar->PathId;
577 mdb->cached_path_len = mdb->pnl;
578 pm_strcpy(mdb->cached_path, mdb->path);
583 sql_free_result(mdb);
586 Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
588 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
589 Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"),
590 mdb->cmd, sql_strerror(mdb));
591 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
595 ar->PathId = sql_insert_id(mdb, NT_("Path"));
600 if (stat && ar->PathId != mdb->cached_path_id) {
601 mdb->cached_path_id = ar->PathId;
602 mdb->cached_path_len = mdb->pnl;
603 pm_strcpy(mdb->cached_path, mdb->path);
609 * Create a Unique record for the counter -- no duplicates
610 * Returns: 0 on failure
611 * 1 on success with counter filled in
613 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
619 memset(&mcr, 0, sizeof(mcr));
620 bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
621 if (db_get_counter_record(jcr, mdb, &mcr)) {
622 memcpy(cr, &mcr, sizeof(COUNTER_DBR));
628 Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue,"
629 "WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
630 cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
633 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
634 Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
635 mdb->cmd, sql_strerror(mdb));
636 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
647 * Create a FileSet record. This record is unique in the
648 * name and the MD5 signature of the include/exclude sets.
649 * Returns: 0 on failure
650 * 1 on success with FileSetId in record
652 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
659 fsr->created = false;
660 Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
661 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
664 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
665 mdb->num_rows = sql_num_rows(mdb);
666 if (mdb->num_rows > 1) {
667 Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
668 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
670 if (mdb->num_rows >= 1) {
671 if ((row = sql_fetch_row(mdb)) == NULL) {
672 Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
673 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
674 sql_free_result(mdb);
678 fsr->FileSetId = str_to_int64(row[0]);
679 if (row[1] == NULL) {
680 fsr->cCreateTime[0] = 0;
682 bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
684 sql_free_result(mdb);
688 sql_free_result(mdb);
691 if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
692 fsr->CreateTime = time(NULL);
694 (void)localtime_r(&fsr->CreateTime, &tm);
695 strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
698 Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
699 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
701 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
702 Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
703 mdb->cmd, sql_strerror(mdb));
704 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
708 fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet"));
721 * dev_t st_dev; * device *
722 * ino_t st_ino; * inode *
723 * mode_t st_mode; * protection *
724 * nlink_t st_nlink; * number of hard links *
725 * uid_t st_uid; * user ID of owner *
726 * gid_t st_gid; * group ID of owner *
727 * dev_t st_rdev; * device type (if inode device) *
728 * off_t st_size; * total size, in bytes *
729 * unsigned long st_blksize; * blocksize for filesystem I/O *
730 * unsigned long st_blocks; * number of blocks allocated *
731 * time_t st_atime; * time of last access *
732 * time_t st_mtime; * time of last modification *
733 * time_t st_ctime; * time of last inode change *
737 #ifdef HAVE_BATCH_FILE_INSERT
739 /* All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path
740 * tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1"
744 * - bulk load a temp table
745 * - insert missing filenames into filename with a single query (lock filenames
746 * - table before that to avoid possible duplicate inserts with concurrent update)
747 * - insert missing paths into path with another single query
748 * - then insert the join between the temp, filename and path tables into file.
755 bool my_batch_start(JCR *jcr, B_DB *mdb)
760 ok = db_sql_query(mdb,
761 "CREATE TEMPORARY TABLE batch ("
767 "MD5 tinyblob)",NULL, NULL);
776 bool my_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
782 mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
783 db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
785 mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
786 db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl);
788 if (ar->Digest == NULL || ar->Digest[0] == 0) {
794 len = Mmsg(mdb->cmd, "INSERT INTO batch VALUES (%u,%s,'%s','%s','%s','%s')",
795 ar->FileIndex, edit_int64(ar->JobId,ed1), mdb->esc_path,
796 mdb->esc_name, ar->attr, digest);
798 return INSERT_DB(jcr, mdb, mdb->cmd);
801 /* set error to something to abort operation */
806 bool my_batch_end(JCR *jcr, B_DB *mdb, const char *error)
809 Dmsg0(50, "sql_batch_end started\n");
813 mdb->status = (dbi_error_flag)0;
825 bool db_write_batch_file_records(JCR *jcr)
827 int JobStatus = jcr->JobStatus;
829 if (!jcr->batch_started) { /* no files to backup ? */
830 Dmsg0(50,"db_create_file_record : no files\n");
833 if (job_canceled(jcr)) {
837 Dmsg1(50,"db_create_file_record changes=%u\n",jcr->db_batch->changes);
839 jcr->JobStatus = JS_AttrInserting;
840 if (!sql_batch_end(jcr, jcr->db_batch, NULL)) {
841 Jmsg1(jcr, M_FATAL, 0, "Batch end %s\n", jcr->db_batch->errmsg);
844 if (job_canceled(jcr)) {
849 /* we have to lock tables */
850 if (!db_sql_query(jcr->db_batch, sql_batch_lock_path_query, NULL, NULL)) {
851 Jmsg1(jcr, M_FATAL, 0, "Lock Path table %s\n", jcr->db_batch->errmsg);
855 if (!db_sql_query(jcr->db_batch, sql_batch_fill_path_query, NULL, NULL)) {
856 Jmsg1(jcr, M_FATAL, 0, "Fill Path table %s\n",jcr->db_batch->errmsg);
857 db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
861 if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
862 Jmsg1(jcr, M_FATAL, 0, "Unlock Path table %s\n", jcr->db_batch->errmsg);
866 /* we have to lock tables */
867 if (!db_sql_query(jcr->db_batch,sql_batch_lock_filename_query,NULL, NULL)) {
868 Jmsg1(jcr, M_FATAL, 0, "Lock Filename table %s\n", jcr->db_batch->errmsg);
872 if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) {
873 Jmsg1(jcr,M_FATAL,0,"Fill Filename table %s\n",jcr->db_batch->errmsg);
874 db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
878 if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) {
879 Jmsg1(jcr, M_FATAL, 0, "Unlock Filename table %s\n", jcr->db_batch->errmsg);
883 if (!db_sql_query(jcr->db_batch,
884 "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
885 "SELECT batch.FileIndex, batch.JobId, Path.PathId, "
886 "Filename.FilenameId,batch.LStat, batch.MD5 "
888 "JOIN Path ON (batch.Path = Path.Path) "
889 "JOIN Filename ON (batch.Name = Filename.Name)",
892 Jmsg1(jcr, M_FATAL, 0, "Fill File table %s\n", jcr->db_batch->errmsg);
896 db_sql_query(jcr->db_batch, "DROP TABLE batch", NULL,NULL);
898 jcr->JobStatus = JobStatus; /* reset entry status */
903 * Create File record in B_DB
905 * In order to reduce database size, we store the File attributes,
906 * the FileName, and the Path separately. In principle, there
907 * is a single FileName record and a single Path record, no matter
908 * how many times it occurs. This is this subroutine, we separate
909 * the file and the path and fill temporary tables with this three records.
911 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
913 Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
914 Dmsg0(dbglevel, "put_file_into_catalog\n");
916 /* Open the dedicated connexion */
917 if (!jcr->batch_started) {
919 if (!db_open_batch_connexion(jcr, mdb)) {
922 if (!sql_batch_start(jcr, jcr->db_batch)) {
924 "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
925 Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
928 jcr->batch_started = true;
930 B_DB *bdb = jcr->db_batch;
933 * Make sure we have an acceptable attributes record.
935 if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
936 ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
937 Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
939 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
943 split_path_and_file(jcr, bdb, ar->fname);
947 * if (bdb->changes > 100000) {
948 * db_write_batch_file_records(jcr);
950 * sql_batch_start(jcr, bdb);
954 return sql_batch_insert(jcr, bdb, ar);
957 #else /* ! HAVE_BATCH_FILE_INSERT */
960 * Create File record in B_DB
962 * In order to reduce database size, we store the File attributes,
963 * the FileName, and the Path separately. In principle, there
964 * is a single FileName record and a single Path record, no matter
965 * how many times it occurs. This is this subroutine, we separate
966 * the file and the path and create three database records.
968 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
971 Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
972 Dmsg0(dbglevel, "put_file_into_catalog\n");
974 * Make sure we have an acceptable attributes record.
976 if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
977 ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
978 Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
980 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
985 split_path_and_file(jcr, mdb, ar->fname);
987 if (!db_create_filename_record(jcr, mdb, ar)) {
990 Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
993 if (!db_create_path_record(jcr, mdb, ar)) {
996 Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
998 /* Now create master File record */
999 if (!db_create_file_record(jcr, mdb, ar)) {
1002 Dmsg0(dbglevel, "db_create_file_record OK\n");
1004 Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
1015 * This is the master File entry containing the attributes.
1016 * The filename and path records have already been created.
1018 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1021 static const char *no_digest = "0";
1026 ASSERT(ar->FilenameId);
1028 if (ar->Digest == NULL || ar->Digest[0] == 0) {
1031 digest = ar->Digest;
1034 /* Must create it */
1036 "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
1037 "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
1038 ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
1041 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1042 Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
1043 mdb->cmd, sql_strerror(mdb));
1044 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1048 ar->FileId = sql_insert_id(mdb, NT_("File"));
1054 /* Create a Unique record for the filename -- no duplicates */
1055 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
1059 mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
1060 db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl);
1062 Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
1064 if (QUERY_DB(jcr, mdb, mdb->cmd)) {
1065 mdb->num_rows = sql_num_rows(mdb);
1066 if (mdb->num_rows > 1) {
1068 Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
1069 edit_uint64(mdb->num_rows, ed1), mdb->fname);
1070 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
1072 if (mdb->num_rows >= 1) {
1073 if ((row = sql_fetch_row(mdb)) == NULL) {
1074 Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
1075 mdb->fname, sql_strerror(mdb));
1076 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
1079 ar->FilenameId = str_to_int64(row[0]);
1081 sql_free_result(mdb);
1082 return ar->FilenameId > 0;
1084 sql_free_result(mdb);
1087 Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
1089 if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
1090 Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
1091 mdb->cmd, sql_strerror(mdb));
1092 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
1095 ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
1097 return ar->FilenameId > 0;
1100 bool db_write_batch_file_records(JCR *jcr)
1105 #endif /* ! HAVE_BATCH_FILE_INSERT */
1107 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */