]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/cats/sql_get.c
Backport of class based catalog backends into Branch-5.1.
[bacula/bacula] / bacula / src / cats / sql_get.c
index 6582a153707eb961fdc262e978f9e7cabd65f9f2..3d11c08048e87d974a9091a6a1b78ac2aec99989 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
 /*
    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
 
    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.
 
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
    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.
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
@@ -25,7 +25,7 @@
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
    (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
  * 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
  *
  */
 
  *
  */
 
+#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"
 #include "cats.h"
-
-#if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
+#include "bdb_priv.h"
+#include "sql_glue.h"
 
 /* -----------------------------------------------------------------------
  *
 
 /* -----------------------------------------------------------------------
  *
@@ -58,7 +55,7 @@ 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_filename_record(JCR *jcr, B_DB *mdb);
 
 
-/*
+/**
  * Given a full filename (with path), look up the File record
  * (with attributes) in the database.
  *
  * Given a full filename (with path), look up the File record
  * (with attributes) in the database.
  *
@@ -85,7 +82,7 @@ int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr,
 }
 
 
 }
 
 
-/*
+/**
  * Get a File record
  * Returns: 0 on failure
  *          1 on success
  * Get a File record
  * Returns: 0 on failure
  *          1 on success
@@ -104,7 +101,7 @@ int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr,
  *    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, 
  *    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.
  */
  *    of the version of the directory/file we actually want and do
  *    a more explicit SQL search.
  */
@@ -114,6 +111,7 @@ int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
    SQL_ROW row;
    int stat = 0;
    char ed1[50], ed2[50], ed3[50];
    SQL_ROW row;
    int stat = 0;
    char ed1[50], ed2[50], ed3[50];
+   int num_rows;
 
    if (jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG) {
       Mmsg(mdb->cmd,
 
    if (jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG) {
       Mmsg(mdb->cmd,
@@ -124,16 +122,14 @@ int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
       edit_int64(fdbr->PathId, ed1), 
       edit_int64(fdbr->FilenameId, ed2), 
       edit_int64(jr->ClientId,ed3));
       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,
       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 "
    } else {
       Mmsg(mdb->cmd,
 "SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
@@ -148,9 +144,9 @@ int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
    Dmsg1(100, "Query=%s\n", mdb->cmd);
 
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
    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) {
+      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 {
          if ((row = sql_fetch_row(mdb)) == NULL) {
             Mmsg1(mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb));
          } else {
@@ -158,9 +154,9 @@ int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
             bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
             bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
             stat = 1;
             bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
             bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
             stat = 1;
-            if (mdb->num_rows > 1) {
+            if (num_rows > 1) {
                Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
                Mmsg3(mdb->errmsg, _("get_file_record want 1 got rows=%d PathId=%s FilenameId=%s\n"),
-                  mdb->num_rows, 
+                  num_rows, 
                   edit_int64(fdbr->PathId, ed1), 
                   edit_int64(fdbr->FilenameId, ed2));
                Dmsg1(000, "=== Problem!  %s", mdb->errmsg);
                   edit_int64(fdbr->PathId, ed1), 
                   edit_int64(fdbr->FilenameId, ed2));
                Dmsg1(000, "=== Problem!  %s", mdb->errmsg);
@@ -179,7 +175,8 @@ int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
 
 }
 
 
 }
 
-/* Get Filename record
+/**
+ * Get Filename record
  * Returns: 0 on failure
  *          FilenameId on success
  *
  * Returns: 0 on failure
  *          FilenameId on success
  *
@@ -189,6 +186,7 @@ static int db_get_filename_record(JCR *jcr, B_DB *mdb)
 {
    SQL_ROW row;
    int FilenameId = 0;
 {
    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);
 
    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);
@@ -196,13 +194,13 @@ static int db_get_filename_record(JCR *jcr, B_DB *mdb)
    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
       char ed1[30];
    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"),
          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);
       }
          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 {
          if ((row = sql_fetch_row(mdb)) == NULL) {
             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
          } else {
@@ -223,7 +221,8 @@ static int db_get_filename_record(JCR *jcr, B_DB *mdb)
    return FilenameId;
 }
 
    return FilenameId;
 }
 
-/* Get path record
+/**
+ * Get path record
  * Returns: 0 on failure
  *          PathId on success
  *
  * Returns: 0 on failure
  *          PathId on success
  *
@@ -233,6 +232,7 @@ int db_get_path_record(JCR *jcr, B_DB *mdb)
 {
    SQL_ROW row;
    uint32_t PathId = 0;
 {
    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);
 
    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);
@@ -246,14 +246,14 @@ int db_get_path_record(JCR *jcr, B_DB *mdb)
 
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
       char ed1[30];
 
    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"),
          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 */
          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 {
          if ((row = sql_fetch_row(mdb)) == NULL) {
             Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
          } else {
@@ -282,7 +282,7 @@ int db_get_path_record(JCR *jcr, B_DB *mdb)
 }
 
 
 }
 
 
-/*
+/**
  * Get Job record for given JobId or Job name
  * Returns: false on failure
  *          true  on success
  * Get Job record for given JobId or Job name
  * Returns: false on failure
  *          true  on success
@@ -297,13 +297,13 @@ bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
       Mmsg(mdb->cmd, "SELECT VolSessionId,VolSessionTime,"
 "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus,"
 "Type,Level,ClientId,Name,PriorJobId,RealEndTime,JobId,FileSetId,"
       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,"
 "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));
     }
 "FROM Job WHERE JobId=%s", 
           edit_int64(jr->JobId, ed1));
     }
@@ -347,13 +347,14 @@ bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
    jr->EndTime = str_to_utime(jr->cEndTime);
    jr->RealEndTime = str_to_utime(jr->cRealEndTime);
    jr->HasBase = str_to_int64(row[21]);
    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;
 }
 
    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
  * Find VolumeNames for a given JobId
  *  Returns: 0 on error or no Volumes found
  *           number of volumes on success
@@ -369,6 +370,7 @@ int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **Volume
    char ed1[50];
    int stat = 0;
    int i;
    char ed1[50];
    int stat = 0;
    int i;
+   int num_rows;
 
    db_lock(mdb);
    /* Get one entry per VolumeName, but "sort" by VolIndex */
 
    db_lock(mdb);
    /* Get one entry per VolumeName, but "sort" by VolIndex */
@@ -381,13 +383,13 @@ int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **Volume
    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
    *VolumeNames[0] = 0;
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
    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 {
          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));
          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));
@@ -410,7 +412,7 @@ int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **Volume
    return stat;
 }
 
    return stat;
 }
 
-/*
+/**
  * Find Volume parameters for a give JobId
  *  Returns: 0 on error or no Volumes found
  *           number of volumes on success
  * Find Volume parameters for a give JobId
  *  Returns: 0 on error or no Volumes found
  *           number of volumes on success
@@ -425,6 +427,7 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS
    int stat = 0;
    int i;
    VOL_PARAMS *Vols = NULL;
    int stat = 0;
    int i;
    VOL_PARAMS *Vols = NULL;
+   int num_rows;
 
    db_lock(mdb);
    Mmsg(mdb->cmd,
 
    db_lock(mdb);
    Mmsg(mdb->cmd,
@@ -437,13 +440,13 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS
 
    Dmsg1(130, "VolNam=%s\n", mdb->cmd);
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
 
    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 {
          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));
          DBId_t *SId = NULL;
          if (stat > 0) {
             *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS));
@@ -498,7 +501,7 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS
 
 
 
 
 
 
-/*
+/**
  * Get the number of pool records
  *
  * Returns: -1 on failure
  * Get the number of pool records
  *
  * Returns: -1 on failure
@@ -515,7 +518,7 @@ int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
    return stat;
 }
 
    return stat;
 }
 
-/*
+/**
  * This function returns a list of all the Pool record ids.
  *  The caller must free ids if non-NULL.
  *
  * This function returns a list of all the Pool record ids.
  *  The caller must free ids if non-NULL.
  *
@@ -552,7 +555,7 @@ int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
    return stat;
 }
 
    return stat;
 }
 
-/*
+/**
  * This function returns a list of all the Client record ids.
  *  The caller must free ids if non-NULL.
  *
  * This function returns a list of all the Client record ids.
  *  The caller must free ids if non-NULL.
  *
@@ -591,7 +594,8 @@ int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
 
 
 
 
 
 
-/* Get Pool Record
+/**
+ * Get Pool Record
  * If the PoolId is non-zero, we get its record,
  *  otherwise, we search on the PoolName
  *
  * If the PoolId is non-zero, we get its record,
  *  otherwise, we search on the PoolName
  *
@@ -603,6 +607,7 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
    SQL_ROW row;
    bool ok = false;
    char ed1[50];
    SQL_ROW row;
    bool ok = false;
    char ed1[50];
+   int num_rows;
 
    db_lock(mdb);
    if (pdbr->PoolId != 0) {               /* find by id */
 
    db_lock(mdb);
    if (pdbr->PoolId != 0) {               /* find by id */
@@ -621,13 +626,13 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
          pdbr->Name);
    }
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
          pdbr->Name);
    }
    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"),
          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);
          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);
          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);
@@ -674,7 +679,8 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr)
    return ok;
 }
 
    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
  *
  * If the ClientId is non-zero, we get its record,
  *  otherwise, we search on the Client Name
  *
@@ -686,6 +692,7 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
    SQL_ROW row;
    int stat = 0;
    char ed1[50];
    SQL_ROW row;
    int stat = 0;
    char ed1[50];
+   int num_rows;
 
    db_lock(mdb);
    if (cdbr->ClientId != 0) {               /* find by id */
 
    db_lock(mdb);
    if (cdbr->ClientId != 0) {               /* find by id */
@@ -700,12 +707,12 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
    }
 
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
    }
 
    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"),
          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);
          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);
          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);
@@ -729,7 +736,7 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
    return stat;
 }
 
    return stat;
 }
 
-/*
+/**
  * Get Counter Record
  *
  * Returns: 0 on failure
  * Get Counter Record
  *
  * Returns: 0 on failure
@@ -738,20 +745,21 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr)
 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
 {
    SQL_ROW row;
 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
 {
    SQL_ROW row;
+   int num_rows;
 
    db_lock(mdb);
 
    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)) {
       "FROM Counters WHERE Counter='%s'", cr->Counter);
 
    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 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);
       }
          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);
          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);
@@ -780,7 +788,8 @@ int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
 }
 
 
 }
 
 
-/* Get FileSet Record
+/**
+ * Get FileSet Record
  * If the FileSetId is non-zero, we get its record,
  *  otherwise, we search on the name
  *
  * If the FileSetId is non-zero, we get its record,
  *  otherwise, we search on the name
  *
@@ -792,6 +801,7 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
    SQL_ROW row;
    int stat = 0;
    char ed1[50];
    SQL_ROW row;
    int stat = 0;
    char ed1[50];
+   int num_rows;
 
    db_lock(mdb);
    if (fsr->FileSetId != 0) {               /* find by id */
 
    db_lock(mdb);
    if (fsr->FileSetId != 0) {               /* find by id */
@@ -806,12 +816,12 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
    }
 
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
    }
 
    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"),
          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);
       }
       if ((row = sql_fetch_row(mdb)) == NULL) {
          Mmsg1(mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet);
@@ -831,7 +841,7 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
 }
 
 
 }
 
 
-/*
+/**
  * Get the number of Media records
  *
  * Returns: -1 on failure
  * Get the number of Media records
  *
  * Returns: -1 on failure
@@ -848,7 +858,7 @@ int db_get_num_media_records(JCR *jcr, B_DB *mdb)
    return stat;
 }
 
    return stat;
 }
 
-/*
+/**
  * This function returns a list of all the Media record ids for
  *     the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
  *     VolumeName if specified
  * This function returns a list of all the Media record ids for
  *     the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
  *     VolumeName if specified
@@ -929,7 +939,7 @@ bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, int *num_ids, uint32_t
 }
 
 
 }
 
 
-/*
+/**
  * This function returns a list of all the DBIds that are returned
  *   for the query.
  *
  * This function returns a list of all the DBIds that are returned
  *   for the query.
  *
@@ -966,7 +976,8 @@ bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids)
    return ok;
 }
 
    return ok;
 }
 
-/* Get Media Record
+/**
+ * Get Media Record
  *
  * Returns: false: on failure
  *          true:  on success
  *
  * Returns: false: on failure
  *          true:  on success
@@ -976,6 +987,7 @@ bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
    SQL_ROW row;
    char ed1[50];
    bool ok = false;
    SQL_ROW row;
    char ed1[50];
    bool ok = false;
+   int num_rows;
 
    db_lock(mdb);
    if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
 
    db_lock(mdb);
    if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
@@ -1007,12 +1019,12 @@ bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
 
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
       char ed1[50];
 
    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"),
          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);
          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);
          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);
@@ -1085,7 +1097,16 @@ bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
    return ok;
 }
 
    return ok;
 }
 
-/*
+/* 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)
  * Find the last "accurate" backup state (that can take deleted files in
  * account)
  * 1) Get all files with jobid in list (F subquery)
@@ -1096,7 +1117,8 @@ bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
  *
  * TODO: See if we can do the SORT only if needed (as an argument)
  */
  *
  * 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) {
                       DB_RESULT_HANDLER *result_handler, void *ctx)
 {
    if (!*jobids) {
@@ -1106,33 +1128,40 @@ bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
       return false;
    }
    POOL_MEM buf(PM_MESSAGE);
       return false;
    }
    POOL_MEM buf(PM_MESSAGE);
-         
-#define new_db_get_file_list
-#ifdef new_db_get_file_list
    POOL_MEM buf2(PM_MESSAGE);
    POOL_MEM buf2(PM_MESSAGE);
-   Mmsg(buf2, select_recent_version_with_basejob[db_type], 
-        jobids, jobids, jobids, jobids);
+   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,
    Mmsg(buf,
-"SELECT Path.Path, Filename.Name, Temp.FileIndex, Temp.JobId, LStat, MD5 "
- "FROM ( %s ) AS Temp "
- "JOIN Filename ON (Filename.FilenameId = Temp.FilenameId) "
- "JOIN Path ON (Path.PathId = Temp.PathId) "
+"SELECT Path.Path, Filename.Name, T1.FileIndex, T1.JobId, LStat, MarkId, MD5 "
+ "FROM ( %s ) AS T1 "
+ "JOIN Filename ON (Filename.FilenameId = T1.FilenameId) "
+ "JOIN Path ON (Path.PathId = T1.PathId) "
 "WHERE FileIndex > 0 "
 "WHERE FileIndex > 0 "
-"ORDER BY Temp.JobId, FileIndex ASC",/* Return sorted by JobId, */
-                                     /* FileIndex for restore code */ 
+"ORDER BY T1.JobTDate, FileIndex ASC",/* Return sorted by JobTDate */
+                                      /* FileIndex for restore code */ 
         buf2.c_str());
         buf2.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.
-    */
-   Mmsg(buf, uar_sel_files, jobids);
-#endif
+
+   if (!use_md5) {
+      strip_md5(buf.c_str());
+   }
+
+   Dmsg1(100, "q=%s\n", buf.c_str());
 
    return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
 }
 
 
    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, 
  * This procedure gets the base jobid list used by jobids,
  */
 bool db_get_used_base_jobids(JCR *jcr, B_DB *mdb, 
@@ -1147,7 +1176,8 @@ bool db_get_used_base_jobids(JCR *jcr, B_DB *mdb,
    return db_sql_query(mdb, buf.c_str(), db_list_handler, result);
 }
 
    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
  * Full : do nothing
  * Differential : get the last full id
  * Incremental : get the last full + last diff + last incr(s) ids
@@ -1169,19 +1199,10 @@ bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
    utime_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
 
    bstrutime(date, sizeof(date),  StartTime + 1);
    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 */
 
    /* 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,
         edit_uint64(jcr->JobId, jobid),
         edit_uint64(jr->ClientId, clientid),
         date,
@@ -1247,16 +1268,19 @@ bail_out:
    return ret;
 }
 
    return ret;
 }
 
-bool db_get_base_file_list(JCR *jcr, B_DB *mdb,
+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,
                            DB_RESULT_HANDLER *result_handler, void *ctx)
 {
    POOL_MEM buf(PM_MESSAGE);
          
    Mmsg(buf,
- "SELECT Path, Name, FileIndex, JobId, LStat, MD5 "
+ "SELECT Path, Name, FileIndex, JobId, LStat, 0 As MarkId, MD5 "
    "FROM new_basefile%lld ORDER BY JobId, FileIndex ASC",
         (uint64_t) jcr->JobId);
    "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);
 }
 
    return db_sql_query(mdb, buf.c_str(), result_handler, ctx);
 }
 
@@ -1267,9 +1291,10 @@ bool db_get_base_jobid(JCR *jcr, B_DB *mdb, JOB_DBR *jr, JobId_t *jobid)
    db_int64_ctx lctx;
    char date[MAX_TIME_LENGTH];
    bool ret=false;
    db_int64_ctx lctx;
    char date[MAX_TIME_LENGTH];
    bool ret=false;
-   *jobid = 0;
-
 // char clientid[50], filesetid[50];
 // char clientid[50], filesetid[50];
+   *jobid = 0;
+   lctx.count = 0;
+   lctx.value = 0;
 
    StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
    bstrutime(date, sizeof(date),  StartTime + 1);
 
    StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
    bstrutime(date, sizeof(date),  StartTime + 1);
@@ -1304,4 +1329,19 @@ bail_out:
    return ret;
 }
 
    return ret;
 }
 
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */
+/* Get JobIds associated with a volume */
+bool db_get_volume_jobids(JCR *jcr, B_DB *mdb, 
+                         MEDIA_DBR *mr, db_list_ctx *lst)
+{
+   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_POSTGRESQL || HAVE_INGRES || HAVE_DBI */