X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=bacula%2Fsrc%2Fcats%2Fsql_create.c;h=539c8db9d571255bfb408877d2a9e86ae3ffea9d;hb=3187e8fbe9f6821b7b6ae9f733c8daae3167735f;hp=95d4afdf8564a2de8b087db4e2cb37c393ff0a87;hpb=0e794438e5b1afd88ba96f584541e2731ab9cc23;p=bacula%2Fbacula diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 95d4afdf85..539c8db9d5 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + Copyright (C) 2000-2010 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. @@ -30,7 +30,6 @@ * * Kern Sibbald, March 2000 * - * Version $Id$ */ /* The following is necessary so that we do not include @@ -41,9 +40,9 @@ #include "bacula.h" #include "cats.h" -static const int dbglevel = 500; +static const int dbglevel = 100; -#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL +#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI /* ----------------------------------------------------------------------- * @@ -56,21 +55,22 @@ static const int dbglevel = 500; #ifndef HAVE_BATCH_FILE_INSERT static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar); static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar); -static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar); #endif /* HAVE_BATCH_FILE_INSERT */ -/* Create a new record for the Job - * Returns: false on failure +/** Create a new record for the Job + * Returns: false on failure * true on success */ bool db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { + POOL_MEM buf; char dt[MAX_TIME_LENGTH]; time_t stime; struct tm tm; bool ok; + int len; utime_t JobTDate; char ed1[30],ed2[30]; @@ -83,21 +83,25 @@ db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm); JobTDate = (utime_t)stime; + len = strlen(jcr->comment); + buf.check_size(len*2+1); + db_escape_string(jcr, mdb, buf.c_str(), jcr->comment, len); + /* Must create it */ Mmsg(mdb->cmd, -"INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate,ClientId) " -"VALUES ('%s','%s','%c','%c','%c','%s',%s,%s)", +"INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate," + "ClientId,Comment) " +"VALUES ('%s','%s','%c','%c','%c','%s',%s,%s,'%s')", jr->Job, jr->Name, (char)(jr->JobType), (char)(jr->JobLevel), (char)(jr->JobStatus), dt, edit_uint64(JobTDate, ed1), - edit_int64(jr->ClientId, ed2)); + edit_int64(jr->ClientId, ed2), buf.c_str()); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + jr->JobId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Job")); + if (jr->JobId == 0) { Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); - jr->JobId = 0; ok = false; } else { - jr->JobId = sql_insert_id(mdb, NT_("Job")); ok = true; } db_unlock(mdb); @@ -105,14 +109,14 @@ db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) } -/* Create a JobMedia record for medium used this job - * Returns: false on failure +/** Create a JobMedia record for medium used this job + * Returns: false on failure * true on success */ bool db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm) { - bool ok = true;; + bool ok = true; int count; char ed1[50], ed2[50]; @@ -127,19 +131,14 @@ db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm) } count++; - /* Note, jm->Strip is not used and is not likely to be used - * in the near future, so I have removed it from the insert - * to save space in the DB. KES June 2006. - */ Mmsg(mdb->cmd, "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex," - "StartFile,EndFile,StartBlock,EndBlock,VolIndex,Copy) " - "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u,%u)", + "StartFile,EndFile,StartBlock,EndBlock,VolIndex) " + "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u)", edit_int64(jm->JobId, ed1), edit_int64(jm->MediaId, ed2), jm->FirstIndex, jm->LastIndex, - jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count, - jm->Copy); + jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count); Dmsg0(300, mdb->cmd); if (!INSERT_DB(jcr, mdb, mdb->cmd)) { @@ -162,17 +161,15 @@ db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm) return ok; } - - -/* Create Unique Pool record - * Returns: false on failure +/** Create Unique Pool record + * Returns: false on failure * true on success */ bool db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) { bool stat; - char ed1[30], ed2[30], ed3[50], ed4[50]; + char ed1[30], ed2[30], ed3[50], ed4[50], ed5[50]; Dmsg0(200, "In create pool\n"); db_lock(mdb); @@ -194,8 +191,9 @@ db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) Mmsg(mdb->cmd, "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog," "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration," -"MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId) " -"VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s)", +"MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat," +"RecyclePoolId,ScratchPoolId,ActionOnPurge) " +"VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s,%s,%d)", pr->Name, pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog, @@ -206,22 +204,25 @@ db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) pr->MaxVolJobs, pr->MaxVolFiles, edit_uint64(pr->MaxVolBytes, ed3), pr->PoolType, pr->LabelType, pr->LabelFormat, - edit_int64(pr->RecyclePoolId,ed4)); + edit_int64(pr->RecyclePoolId,ed4), + edit_int64(pr->ScratchPoolId,ed5), + pr->ActionOnPurge + ); Dmsg1(200, "Create Pool: %s\n", mdb->cmd); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + pr->PoolId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Pool")); + if (pr->PoolId == 0) { Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); - pr->PoolId = 0; stat = false; } else { - pr->PoolId = sql_insert_id(mdb, NT_("Pool")); stat = true; } db_unlock(mdb); + Dmsg0(500, "Create Pool: done\n"); return stat; } -/* +/** * Create Unique Device record * Returns: false on failure * true on success @@ -255,13 +256,12 @@ db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr) edit_uint64(dr->MediaTypeId, ed1), edit_int64(dr->StorageId, ed2)); Dmsg1(200, "Create Device: %s\n", mdb->cmd); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + dr->DeviceId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Device")); + if (dr->DeviceId == 0) { Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); - dr->DeviceId = 0; ok = false; } else { - dr->DeviceId = sql_insert_id(mdb, NT_("Device")); ok = true; } db_unlock(mdb); @@ -270,7 +270,7 @@ db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr) -/* +/** * Create a Unique record for Storage -- no duplicates * Returns: false on failure * true on success with id in sr->StorageId @@ -285,6 +285,7 @@ bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr) sr->StorageId = 0; sr->created = false; + /* Check if it already exists */ if (QUERY_DB(jcr, mdb, mdb->cmd)) { mdb->num_rows = sql_num_rows(mdb); /* If more than one, report error, but return first row */ @@ -313,13 +314,13 @@ bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr) Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)" " VALUES ('%s',%d)", sr->Name, sr->AutoChanger); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + sr->StorageId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Storage")); + if (sr->StorageId == 0) { Mmsg2(&mdb->errmsg, _("Create DB Storage record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); ok = false; } else { - sr->StorageId = sql_insert_id(mdb, NT_("Storage")); sr->created = true; ok = true; } @@ -328,7 +329,7 @@ bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr) } -/* +/** * Create Unique MediaType record * Returns: false on failure * true on success @@ -361,13 +362,12 @@ db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr) mr->MediaType, mr->ReadOnly); Dmsg1(200, "Create mediatype: %s\n", mdb->cmd); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + mr->MediaTypeId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("MediaType")); + if (mr->MediaTypeId == 0) { Mmsg2(&mdb->errmsg, _("Create db mediatype record %s failed: ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); - mr->MediaTypeId = 0; stat = false; } else { - mr->MediaTypeId = sql_insert_id(mdb, NT_("MediaType")); stat = true; } db_unlock(mdb); @@ -375,7 +375,7 @@ db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr) } -/* +/** * Create Media record. VolumeName and non-zero Slot must be unique * * Returns: 0 on failure @@ -411,9 +411,9 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts," "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId," -"ScratchPoolId,RecyclePoolId,Enabled)" +"ScratchPoolId,RecyclePoolId,Enabled,ActionOnPurge)" "VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s," -"%s,%s,%s,%s,%d)", +"%s,%s,%s,%s,%d,%d)", mr->VolumeName, mr->MediaType, mr->PoolId, edit_uint64(mr->MaxVolBytes,ed1), @@ -436,17 +436,17 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) edit_int64(mr->LocationId, ed10), edit_int64(mr->ScratchPoolId, ed11), edit_int64(mr->RecyclePoolId, ed12), - mr->Enabled + mr->Enabled, mr->ActionOnPurge ); Dmsg1(500, "Create Volume: %s\n", mdb->cmd); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + mr->MediaId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Media")); + if (mr->MediaId == 0) { Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); stat = 0; } else { - mr->MediaId = sql_insert_id(mdb, NT_("Media")); stat = 1; if (mr->set_label_date) { char dt[MAX_TIME_LENGTH]; @@ -459,19 +459,18 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) "WHERE MediaId=%d", dt, mr->MediaId); stat = UPDATE_DB(jcr, mdb, mdb->cmd); } + /* + * Make sure that if InChanger is non-zero any other identical slot + * has InChanger zero. + */ + db_make_inchanger_unique(jcr, mdb, mr); } - /* - * Make sure that if InChanger is non-zero any other identical slot - * has InChanger zero. - */ - db_make_inchanger_unique(jcr, mdb, mr); - db_unlock(mdb); return stat; } -/* +/** * Create a Unique record for the client -- no duplicates * Returns: 0 on failure * 1 on success with id in cr->ClientId @@ -521,14 +520,13 @@ int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr) edit_uint64(cr->FileRetention, ed1), edit_uint64(cr->JobRetention, ed2)); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + cr->ClientId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Client")); + if (cr->ClientId == 0) { Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - cr->ClientId = 0; stat = 0; } else { - cr->ClientId = sql_insert_id(mdb, NT_("Client")); stat = 1; } db_unlock(mdb); @@ -536,10 +534,78 @@ int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr) } +/** Create a Unique record for the Path -- no duplicates */ +int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) +{ + SQL_ROW row; + int stat; + + mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2); + db_escape_string(jcr, mdb, mdb->esc_name, mdb->path, mdb->pnl); + if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl && + strcmp(mdb->cached_path, mdb->path) == 0) { + ar->PathId = mdb->cached_path_id; + return 1; + } + Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name); -/* + if (QUERY_DB(jcr, mdb, mdb->cmd)) { + mdb->num_rows = sql_num_rows(mdb); + if (mdb->num_rows > 1) { + char ed1[30]; + Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"), + edit_uint64(mdb->num_rows, ed1), mdb->path); + Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg); + } + /* Even if there are multiple paths, take the first one */ + if (mdb->num_rows >= 1) { + if ((row = sql_fetch_row(mdb)) == NULL) { + Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); + Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); + sql_free_result(mdb); + ar->PathId = 0; + ASSERT(ar->PathId); + return 0; + } + ar->PathId = str_to_int64(row[0]); + sql_free_result(mdb); + /* Cache path */ + if (ar->PathId != mdb->cached_path_id) { + mdb->cached_path_id = ar->PathId; + mdb->cached_path_len = mdb->pnl; + pm_strcpy(mdb->cached_path, mdb->path); + } + ASSERT(ar->PathId); + return 1; + } + sql_free_result(mdb); + } + + Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name); + + ar->PathId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Path")); + if (ar->PathId == 0) { + Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"), + mdb->cmd, sql_strerror(mdb)); + Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); + ar->PathId = 0; + stat = 0; + } else { + stat = 1; + } + + /* Cache path */ + if (stat && ar->PathId != mdb->cached_path_id) { + mdb->cached_path_id = ar->PathId; + mdb->cached_path_len = mdb->pnl; + pm_strcpy(mdb->cached_path, mdb->path); + } + return stat; +} + +/** * Create a Unique record for the counter -- no duplicates * Returns: 0 on failure * 1 on success with counter filled in @@ -577,7 +643,7 @@ int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) } -/* +/** * Create a FileSet record. This record is unique in the * name and the MD5 signature of the include/exclude sets. * Returns: 0 on failure @@ -632,14 +698,13 @@ bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) " "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + fsr->FileSetId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("FileSet")); + if (fsr->FileSetId == 0) { Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - fsr->FileSetId = 0; stat = false; } else { - fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet")); fsr->created = true; stat = true; } @@ -649,7 +714,7 @@ bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) } -/* +/** * struct stat * { * dev_t st_dev; * device * @@ -668,7 +733,9 @@ bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) * }; */ -/* All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path +#ifdef HAVE_BATCH_FILE_INSERT + +/** All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path * tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1" * in baconfig.h * @@ -690,13 +757,13 @@ bool my_batch_start(JCR *jcr, B_DB *mdb) db_lock(mdb); ok = db_sql_query(mdb, - " CREATE TEMPORARY TABLE batch " - " (fileindex integer, " - " jobid integer, " - " path blob, " - " name blob, " - " lstat tinyblob, " - " md5 tinyblob) ",NULL, NULL); + "CREATE TEMPORARY TABLE batch (" + "FileIndex integer," + "JobId integer," + "Path blob," + "Name blob," + "LStat tinyblob," + "MD5 tinyblob)",NULL, NULL); db_unlock(mdb); return ok; } @@ -708,14 +775,14 @@ bool my_batch_start(JCR *jcr, B_DB *mdb) bool my_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) { size_t len; - char *digest; + const char *digest; char ed1[50]; mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1); - db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl); + db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl); mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1); - db_escape_string(mdb->esc_path, mdb->path, mdb->pnl); + db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl); if (ar->Digest == NULL || ar->Digest[0] == 0) { digest = "0"; @@ -741,87 +808,97 @@ bool my_batch_end(JCR *jcr, B_DB *mdb, const char *error) Dmsg0(50, "sql_batch_end started\n"); if (mdb) { +#ifdef HAVE_DBI + mdb->status = (dbi_error_flag)0; +#else mdb->status = 0; +#endif } return true; } -#ifdef HAVE_BATCH_FILE_INSERT /* * Returns 1 if OK * 0 if failed */ bool db_write_batch_file_records(JCR *jcr) { - if (!jcr->db_batch) { /* no files to backup ? */ + int JobStatus = jcr->JobStatus; + + if (!jcr->batch_started) { /* no files to backup ? */ Dmsg0(50,"db_create_file_record : no files\n"); return true; } + if (job_canceled(jcr)) { + return false; + } Dmsg1(50,"db_create_file_record changes=%u\n",jcr->db_batch->changes); + jcr->JobStatus = JS_AttrInserting; if (!sql_batch_end(jcr, jcr->db_batch, NULL)) { - Jmsg(jcr, M_FATAL, 0, "Bad batch end %s\n", jcr->db_batch->errmsg); + Jmsg1(jcr, M_FATAL, 0, "Batch end %s\n", jcr->db_batch->errmsg); return false; } - if (job_canceled(jcr)) { return false; } + /* we have to lock tables */ if (!db_sql_query(jcr->db_batch, sql_batch_lock_path_query, NULL, NULL)) { - Jmsg(jcr, M_FATAL, 0, "Can't lock Path table %s\n", jcr->db_batch->errmsg); + Jmsg1(jcr, M_FATAL, 0, "Lock Path table %s\n", jcr->db_batch->errmsg); return false; } if (!db_sql_query(jcr->db_batch, sql_batch_fill_path_query, NULL, NULL)) { - Jmsg(jcr, M_FATAL, 0, "Can't fill Path table %s\n",jcr->db_batch->errmsg); + Jmsg1(jcr, M_FATAL, 0, "Fill Path table %s\n",jcr->db_batch->errmsg); db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL); return false; } if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) { - Jmsg(jcr, M_FATAL, 0, "Can't unlock Path table %s\n", jcr->db_batch->errmsg); + Jmsg1(jcr, M_FATAL, 0, "Unlock Path table %s\n", jcr->db_batch->errmsg); return false; } /* we have to lock tables */ if (!db_sql_query(jcr->db_batch,sql_batch_lock_filename_query,NULL, NULL)) { - Jmsg(jcr, M_FATAL, 0, "Can't lock Filename table %s\n", jcr->db_batch->errmsg); + Jmsg1(jcr, M_FATAL, 0, "Lock Filename table %s\n", jcr->db_batch->errmsg); return false; } if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) { - Jmsg(jcr,M_FATAL,0,"Can't fill Filename table %s\n",jcr->db_batch->errmsg); - QUERY_DB(jcr, jcr->db_batch, sql_batch_unlock_tables_query); + Jmsg1(jcr,M_FATAL,0,"Fill Filename table %s\n",jcr->db_batch->errmsg); + db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL); return false; } if (!db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query,NULL,NULL)) { - Jmsg(jcr, M_FATAL, 0, "Can't unlock Filename table %s\n", jcr->db_batch->errmsg); + Jmsg1(jcr, M_FATAL, 0, "Unlock Filename table %s\n", jcr->db_batch->errmsg); return false; } if (!db_sql_query(jcr->db_batch, - " INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)" - " SELECT batch.FileIndex, batch.JobId, Path.PathId, " - " Filename.FilenameId,batch.LStat, batch.MD5 " - " FROM batch " - " JOIN Path ON (batch.Path = Path.Path) " - " JOIN Filename ON (batch.Name = Filename.Name) ", + "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)" + "SELECT batch.FileIndex, batch.JobId, Path.PathId, " + "Filename.FilenameId,batch.LStat, batch.MD5 " + "FROM batch " + "JOIN Path ON (batch.Path = Path.Path) " + "JOIN Filename ON (batch.Name = Filename.Name)", NULL,NULL)) { - Jmsg(jcr, M_FATAL, 0, "Can't fill File table %s\n", jcr->db_batch->errmsg); + Jmsg1(jcr, M_FATAL, 0, "Fill File table %s\n", jcr->db_batch->errmsg); return false; } db_sql_query(jcr->db_batch, "DROP TABLE batch", NULL,NULL); + jcr->JobStatus = JobStatus; /* reset entry status */ return true; } -/* +/** * Create File record in B_DB * * In order to reduce database size, we store the File attributes, @@ -829,70 +906,50 @@ bool db_write_batch_file_records(JCR *jcr) * is a single FileName record and a single Path record, no matter * how many times it occurs. This is this subroutine, we separate * the file and the path and fill temporary tables with this three records. + * + * Note: all routines that call this expect to be able to call + * db_strerror(mdb) to get the error message, so the error message + * MUST be edited into mdb->errmsg before returning an error status. */ bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) { + ASSERT(ar->FileType != FT_BASE); + Dmsg1(dbglevel, "Fname=%s\n", ar->fname); Dmsg0(dbglevel, "put_file_into_catalog\n"); - if (!jcr->db_batch) { - Dmsg2(100, "Opendb attr. Stream=%d fname=%s\n", ar->Stream, ar->fname); - jcr->db_batch = db_init_database(jcr, - mdb->db_name, - mdb->db_user, - mdb->db_password, - mdb->db_address, - mdb->db_port, - mdb->db_socket, - 1 /* multi_db = true */); - - if (!jcr->db_batch || !db_open_database(jcr, jcr->db_batch)) { - Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"), - jcr->db->db_name); - if (jcr->db_batch) { - Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db_batch)); - } - return false; - } - + /* Open the dedicated connexion */ + if (!jcr->batch_started) { + if (!db_open_batch_connexion(jcr, mdb)) { + return false; /* error already printed */ + } if (!sql_batch_start(jcr, jcr->db_batch)) { - Jmsg(jcr, M_FATAL, 0, - "Can't start batch mode %s", db_strerror(jcr->db_batch)); + Mmsg1(&mdb->errmsg, + "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch)); + Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); return false; } - Dmsg3(100, "initdb ref=%d connected=%d db=%p\n", jcr->db_batch->ref_count, - jcr->db_batch->connected, jcr->db_batch->db); + jcr->batch_started = true; } B_DB *bdb = jcr->db_batch; - /* - * Make sure we have an acceptable attributes record. - */ - if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES || - ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) { - Mmsg1(&bdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"), - ar->Stream); - Jmsg(jcr, M_ERROR, 0, "%s", bdb->errmsg); - return 0; - } - split_path_and_file(jcr, bdb, ar->fname); /* - if (bdb->changes > 100000) { - db_write_batch_file_records(jcr); - bdb->changes = 0; - sql_batch_start(jcr, bdb); - } -*/ + * if (bdb->changes > 100000) { + * db_write_batch_file_records(jcr); + * bdb->changes = 0; + * sql_batch_start(jcr, bdb); + * } + */ return sql_batch_insert(jcr, bdb, ar); } #else /* ! HAVE_BATCH_FILE_INSERT */ -/* +/** * Create File record in B_DB * * In order to reduce database size, we store the File attributes, @@ -906,17 +963,6 @@ bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) db_lock(mdb); Dmsg1(dbglevel, "Fname=%s\n", ar->fname); Dmsg0(dbglevel, "put_file_into_catalog\n"); - /* - * Make sure we have an acceptable attributes record. - */ - if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES || - ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) { - Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"), - ar->Stream); - Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - goto bail_out; - } - split_path_and_file(jcr, mdb, ar->fname); @@ -947,15 +993,15 @@ bail_out: } -/* +/** * This is the master File entry containing the attributes. * The filename and path records have already been created. */ static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) { int stat; - static char *no_digest = "0"; - char *digest; + static const char *no_digest = "0"; + const char *digest; ASSERT(ar->JobId); ASSERT(ar->PathId); @@ -974,98 +1020,26 @@ static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId, ar->attr, digest); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + ar->FileId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("File")); + if (ar->FileId == 0) { Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"), mdb->cmd, sql_strerror(mdb)); Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); - ar->FileId = 0; stat = 0; } else { - ar->FileId = sql_insert_id(mdb, NT_("File")); stat = 1; } return stat; } -/* Create a Unique record for the Path -- no duplicates */ -static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) -{ - SQL_ROW row; - int stat; - - mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2); - db_escape_string(mdb->esc_name, mdb->path, mdb->pnl); - - if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl && - strcmp(mdb->cached_path, mdb->path) == 0) { - ar->PathId = mdb->cached_path_id; - return 1; - } - - Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name); - - if (QUERY_DB(jcr, mdb, mdb->cmd)) { - mdb->num_rows = sql_num_rows(mdb); - if (mdb->num_rows > 1) { - char ed1[30]; - Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"), - edit_uint64(mdb->num_rows, ed1), mdb->path); - Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg); - } - /* Even if there are multiple paths, take the first one */ - if (mdb->num_rows >= 1) { - if ((row = sql_fetch_row(mdb)) == NULL) { - Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); - Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - sql_free_result(mdb); - ar->PathId = 0; - ASSERT(ar->PathId); - return 0; - } - ar->PathId = str_to_int64(row[0]); - sql_free_result(mdb); - /* Cache path */ - if (ar->PathId != mdb->cached_path_id) { - mdb->cached_path_id = ar->PathId; - mdb->cached_path_len = mdb->pnl; - pm_strcpy(mdb->cached_path, mdb->path); - } - ASSERT(ar->PathId); - return 1; - } - sql_free_result(mdb); - } - - Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name); - - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { - Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"), - mdb->cmd, sql_strerror(mdb)); - Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); - ar->PathId = 0; - stat = 0; - } else { - ar->PathId = sql_insert_id(mdb, NT_("Path")); - stat = 1; - } - - /* Cache path */ - if (stat && ar->PathId != mdb->cached_path_id) { - mdb->cached_path_id = ar->PathId; - mdb->cached_path_len = mdb->pnl; - pm_strcpy(mdb->cached_path, mdb->path); - } - return stat; -} - -/* Create a Unique record for the filename -- no duplicates */ +/** Create a Unique record for the filename -- no duplicates */ static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) { SQL_ROW row; mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2); - db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl); - + db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl); + Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name); if (QUERY_DB(jcr, mdb, mdb->cmd)) { @@ -1093,13 +1067,11 @@ static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name); - if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + ar->FilenameId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Filename")); + if (ar->FilenameId == 0) { Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); - ar->FilenameId = 0; - } else { - ar->FilenameId = sql_insert_id(mdb, NT_("Filename")); } return ar->FilenameId > 0; } @@ -1111,4 +1083,177 @@ bool db_write_batch_file_records(JCR *jcr) #endif /* ! HAVE_BATCH_FILE_INSERT */ -#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL */ +/** + * Create file attributes record, or base file attributes record + */ +bool db_create_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) +{ + bool ret; + + /* + * Make sure we have an acceptable attributes record. + */ + if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES || + ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) { + Jmsg(jcr, M_FATAL, 0, _("Attempt to put non-attributes into catalog. Stream=%d\n")); + return false; + } + + if (ar->FileType != FT_BASE) { + ret = db_create_file_attributes_record(jcr, mdb, ar); + + } else if (jcr->HasBase) { + ret = db_create_base_file_attributes_record(jcr, mdb, ar); + + } else { + Jmsg0(jcr, M_FATAL, 0, _("Can't Copy/Migrate job using BaseJob")); + ret = true; /* in copy/migration what do we do ? */ + } + + return ret; +} + +/** + * Create Base File record in B_DB + * + */ +bool db_create_base_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) +{ + bool ret; + Dmsg1(dbglevel, "create_base_file Fname=%s\n", ar->fname); + Dmsg0(dbglevel, "put_base_file_into_catalog\n"); + + db_lock(mdb); + split_path_and_file(jcr, mdb, ar->fname); + + mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1); + db_escape_string(jcr, mdb, mdb->esc_name, mdb->fname, mdb->fnl); + + mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1); + db_escape_string(jcr, mdb, mdb->esc_path, mdb->path, mdb->pnl); + + Mmsg(mdb->cmd, "INSERT INTO basefile%lld (Path, Name) VALUES ('%s','%s')", + (uint64_t)jcr->JobId, mdb->esc_path, mdb->esc_name); + + ret = INSERT_DB(jcr, mdb, mdb->cmd); + db_unlock(mdb); + + return ret; +} + +/** + * Cleanup the base file temporary tables + */ +static void db_cleanup_base_file(JCR *jcr, B_DB *mdb) +{ + POOL_MEM buf(PM_MESSAGE); + Mmsg(buf, "DROP TABLE new_basefile%lld", (uint64_t) jcr->JobId); + db_sql_query(mdb, buf.c_str(), NULL, NULL); + + Mmsg(buf, "DROP TABLE basefile%lld", (uint64_t) jcr->JobId); + db_sql_query(mdb, buf.c_str(), NULL, NULL); +} + +/** + * Put all base file seen in the backup to the BaseFile table + * and cleanup temporary tables + */ +bool db_commit_base_file_attributes_record(JCR *jcr, B_DB *mdb) +{ + bool ret; + char ed1[50]; + + db_lock(mdb); + + Mmsg(mdb->cmd, + "INSERT INTO BaseFiles (BaseJobId, JobId, FileId, FileIndex) " + "SELECT B.JobId AS BaseJobId, %s AS JobId, " + "B.FileId, B.FileIndex " + "FROM basefile%s AS A, new_basefile%s AS B " + "WHERE A.Path = B.Path " + "AND A.Name = B.Name " + "ORDER BY B.FileId", + edit_uint64(jcr->JobId, ed1), ed1, ed1); + ret = db_sql_query(mdb, mdb->cmd, NULL, NULL); + jcr->nb_base_files_used = sql_affected_rows(mdb); + db_cleanup_base_file(jcr, mdb); + + db_unlock(mdb); + return ret; +} + +/** + * Find the last "accurate" backup state with Base jobs + * 1) Get all files with jobid in list (F subquery) + * 2) Take only the last version of each file (Temp subquery) => accurate list is ok + * 3) Put the result in a temporary table for the end of job + * + */ +bool db_create_base_file_list(JCR *jcr, B_DB *mdb, char *jobids) +{ + POOL_MEM buf; + bool ret=false; + + db_lock(mdb); + + if (!*jobids) { + Mmsg(mdb->errmsg, _("ERR=JobIds are empty\n")); + goto bail_out; + } + + Mmsg(mdb->cmd, create_temp_basefile[db_type], (uint64_t) jcr->JobId); + if (!db_sql_query(mdb, mdb->cmd, NULL, NULL)) { + goto bail_out; + } + Mmsg(buf, select_recent_version[db_type], jobids, jobids); + Mmsg(mdb->cmd, create_temp_new_basefile[db_type], (uint64_t)jcr->JobId, buf.c_str()); + + ret = db_sql_query(mdb, mdb->cmd, NULL, NULL); +bail_out: + db_unlock(mdb); + return ret; +} + +/** + * Create Restore Object record in B_DB + * + */ +bool db_create_restore_object_record(JCR *jcr, B_DB *mdb, ROBJECT_DBR *ro) +{ + bool stat; + POOLMEM *esc_obj = get_pool_memory(PM_MESSAGE); + db_lock(mdb); + + Dmsg1(dbglevel, "Oname=%s\n", ro->object_name); + Dmsg0(dbglevel, "put_object_into_catalog\n"); + + mdb->fnl = strlen(ro->object_name); + mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1); + db_escape_string(jcr, mdb, mdb->esc_name, ro->object_name, mdb->fnl); + + esc_obj = check_pool_memory_size(esc_obj, ro->object_len*2+1); + db_escape_string(jcr, mdb, esc_obj, ro->object, ro->object_len); + + Mmsg(mdb->cmd, + "INSERT INTO RestoreObject (ObjectName,RestoreObject," + "ObjectLength,ObjectIndex,ObjectType,ObjectCompression,FileIndex,JobId) " + "VALUES ('%s','%s',%d,%d,%d,%d,%d,%u)", + mdb->esc_name, esc_obj, ro->object_len, ro->object_index, + FT_RESTORE_FIRST, ro->object_compression, ro->FileIndex, ro->JobId); + + ro->RestoreObjectId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("RestoreObject")); + if (ro->RestoreObjectId == 0) { + Mmsg2(&mdb->errmsg, _("Create db Object record %s failed. ERR=%s"), + mdb->cmd, sql_strerror(mdb)); + Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg); + stat = false; + } else { + stat = true; + } + db_unlock(mdb); + free_pool_memory(esc_obj); + return stat; +} + + +#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */