/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2009 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.
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.
(FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
Switzerland, email:ftf@fsfeurope.org.
*/
-/*
+/**
* Bacula Catalog Database Get record interface routines
* Note, these routines generally get a record by id or
* by name. If more logic is involved, the routine
*
* Kern Sibbald, March 2000
*
- * Version $Id: sql_get.c 8918 2009-06-23 11:56:35Z ricozz $
*/
-/* The following is necessary so that we do not include
+/**
+ * The following is necessary so that we do not include
* the dummy external definition of DB.
*/
#define __SQL_C /* indicate that this is sql.c */
#include "bacula.h"
#include "cats.h"
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
/* -----------------------------------------------------------------------
*
static int db_get_filename_record(JCR *jcr, B_DB *mdb);
-/*
+/**
* Given a full filename (with path), look up the File record
* (with attributes) in the database.
*
}
-/*
+/**
* Get a File record
* Returns: 0 on failure
* 1 on success
int stat = 0;
char ed1[50], ed2[50], ed3[50];
- if (jcr->get_JobLevel() == L_VERIFY_DISK_TO_CATALOG) {
+ if (jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG) {
Mmsg(mdb->cmd,
"SELECT FileId, LStat, MD5 FROM File,Job WHERE "
"File.JobId=Job.JobId AND File.PathId=%s AND "
edit_int64(fdbr->PathId, ed1),
edit_int64(fdbr->FilenameId, ed2),
edit_int64(jr->ClientId,ed3));
-
- } else if (jr != NULL) {
- /* Called from Verify so jr->FileIndex is valid */
- Mmsg(mdb->cmd,
-"SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
-"File.FilenameId=%s AND FileIndex=%u",
- edit_int64(fdbr->JobId, ed1),
- edit_int64(fdbr->PathId, ed2),
- edit_int64(fdbr->FilenameId,ed3),
- jr->FileIndex);
} else {
Mmsg(mdb->cmd,
"SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
mdb->num_rows = sql_num_rows(mdb);
Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows);
- if (mdb->num_rows > 1) {
- Mmsg1(mdb->errmsg, _("get_file_record want 1 got rows=%d\n"),
- mdb->num_rows);
- Dmsg1(000, "=== Problem! %s", mdb->errmsg);
- }
if (mdb->num_rows >= 1) {
if ((row = sql_fetch_row(mdb)) == NULL) {
Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
stat = 1;
+ if (mdb->num_rows > 1) {
+ Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
+ mdb->num_rows,
+ edit_int64(fdbr->PathId, ed1),
+ edit_int64(fdbr->FilenameId, ed2));
+ Dmsg1(000, "=== Problem! %s", mdb->errmsg);
+ }
}
} else {
Mmsg2(mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"),
}
-/* Get Filename record
+/**
+ * Get Filename record
* Returns: 0 on failure
* FilenameId on success
*
return FilenameId;
}
-/* Get path record
+/**
+ * Get path record
* Returns: 0 on failure
* PathId on success
*
}
-/*
+/**
* Get Job record for given JobId or Job name
* Returns: false on failure
* true on success
Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
"PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
"Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
-"SchedTime,RealEndTime,ReadBytes,HasBase "
+"SchedTime,RealEndTime,ReadBytes,HasBase,PurgedFiles "
"FROM Job WHERE Job='%s'", jr->Job);
} else {
Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
"PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
"Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
-"SchedTime,RealEndTime,ReadBytes,HasBase "
+"SchedTime,RealEndTime,ReadBytes,HasBase,PurgedFiles "
"FROM Job WHERE JobId=%s",
edit_int64(jr->JobId, ed1));
}
jr->EndTime = str_to_utime(jr->cEndTime);
jr->RealEndTime = str_to_utime(jr->cRealEndTime);
jr->HasBase = str_to_int64(row[21]);
+ jr->PurgedFiles = str_to_int64(row[22]);
sql_free_result(mdb);
db_unlock(mdb);
return true;
}
-/*
+/**
* Find VolumeNames for a given JobId
* Returns: 0 on error or no Volumes found
* number of volumes on success
return stat;
}
-/*
+/**
* Find Volume parameters for a give JobId
* Returns: 0 on error or no Volumes found
* number of volumes on success
db_lock(mdb);
Mmsg(mdb->cmd,
"SELECT VolumeName,MediaType,FirstIndex,LastIndex,StartFile,"
-"JobMedia.EndFile,StartBlock,JobMedia.EndBlock,Copy,"
+"JobMedia.EndFile,StartBlock,JobMedia.EndBlock,"
"Slot,StorageId,InChanger"
" FROM JobMedia,Media WHERE JobMedia.JobId=%s"
" AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId",
EndBlock = str_to_uint64(row[7]);
Vols[i].StartAddr = (((uint64_t)StartFile)<<32) | StartBlock;
Vols[i].EndAddr = (((uint64_t)EndFile)<<32) | EndBlock;
-// Vols[i].Copy = str_to_uint64(row[8]);
- Vols[i].Slot = str_to_uint64(row[9]);
- StorageId = str_to_uint64(row[10]);
- Vols[i].InChanger = str_to_uint64(row[11]);
+ Vols[i].Slot = str_to_uint64(row[8]);
+ StorageId = str_to_uint64(row[9]);
+ Vols[i].InChanger = str_to_uint64(row[10]);
Vols[i].Storage[0] = 0;
SId[i] = StorageId;
}
-/*
+/**
* Get the number of pool records
*
* Returns: -1 on failure
return stat;
}
-/*
+/**
* This function returns a list of all the Pool record ids.
* The caller must free ids if non-NULL.
*
return stat;
}
-/*
+/**
* This function returns a list of all the Client record ids.
* The caller must free ids if non-NULL.
*
db_lock(mdb);
*ids = NULL;
- Mmsg(mdb->cmd, "SELECT ClientId FROM Client");
+ Mmsg(mdb->cmd, "SELECT ClientId FROM Client ORDER BY Name");
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
*num_ids = sql_num_rows(mdb);
if (*num_ids > 0) {
-/* Get Pool Record
+/**
+ * Get Pool Record
* If the PoolId is non-zero, we get its record,
* otherwise, we search on the PoolName
*
Mmsg(mdb->cmd,
"SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
"AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
-"MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId FROM Pool WHERE Pool.PoolId=%s",
+"MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
+"ActionOnPurge FROM Pool WHERE Pool.PoolId=%s",
edit_int64(pdbr->PoolId, ed1));
} else { /* find by name */
Mmsg(mdb->cmd,
"SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume,"
"AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
-"MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId FROM Pool WHERE Pool.Name='%s'",
+"MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
+"ActionOnPurge FROM Pool WHERE Pool.Name='%s'",
pdbr->Name);
}
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat));
pdbr->RecyclePoolId = str_to_int64(row[17]);
pdbr->ScratchPoolId = str_to_int64(row[18]);
+ pdbr->ActionOnPurge = str_to_int32(row[19]);
ok = true;
}
}
return ok;
}
-/* Get Client Record
+/**
+ * Get Client Record
* If the ClientId is non-zero, we get its record,
* otherwise, we search on the Client Name
*
return stat;
}
-/*
+/**
* Get Counter Record
*
* Returns: 0 on failure
SQL_ROW row;
db_lock(mdb);
- Mmsg(mdb->cmd, "SELECT MinValue,MaxValue,CurrentValue,WrapCounter "
+ Mmsg(mdb->cmd, "SELECT \"MinValue\",\"MaxValue\",CurrentValue,WrapCounter "
"FROM Counters WHERE Counter='%s'", cr->Counter);
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
}
-/* Get FileSet Record
+/**
+ * Get FileSet Record
* If the FileSetId is non-zero, we get its record,
* otherwise, we search on the name
*
}
-/*
+/**
* Get the number of Media records
*
* Returns: -1 on failure
return stat;
}
-
-/*
+/**
* This function returns a list of all the Media record ids for
- * the current Pool with the correct Media Type.
+ * the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
+ * VolumeName if specified
* The caller must free ids if non-NULL.
*
* Returns false: on failure
uint32_t *id;
char ed1[50];
bool ok = false;
+ char buf[MAX_NAME_LENGTH*3]; /* Can contain MAX_NAME_LENGTH*2+1 + AND ....='' */
+ char esc[MAX_NAME_LENGTH*2+1];
db_lock(mdb);
*ids = NULL;
- Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE PoolId=%s "
- " AND MediaType='%s'",
- edit_int64(mr->PoolId, ed1), mr->MediaType);
+
+ Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE Recycle=%d AND Enabled=%d ",
+ mr->Recycle, mr->Enabled);
+
+ if (*mr->MediaType) {
+ db_escape_string(jcr, mdb, esc, mr->MediaType, strlen(mr->MediaType));
+ bsnprintf(buf, sizeof(buf), "AND MediaType='%s' ", esc);
+ pm_strcat(mdb->cmd, buf);
+ }
+
+ if (mr->StorageId) {
+ bsnprintf(buf, sizeof(buf), "AND StorageId=%s ", edit_uint64(mr->StorageId, ed1));
+ pm_strcat(mdb->cmd, buf);
+ }
+
+ if (mr->PoolId) {
+ bsnprintf(buf, sizeof(buf), "AND PoolId=%s ", edit_uint64(mr->PoolId, ed1));
+ pm_strcat(mdb->cmd, buf);
+ }
+
+ if (mr->VolBytes) {
+ bsnprintf(buf, sizeof(buf), "AND VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
+ pm_strcat(mdb->cmd, buf);
+ }
+
+ if (*mr->VolumeName) {
+ db_escape_string(jcr, mdb, esc, mr->VolumeName, strlen(mr->VolumeName));
+ bsnprintf(buf, sizeof(buf), "AND VolumeName = '%s' ", esc);
+ pm_strcat(mdb->cmd, buf);
+ }
+
+ if (*mr->VolStatus) {
+ db_escape_string(jcr, mdb, esc, mr->VolStatus, strlen(mr->VolStatus));
+ bsnprintf(buf, sizeof(buf), "AND VolStatus = '%s' ", esc);
+ pm_strcat(mdb->cmd, buf);
+ }
+
+ Dmsg1(100, "q=%s\n", mdb->cmd);
+
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
*num_ids = sql_num_rows(mdb);
if (*num_ids > 0) {
}
-/*
+/**
* This function returns a list of all the DBIds that are returned
* for the query.
*
return ok;
}
-/* Get Media Record
+/**
+ * Get Media Record
*
* Returns: false: on failure
* true: on success
"MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
"EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
"Enabled,LocationId,RecycleCount,InitialWrite,"
- "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime "
+ "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
"FROM Media WHERE MediaId=%s",
edit_int64(mr->MediaId, ed1));
} else { /* find by name */
"MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
"EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
"Enabled,LocationId,RecycleCount,InitialWrite,"
- "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime "
+ "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
"FROM Media WHERE VolumeName='%s'", mr->VolumeName);
}
mr->RecyclePoolId = str_to_int64(row[34]);
mr->VolReadTime = str_to_int64(row[35]);
mr->VolWriteTime = str_to_int64(row[36]);
+ mr->ActionOnPurge = str_to_int32(row[37]);
ok = true;
}
return ok;
}
-/*
+/**
* Find the last "accurate" backup state (that can take deleted files in
* account)
* 1) Get all files with jobid in list (F subquery)
#ifdef new_db_get_file_list
POOL_MEM buf2(PM_MESSAGE);
Mmsg(buf2, select_recent_version_with_basejob[db_type],
- jobids, jobids, jobids);
+ jobids, jobids, jobids, jobids);
Mmsg(buf,
"SELECT Path.Path, Filename.Name, Temp.FileIndex, Temp.JobId, LStat, MD5 "
"FROM ( %s ) AS Temp "
return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
}
-/*
+/**
* This procedure gets the base jobid list used by jobids,
*/
bool db_get_used_base_jobids(JCR *jcr, B_DB *mdb,
"SELECT DISTINCT BaseJobId "
" FROM Job JOIN BaseFiles USING (JobId) "
" WHERE Job.HasBase = 1 "
- " AND JobId IN (%s) ", jobids);
+ " AND Job.JobId IN (%s) ", jobids);
return db_sql_query(mdb, buf.c_str(), db_list_handler, result);
}
-/* The decision do change an incr/diff was done before
+/**
+ * The decision do change an incr/diff was done before
* Full : do nothing
* Differential : get the last full id
* Incremental : get the last full + last diff + last incr(s) ids
utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
bstrutime(date, sizeof(date), StartTime + 1);
- jobids->list[0] = 0;
- jobids->count = 0;
+ jobids->reset();
/* First, find the last good Full backup for this job/client/fileset */
- Mmsg(query,
-"CREATE TABLE btemp3%s AS "
- "SELECT JobId, StartTime, EndTime, JobTDate, PurgedFiles "
- "FROM Job JOIN FileSet USING (FileSetId) "
- "WHERE ClientId = %s "
- "AND Level='F' AND JobStatus IN ('T','W') AND Type='B' "
- "AND StartTime<'%s' "
- "AND FileSet.FileSet=(SELECT FileSet FROM FileSet WHERE FileSetId = %s) "
- "ORDER BY Job.JobTDate DESC LIMIT 1",
+ Mmsg(query, create_temp_accurate_jobids[db_type],
edit_uint64(jcr->JobId, jobid),
edit_uint64(jr->ClientId, clientid),
date,
bool db_get_base_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr, JobId_t *jobid)
{
- char date[MAX_TIME_LENGTH];
- int64_t id = *jobid = 0;
POOL_MEM query(PM_FNAME);
-
+ utime_t StartTime;
+ db_int64_ctx lctx;
+ char date[MAX_TIME_LENGTH];
+ bool ret=false;
// char clientid[50], filesetid[50];
+ *jobid = 0;
+ lctx.count = 0;
+ lctx.value = 0;
- utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
+ StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
bstrutime(date, sizeof(date), StartTime + 1);
/* we can take also client name, fileset, etc... */
date);
Dmsg1(10, "db_get_base_jobid q=%s\n", query.c_str());
- if (!db_sql_query(mdb, query.c_str(), db_int64_handler, &id)) {
+ if (!db_sql_query(mdb, query.c_str(), db_int64_handler, &lctx)) {
goto bail_out;
}
- *jobid = (JobId_t) id;
+ *jobid = (JobId_t) lctx.value;
- Dmsg1(10, "db_get_base_jobid=%lld\n", id);
- return true;
+ Dmsg1(10, "db_get_base_jobid=%lld\n", *jobid);
+ ret = true;
bail_out:
- return false;
-}
-
-/*
- * Use to build a string of int list from a query. "10,20,30"
- */
-int db_get_int_handler(void *ctx, int num_fields, char **row)
-{
- POOLMEM *ret = (POOLMEM *)ctx;
- if (num_fields == 1) {
- if (ret[0]) {
- pm_strcat(ret, ",");
- }
- pm_strcat(ret, row[0]);
- }
- return 0;
+ return ret;
}
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */