/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2008 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 $
*/
+#include "bacula.h"
-/* 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 */
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
-#include "bacula.h"
#include "cats.h"
-
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#include "bdb_priv.h"
+#include "sql_glue.h"
/* -----------------------------------------------------------------------
*
/* Forward referenced functions */
static int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr);
static int db_get_filename_record(JCR *jcr, B_DB *mdb);
-static int db_get_path_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
* use includes the directory twice. In this case, Verify
* VolumeToCatalog fails because we have two copies in the catalog,
* and only the first one is marked (twice). So, when calling from Verify,
- * jr is not NULL and we know jr->FileIndex is the fileindex
+ * VolumeToCatalog jr is not NULL and we know jr->FileIndex is the fileindex
* of the version of the directory/file we actually want and do
* a more explicit SQL search.
*/
SQL_ROW row;
int stat = 0;
char ed1[50], ed2[50], ed3[50];
+ int num_rows;
- 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 */
+ } else if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG) {
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);
+ "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
+ "File.FilenameId=%s AND File.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 "
Dmsg1(100, "Query=%s\n", mdb->cmd);
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) {
+ num_rows = sql_num_rows(mdb);
+ Dmsg1(050, "get_file_record num_rows=%d\n", num_rows);
+ if (num_rows >= 1) {
if ((row = sql_fetch_row(mdb)) == NULL) {
Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
} else {
bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
stat = 1;
+ if (num_rows > 1) {
+ Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
+ 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
*
{
SQL_ROW row;
int FilenameId = 0;
+ int num_rows;
mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
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)) {
char ed1[30];
- mdb->num_rows = sql_num_rows(mdb);
- if (mdb->num_rows > 1) {
+ num_rows = sql_num_rows(mdb);
+ if (num_rows > 1) {
Mmsg2(mdb->errmsg, _("More than one Filename!: %s for file: %s\n"),
- edit_uint64(mdb->num_rows, ed1), mdb->fname);
+ edit_uint64(num_rows, ed1), mdb->fname);
Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
}
- if (mdb->num_rows >= 1) {
+ if (num_rows >= 1) {
if ((row = sql_fetch_row(mdb)) == NULL) {
Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
} else {
return FilenameId;
}
-/* Get path record
+/**
+ * Get path record
* Returns: 0 on failure
* PathId on success
*
* DO NOT use Jmsg in this routine (see notes for get_file_record)
*/
-static int db_get_path_record(JCR *jcr, B_DB *mdb)
+int db_get_path_record(JCR *jcr, B_DB *mdb)
{
SQL_ROW row;
uint32_t PathId = 0;
+ int num_rows;
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 (QUERY_DB(jcr, mdb, mdb->cmd)) {
char ed1[30];
- mdb->num_rows = sql_num_rows(mdb);
- if (mdb->num_rows > 1) {
+ num_rows = sql_num_rows(mdb);
+ if (num_rows > 1) {
Mmsg2(mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
- edit_uint64(mdb->num_rows, ed1), mdb->path);
+ edit_uint64(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 (num_rows >= 1) {
if ((row = sql_fetch_row(mdb)) == NULL) {
Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
} else {
}
-/*
+/**
* Get Job record for given JobId or Job name
* Returns: false on failure
* true on success
{
SQL_ROW row;
char ed1[50];
+ char esc[MAX_ESCAPE_NAME_LENGTH];
db_lock(mdb);
if (jr->JobId == 0) {
+ mdb->db_escape_string(jcr, esc, jr->Job, strlen(jr->Job));
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 "
-"FROM Job WHERE Job='%s'", jr->Job);
+"SchedTime,RealEndTime,ReadBytes,HasBase,PurgedFiles "
+"FROM Job WHERE Job='%s'", esc);
} 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 "
+"SchedTime,RealEndTime,ReadBytes,HasBase,PurgedFiles "
"FROM Job WHERE JobId=%s",
edit_int64(jr->JobId, ed1));
}
jr->SchedTime = str_to_utime(jr->cSchedTime);
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
char ed1[50];
int stat = 0;
int i;
+ int num_rows;
db_lock(mdb);
/* Get one entry per VolumeName, but "sort" by VolIndex */
Dmsg1(130, "VolNam=%s\n", mdb->cmd);
*VolumeNames[0] = 0;
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
- mdb->num_rows = sql_num_rows(mdb);
- Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
- if (mdb->num_rows <= 0) {
+ num_rows = sql_num_rows(mdb);
+ Dmsg1(130, "Num rows=%d\n", num_rows);
+ if (num_rows <= 0) {
Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
stat = 0;
} else {
- stat = mdb->num_rows;
+ stat = num_rows;
for (i=0; i < stat; i++) {
if ((row = sql_fetch_row(mdb)) == NULL) {
Mmsg2(mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
return stat;
}
-/*
+/**
* Find Volume parameters for a give JobId
* Returns: 0 on error or no Volumes found
* number of volumes on success
int stat = 0;
int i;
VOL_PARAMS *Vols = NULL;
+ int num_rows;
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",
Dmsg1(130, "VolNam=%s\n", mdb->cmd);
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
- mdb->num_rows = sql_num_rows(mdb);
- Dmsg1(200, "Num rows=%d\n", mdb->num_rows);
- if (mdb->num_rows <= 0) {
+ num_rows = sql_num_rows(mdb);
+ Dmsg1(200, "Num rows=%d\n", num_rows);
+ if (num_rows <= 0) {
Mmsg1(mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId);
stat = 0;
} else {
- stat = mdb->num_rows;
+ stat = num_rows;
DBId_t *SId = NULL;
if (stat > 0) {
*VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
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
*
SQL_ROW row;
bool ok = false;
char ed1[50];
+ int num_rows;
+ char esc[MAX_ESCAPE_NAME_LENGTH];
db_lock(mdb);
if (pdbr->PoolId != 0) { /* find by id */
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 */
+ mdb->db_escape_string(jcr, esc, pdbr->Name, strlen(pdbr->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'",
- pdbr->Name);
+"MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId,"
+"ActionOnPurge FROM Pool WHERE Pool.Name='%s'", esc);
}
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
- mdb->num_rows = sql_num_rows(mdb);
- if (mdb->num_rows > 1) {
+ num_rows = sql_num_rows(mdb);
+ if (num_rows > 1) {
char ed1[30];
Mmsg1(mdb->errmsg, _("More than one Pool!: %s\n"),
- edit_uint64(mdb->num_rows, ed1));
+ edit_uint64(num_rows, ed1));
Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
- } else if (mdb->num_rows == 1) {
+ } else if (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);
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
*
SQL_ROW row;
int stat = 0;
char ed1[50];
+ int num_rows;
+ char esc[MAX_ESCAPE_NAME_LENGTH];
db_lock(mdb);
if (cdbr->ClientId != 0) { /* find by id */
"FROM Client WHERE Client.ClientId=%s",
edit_int64(cdbr->ClientId, ed1));
} else { /* find by name */
+ mdb->db_escape_string(jcr, esc, cdbr->Name, strlen(cdbr->Name));
Mmsg(mdb->cmd,
"SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention "
-"FROM Client WHERE Client.Name='%s'", cdbr->Name);
+"FROM Client WHERE Client.Name='%s'", esc);
}
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
- mdb->num_rows = sql_num_rows(mdb);
- if (mdb->num_rows > 1) {
+ num_rows = sql_num_rows(mdb);
+ if (num_rows > 1) {
Mmsg1(mdb->errmsg, _("More than one Client!: %s\n"),
- edit_uint64(mdb->num_rows, ed1));
+ edit_uint64(num_rows, ed1));
Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
- } else if (mdb->num_rows == 1) {
+ } else if (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);
return stat;
}
-/*
+/**
* Get Counter Record
*
* Returns: 0 on failure
int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
{
SQL_ROW row;
+ int num_rows;
+ char esc[MAX_ESCAPE_NAME_LENGTH];
db_lock(mdb);
- Mmsg(mdb->cmd, "SELECT MinValue,MaxValue,CurrentValue,WrapCounter "
- "FROM Counters WHERE Counter='%s'", cr->Counter);
+ mdb->db_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
+
+ Mmsg(mdb->cmd, "SELECT \"MinValue\",\"MaxValue\",CurrentValue,WrapCounter "
+ "FROM Counters WHERE Counter='%s'", esc);
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
- mdb->num_rows = sql_num_rows(mdb);
+ num_rows = sql_num_rows(mdb);
/* If more than one, report error, but return first row */
- if (mdb->num_rows > 1) {
- Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), (int)(mdb->num_rows));
+ if (num_rows > 1) {
+ Mmsg1(mdb->errmsg, _("More than one Counter!: %d\n"), num_rows);
Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
}
- if (mdb->num_rows >= 1) {
+ if (num_rows >= 1) {
if ((row = sql_fetch_row(mdb)) == NULL) {
Mmsg1(mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb));
Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
}
-/* Get FileSet Record
+/**
+ * Get FileSet Record
* If the FileSetId is non-zero, we get its record,
* otherwise, we search on the name
*
SQL_ROW row;
int stat = 0;
char ed1[50];
+ int num_rows;
+ char esc[MAX_ESCAPE_NAME_LENGTH];
db_lock(mdb);
if (fsr->FileSetId != 0) { /* find by id */
"WHERE FileSetId=%s",
edit_int64(fsr->FileSetId, ed1));
} else { /* find by name */
+ mdb->db_escape_string(jcr, esc, fsr->FileSet, strlen(fsr->FileSet));
Mmsg(mdb->cmd,
"SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
- "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", fsr->FileSet);
+ "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", esc);
}
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
- mdb->num_rows = sql_num_rows(mdb);
- if (mdb->num_rows > 1) {
+ num_rows = sql_num_rows(mdb);
+ if (num_rows > 1) {
char ed1[30];
Mmsg1(mdb->errmsg, _("Error got %s FileSets but expected only one!\n"),
- edit_uint64(mdb->num_rows, ed1));
- sql_data_seek(mdb, mdb->num_rows-1);
+ edit_uint64(num_rows, ed1));
+ sql_data_seek(mdb, num_rows-1);
}
if ((row = sql_fetch_row(mdb)) == NULL) {
Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
}
-/*
+/**
* 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
SQL_ROW row;
char ed1[50];
bool ok = false;
+ int num_rows;
+ char esc[MAX_ESCAPE_NAME_LENGTH];
db_lock(mdb);
if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
"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 */
+ mdb->db_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
"VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
"MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
"MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
"EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
"Enabled,LocationId,RecycleCount,InitialWrite,"
- "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime "
- "FROM Media WHERE VolumeName='%s'", mr->VolumeName);
+ "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
+ "FROM Media WHERE VolumeName='%s'", esc);
}
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
char ed1[50];
- mdb->num_rows = sql_num_rows(mdb);
- if (mdb->num_rows > 1) {
+ num_rows = sql_num_rows(mdb);
+ if (num_rows > 1) {
Mmsg1(mdb->errmsg, _("More than one Volume!: %s\n"),
- edit_uint64(mdb->num_rows, ed1));
+ edit_uint64(num_rows, ed1));
Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
- } else if (mdb->num_rows == 1) {
+ } else if (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);
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)
+/* Remove all MD5 from a query (can save lot of memory with many files) */
+static void strip_md5(char *q)
+{
+ char *p = q;
+ while ((p = strstr(p, ", MD5"))) {
+ memset(p, ' ', 5 * sizeof(char));
+ }
+}
+
+/**
+ * Find the last "accurate" backup state (that can take deleted files in
+ * account)
* 1) Get all files with jobid in list (F subquery)
* Get all files in BaseFiles with jobid in list
- * 2) Take only the last version of each file (Temp subquery) => accurate list is ok
+ * 2) Take only the last version of each file (Temp subquery) => accurate list
+ * is ok
* 3) Join the result to file table to get fileindex, jobid and lstat information
*
* TODO: See if we can do the SORT only if needed (as an argument)
*/
-bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
+bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
+ bool use_md5, bool use_delta,
DB_RESULT_HANDLER *result_handler, void *ctx)
{
if (!*jobids) {
return false;
}
POOL_MEM buf(PM_MESSAGE);
-
-#define new_db_get_file_list
-#ifdef new_db_get_file_list
- /* This is broken, at least if called from ua_restore.c */
- Mmsg(buf,
- "SELECT Path.Path, Filename.Name, File.FileIndex, File.JobId, File.LStat "
- "FROM ( "
- "SELECT max(FileId) as FileId, PathId, FilenameId "
- "FROM (SELECT FileId, PathId, FilenameId FROM File WHERE JobId IN (%s) "
- "UNION "
- "SELECT File.FileId, PathId, FilenameId "
- "FROM BaseFiles JOIN File USING (FileId) "
- "WHERE BaseFiles.JobId IN (%s) "
- ") AS F "
- "GROUP BY PathId, FilenameId "
- ") AS Temp "
- "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
- "JOIN Path ON (Path.PathId = Temp.PathId) "
- "JOIN File ON (File.FileId = Temp.FileId) "
-"WHERE File.FileIndex > 0 ORDER BY JobId, FileIndex ASC",/* Return sorted by JobId, */
- /* FileIndex for restore code */
- jobids, jobids);
- Dmsg1(0, "q=%s\n", buf.c_str());
-#else
- /*
- * I am not sure that this works the same as the code in ua_restore.c
- * but it is very similar. The accurate-test fails in a restore. Bad file count.
+ POOL_MEM buf2(PM_MESSAGE);
+ if (use_delta) {
+ Mmsg(buf2, select_recent_version_with_basejob_and_delta[db_get_type_index(mdb)],
+ jobids, jobids, jobids, jobids);
+
+ } else {
+ Mmsg(buf2, select_recent_version_with_basejob[db_get_type_index(mdb)],
+ jobids, jobids, jobids, jobids);
+ }
+
+ /* bsr code is optimized for JobId sorted, with Delta, we need to get
+ * them ordered by date. JobTDate and JobId can be mixed if using Copy
+ * or Migration
*/
- Mmsg(buf, uar_sel_files, jobids);
-#endif
+ Mmsg(buf,
+"SELECT Path.Path, Filename.Name, T1.FileIndex, T1.JobId, LStat, DeltaSeq, MD5 "
+ "FROM ( %s ) AS T1 "
+ "JOIN Filename ON (Filename.FilenameId = T1.FilenameId) "
+ "JOIN Path ON (Path.PathId = T1.PathId) "
+"WHERE FileIndex > 0 "
+"ORDER BY T1.JobTDate, FileIndex ASC",/* Return sorted by JobTDate */
+ /* FileIndex for restore code */
+ buf2.c_str());
+
+ if (!use_md5) {
+ strip_md5(buf.c_str());
+ }
- return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
+ Dmsg1(100, "q=%s\n", buf.c_str());
+
+ return db_big_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,
+ POOLMEM *jobids, db_list_ctx *result)
+{
+ POOL_MEM buf;
+ Mmsg(buf,
+ "SELECT DISTINCT BaseJobId "
+ " FROM Job JOIN BaseFiles USING (JobId) "
+ " WHERE Job.HasBase = 1 "
+ " 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
* TODO: look and merge from ua_restore.c
*/
bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
- JOB_DBR *jr, POOLMEM *jobids)
+ JOB_DBR *jr, db_list_ctx *jobids)
{
bool ret=false;
char clientid[50], jobid[50], filesetid[50];
utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
bstrutime(date, sizeof(date), StartTime + 1);
- jobids[0]='\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_get_type_index(mdb)],
edit_uint64(jcr->JobId, jobid),
edit_uint64(jr->ClientId, clientid),
date,
/* build a jobid list ie: 1,2,3,4 */
Mmsg(query, "SELECT JobId FROM btemp3%s ORDER by JobTDate", jobid);
- db_sql_query(mdb, query.c_str(), db_get_int_handler, jobids);
- Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids);
+ db_sql_query(mdb, query.c_str(), db_list_handler, jobids);
+ Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids->list);
ret = true;
bail_out:
return ret;
}
+bool db_get_base_file_list(JCR *jcr, B_DB *mdb, bool use_md5,
+ DB_RESULT_HANDLER *result_handler, void *ctx)
+{
+ POOL_MEM buf(PM_MESSAGE);
+
+ Mmsg(buf,
+ "SELECT Path, Name, FileIndex, JobId, LStat, 0 As DeltaSeq, MD5 "
+ "FROM new_basefile%lld ORDER BY JobId, FileIndex ASC",
+ (uint64_t) jcr->JobId);
+
+ if (!use_md5) {
+ strip_md5(buf.c_str());
+ }
+ return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
+}
+
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];
+ char esc[MAX_ESCAPE_NAME_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);
-
+ mdb->db_escape_string(jcr, esc, jr->Name, strlen(jr->Name));
+
/* we can take also client name, fileset, etc... */
Mmsg(query,
// "AND Client.Name = '%s' "
"AND StartTime<'%s' "
"ORDER BY Job.JobTDate DESC LIMIT 1",
- jr->Name,
+ esc,
// edit_uint64(jr->ClientId, clientid),
// edit_uint64(jr->FileSetId, filesetid));
date);
- Dmsg1(1, "db_get_base_jobid q=%s\n", query.c_str());
- if (!db_sql_query(mdb, query.c_str(), db_int64_handler, &id)) {
+ Dmsg1(10, "db_get_base_jobid q=%s\n", query.c_str());
+ 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(1, "db_get_base_jobid=%lld\n", id);
- return true;
+ Dmsg1(10, "db_get_base_jobid=%lld\n", *jobid);
+ ret = true;
bail_out:
- return false;
+ return ret;
}
-/*
- * 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)
+/* Get JobIds associated with a volume */
+bool db_get_volume_jobids(JCR *jcr, B_DB *mdb,
+ MEDIA_DBR *mr, db_list_ctx *lst)
{
- POOLMEM *ret = (POOLMEM *)ctx;
- if (num_fields == 1) {
- if (ret[0]) {
- pm_strcat(ret, ",");
- }
- pm_strcat(ret, row[0]);
- }
- return 0;
+ char ed1[50];
+ bool ret=false;
+
+ db_lock(mdb);
+ Mmsg(mdb->cmd, "SELECT DISTINCT JobId FROM JobMedia WHERE MediaId=%s",
+ edit_int64(mr->MediaId, ed1));
+ ret = db_sql_query(mdb, mdb->cmd, db_list_handler, lst);
+ db_unlock(mdb);
+ return ret;
}
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */