/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2008 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.
This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation and included
in the file LICENSE.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
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.
*
* Kern Sibbald, March 2000
*
- * Version $Id$
+ * Version $Id: sql_create.c 8407 2009-01-28 10:47:21Z ricozz $
*/
/* The following is necessary so that we do not include
#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
/* -----------------------------------------------------------------------
*
#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 */
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];
*/
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)) {
return ok;
}
-
-
/* Create Unique Pool record
* Returns: false on failure
* true on success
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);
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,
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)) {
Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
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 */
"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),
edit_int64(mr->LocationId, ed10),
edit_int64(mr->ScratchPoolId, ed11),
edit_int64(mr->RecyclePoolId, ed12),
- mr->Enabled
+ mr->Enabled, mr->ActionOnPurge
);
"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 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);
+ 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 counter -- no duplicates
}
/* Must create it */
- Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue,"
+ Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,\"MinValue\",\"MaxValue\",CurrentValue,"
"WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
cr->WrapCounter);
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;
}
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);
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;
}
*/
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;
}
* 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);
}
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);
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);
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(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);
-
- 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 */
static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
{
#endif /* ! HAVE_BATCH_FILE_INSERT */
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL */
+
+/* List of SQL commands to create temp table and indicies */
+const char *create_temp_basefile[5] = {
+ /* MySQL */
+ "CREATE TEMPORARY TABLE basefile%lld ("
+// "CREATE TABLE basefile%lld ("
+ "Path BLOB NOT NULL,"
+ "Name BLOB NOT NULL)",
+
+ /* Postgresql */
+ "CREATE TEMPORARY TABLE basefile%lld ("
+// "CREATE TABLE basefile%lld ("
+ "Path TEXT,"
+ "Name TEXT)",
+
+ /* SQLite */
+ "CREATE TEMPORARY TABLE basefile%lld ("
+ "Path TEXT,"
+ "Name TEXT)",
+
+ /* SQLite3 */
+ "CREATE TEMPORARY TABLE basefile%lld ("
+ "Path TEXT,"
+ "Name TEXT)",
+
+ /* Ingres */
+ "DECLARE GLOBAL TEMPORARY TABLE basefile%lld ("
+ "Path TEXT NOT NULL,"
+ "Name TEXT NOT NULL)"
+ "ON COMMIT PRESERVE ROWS WITH NORECOVERY"
+};
+
+/*
+ * 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;
+ }
+ /* Quick and dirty fix for MySQL and Bacula 5.0.1 */
+#ifdef HAVE_MYSQL
+ Mmsg(mdb->cmd,
+ "CREATE INDEX basefile%lld_idx ON basefile%lld (Path(255), Name(255))",
+ (uint64_t) jcr->JobId, (uint64_t) jcr->JobId);
+ if (!db_sql_query(mdb, mdb->cmd, NULL, NULL)) {
+ goto bail_out;
+ }
+#endif
+ Mmsg(buf, select_recent_version[db_type], jobids, jobids);
+ Mmsg(mdb->cmd,
+"CREATE TEMPORARY TABLE new_basefile%lld AS "
+//"CREATE TABLE new_basefile%lld AS "
+ "SELECT Path.Path AS Path, Filename.Name AS Name, Temp.FileIndex AS FileIndex,"
+ "Temp.JobId AS JobId, Temp.LStat AS LStat, Temp.FileId AS FileId, "
+ "Temp.MD5 AS MD5 "
+ "FROM ( %s ) AS Temp "
+ "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
+ "JOIN Path ON (Path.PathId = Temp.PathId) "
+ "WHERE Temp.FileIndex > 0",
+ (uint64_t)jcr->JobId, buf.c_str());
+
+ ret = db_sql_query(mdb, mdb->cmd, NULL, NULL);
+bail_out:
+ db_unlock(mdb);
+ return ret;
+}
+
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */