diff --git a/catalogue/CMakeLists.txt b/catalogue/CMakeLists.txt
index 3cde8545579f9834b2d4527943609d1e5b760664..1e3f20791e90d677d07028b7c736c8ded21786a7 100644
--- a/catalogue/CMakeLists.txt
+++ b/catalogue/CMakeLists.txt
@@ -15,9 +15,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 cmake_minimum_required (VERSION 2.6)
 
-if (OCCI_SUPPORT)
-  include_directories (${ORACLE-INSTANTCLIENT_INCLUDE_DIRS})
-endif (OCCI_SUPPORT)
+include_directories (${ORACLE-INSTANTCLIENT_INCLUDE_DIRS})
 
 set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
 
@@ -37,25 +35,17 @@ set (CATALOGUE_LIB_SRC_FILES
   SqliteCatalogue.cpp
   TapeForWriting.cpp)
 
-if (OCCI_SUPPORT)
-  set (CATALOGUE_LIB_SRC_FILES
-    ${CATALOGUE_LIB_SRC_FILES}
-    CatalogueFactory.cpp
-    OracleCatalogue.cpp)
-else (OCCI_SUPPORT)
-  set (CATALOGUE_LIB_SRC_FILES
-    ${CATALOGUE_LIB_SRC_FILES}
-    CatalogueFactory_OCCI_SUPPORT_OFF.cpp)
-endif (OCCI_SUPPORT)
+set (CATALOGUE_LIB_SRC_FILES
+  ${CATALOGUE_LIB_SRC_FILES}
+  CatalogueFactory.cpp
+  OracleCatalogue.cpp)
 
 add_library (ctacatalogue SHARED
    ${CATALOGUE_LIB_SRC_FILES})
 set_property(TARGET ctacatalogue PROPERTY SOVERSION "${CTA_SOVERSION}")
 set_property(TARGET ctacatalogue PROPERTY   VERSION "${CTA_LIBVERSION}")
 
-if (OCCI_SUPPORT)
-  set_property (TARGET ctacatalogue APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
-endif (OCCI_SUPPORT)
+set_property (TARGET ctacatalogue APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
 
 install (TARGETS ctacatalogue DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
 
@@ -133,9 +123,7 @@ add_executable(cta-catalogue-schema-create
 target_link_libraries (cta-catalogue-schema-create
   ctacatalogue)
 
-if (OCCI_SUPPORT)
-  set_property (TARGET cta-catalogue-schema-create APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
-endif (OCCI_SUPPORT)
+set_property (TARGET cta-catalogue-schema-create APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
 
 install (TARGETS cta-catalogue-schema-create DESTINATION /usr/bin)
 install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/cta-catalogue-schema-create.1cta DESTINATION /usr/share/man/man1)
@@ -148,9 +136,7 @@ add_executable(cta-catalogue-schema-drop
 target_link_libraries (cta-catalogue-schema-drop
   ctacatalogue)
 
-if (OCCI_SUPPORT)
-  set_property (TARGET cta-catalogue-schema-drop APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
-endif (OCCI_SUPPORT)
+set_property (TARGET cta-catalogue-schema-drop APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
 
 install (TARGETS cta-catalogue-schema-drop DESTINATION /usr/bin)
 install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/cta-catalogue-schema-drop.1cta DESTINATION /usr/share/man/man1)
@@ -163,9 +149,7 @@ add_executable(cta-database-poll
 target_link_libraries (cta-database-poll
   ctacatalogue)
 
-if (OCCI_SUPPORT)
-  set_property (TARGET cta-database-poll APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
-endif (OCCI_SUPPORT)
+set_property (TARGET cta-database-poll APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
 
 install (TARGETS cta-database-poll DESTINATION /usr/bin)
 install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/cta-database-poll.1cta DESTINATION /usr/share/man/man1)
@@ -178,9 +162,7 @@ add_executable(cta-catalogue-admin-user-create
 target_link_libraries (cta-catalogue-admin-user-create
   ctacatalogue)
 
-if (OCCI_SUPPORT)
-  set_property (TARGET cta-catalogue-admin-user-create APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
-endif (OCCI_SUPPORT)
+set_property (TARGET cta-catalogue-admin-user-create APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
 
 install (TARGETS cta-catalogue-admin-user-create DESTINATION /usr/bin)
 install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/cta-catalogue-admin-user-create.1cta DESTINATION /usr/share/man/man1)
@@ -193,9 +175,7 @@ add_executable(cta-catalogue-admin-host-create
 target_link_libraries (cta-catalogue-admin-host-create
   ctacatalogue)
 
-if (OCCI_SUPPORT)
-  set_property (TARGET cta-catalogue-admin-host-create APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
-endif (OCCI_SUPPORT)
+set_property (TARGET cta-catalogue-admin-host-create APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
 
 install (TARGETS cta-catalogue-admin-host-create DESTINATION /usr/bin)
 install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/cta-catalogue-admin-host-create.1cta DESTINATION /usr/share/man/man1)
diff --git a/catalogue/CatalogueFactory_OCCI_SUPPORT_OFF.cpp b/catalogue/CatalogueFactory_OCCI_SUPPORT_OFF.cpp
deleted file mode 100644
index 6c0c2895752343e9898f4b960da24ea44730930e..0000000000000000000000000000000000000000
--- a/catalogue/CatalogueFactory_OCCI_SUPPORT_OFF.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * The CERN Tape Archive (CTA) project
- * Copyright (C) 2015  CERN
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * 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
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "catalogue/CatalogueFactory.hpp"
-#include "catalogue/InMemoryCatalogue.hpp"
-#include "catalogue/SqliteCatalogue.hpp"
-#include "common/exception/Exception.hpp"
-#include "common/make_unique.hpp"
-
-namespace cta {
-namespace catalogue {
-
-//------------------------------------------------------------------------------
-// create
-//------------------------------------------------------------------------------
-std::unique_ptr<Catalogue> CatalogueFactory::create(const rdbms::Login &login, const uint64_t nbConns) {
-  try {
-    switch(login.dbType) {
-    case rdbms::Login::DBTYPE_IN_MEMORY:
-      return cta::make_unique<InMemoryCatalogue>(nbConns);
-    case rdbms::Login::DBTYPE_ORACLE:
-      throw exception::Exception("OCCI support disabled at compile time");
-    case rdbms::Login::DBTYPE_SQLITE:
-      return cta::make_unique<SqliteCatalogue>(login.database, nbConns);
-    case rdbms::Login::DBTYPE_NONE:
-      throw exception::Exception("Cannot create a catalogue without a database type");
-    default:
-      {
-        exception::Exception ex;
-        ex.getMessage() << "Unknown database type: value=" << login.dbType;
-        throw ex;
-      }
-    }
-  } catch(exception::Exception &ex) {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
-  }
-}
-
-} // namespace catalogue
-} // namespace cta
diff --git a/catalogue/CatalogueTest.cpp b/catalogue/CatalogueTest.cpp
index fcf5cfcfbe04f4f381d837c988643338cdeeaa7d..3a01724ce89f560b98d3d9c35e4de1e5d924717f 100644
--- a/catalogue/CatalogueTest.cpp
+++ b/catalogue/CatalogueTest.cpp
@@ -21,7 +21,7 @@
 #include "catalogue/CatalogueTest.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/exception/UserError.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
+#include "rdbms/wrapper/ConnFactoryFactory.hpp"
 
 #include <algorithm>
 #include <gtest/gtest.h>
@@ -53,7 +53,7 @@ void cta_catalogue_CatalogueTest::SetUp() {
 
   try {
     const rdbms::Login &login = GetParam()->create();
-    auto connFactory = rdbms::ConnFactoryFactory::create(login);
+    auto connFactory = rdbms::wrapper::ConnFactoryFactory::create(login);
     const uint64_t nbConns = 2;
     const uint64_t nbArchiveFileListingConns = 2;
 
@@ -4528,6 +4528,64 @@ TEST_P(cta_catalogue_CatalogueTest, deleteRequesterGroupMountRule_non_existant)
     exception::UserError);
 }
 
+TEST_P(cta_catalogue_CatalogueTest, prepareForNewFile_no_archive_routes) {
+  using namespace cta;
+
+  ASSERT_TRUE(m_catalogue->getRequesterMountRules().empty());
+
+  const std::string mountPolicyName = "mount_policy";
+  const uint64_t archivePriority = 1;
+  const uint64_t minArchiveRequestAge = 2;
+  const uint64_t retrievePriority = 3;
+  const uint64_t minRetrieveRequestAge = 4;
+  const uint64_t maxDrivesAllowed = 5;
+
+  m_catalogue->createMountPolicy(
+    m_admin,
+    mountPolicyName,
+    archivePriority,
+    minArchiveRequestAge,
+    retrievePriority,
+    minRetrieveRequestAge,
+    maxDrivesAllowed,
+    "Create mount policy");
+
+  const std::string comment = "Create mount rule for requester";
+  const std::string diskInstanceName = "disk_instance_name";
+  const std::string requesterName = "requester_name";
+  m_catalogue->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName, requesterName, comment);
+
+  const std::list<common::dataStructures::RequesterMountRule> rules = m_catalogue->getRequesterMountRules();
+  ASSERT_EQ(1, rules.size());
+
+  const common::dataStructures::RequesterMountRule rule = rules.front();
+
+  ASSERT_EQ(diskInstanceName, rule.diskInstance);
+  ASSERT_EQ(requesterName, rule.name);
+  ASSERT_EQ(mountPolicyName, rule.mountPolicy);
+  ASSERT_EQ(comment, rule.comment);
+  ASSERT_EQ(m_admin.username, rule.creationLog.username);
+  ASSERT_EQ(m_admin.host, rule.creationLog.host);
+  ASSERT_EQ(rule.creationLog, rule.lastModificationLog);
+
+  // Do not create any archive routes
+  ASSERT_TRUE(m_catalogue->getArchiveRoutes().empty());
+
+  common::dataStructures::StorageClass storageClass;
+  storageClass.diskInstance = diskInstanceName;
+  storageClass.name = "storage_class";
+  storageClass.nbCopies = 2;
+  storageClass.comment = "Create storage class";
+  m_catalogue->createStorageClass(m_admin, storageClass);
+
+  common::dataStructures::UserIdentity userIdentity;
+  userIdentity.name = requesterName;
+  userIdentity.group = "group";
+
+  ASSERT_THROW(m_catalogue->prepareForNewFile(storageClass.diskInstance, storageClass.name, userIdentity),
+    exception::UserError);
+}
+
 TEST_P(cta_catalogue_CatalogueTest, prepareForNewFile_requester_mount_rule) {
   using namespace cta;
 
diff --git a/catalogue/CatalogueTest.hpp b/catalogue/CatalogueTest.hpp
index a421ae0a6972a02a05ac9f56353fbe175cd36087..b190b8712082431a119f3938a0947dcc48ca6506 100644
--- a/catalogue/CatalogueTest.hpp
+++ b/catalogue/CatalogueTest.hpp
@@ -22,7 +22,7 @@
 #include "catalogue/CatalogueFactory.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/log/DummyLogger.hpp"
-#include "rdbms/Conn.hpp"
+#include "rdbms/wrapper/Conn.hpp"
 #include "rdbms/LoginFactory.hpp"
 
 #include <gtest/gtest.h>
@@ -48,7 +48,7 @@ protected:
    * A general purpose database connection outside of the m_catalogue object to
    * be used to run tests directly on the underlying "raw" catalogue database.
    */
-  std::unique_ptr<cta::rdbms::Conn> m_conn;
+  std::unique_ptr<cta::rdbms::wrapper::Conn> m_conn;
 
   virtual void SetUp();
 
diff --git a/catalogue/CreateAdminHostCmd.cpp b/catalogue/CreateAdminHostCmd.cpp
index aad0551c81ce48b221577d4598ddebd673bfe19d..e7540c591ded5adba15c028d155953e15d81acb0 100644
--- a/catalogue/CreateAdminHostCmd.cpp
+++ b/catalogue/CreateAdminHostCmd.cpp
@@ -21,7 +21,7 @@
 #include "catalogue/CreateAdminHostCmdLineArgs.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/log/DummyLogger.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
+#include "rdbms/wrapper/ConnFactoryFactory.hpp"
 
 namespace cta {
 namespace catalogue {
diff --git a/catalogue/CreateAdminUserCmd.cpp b/catalogue/CreateAdminUserCmd.cpp
index 8bc5d1c98920520207b21956a48d9644b5baceb1..a0af942d14f2f0a0d2005f758c7e3f900dcaa505 100644
--- a/catalogue/CreateAdminUserCmd.cpp
+++ b/catalogue/CreateAdminUserCmd.cpp
@@ -21,7 +21,7 @@
 #include "catalogue/CreateAdminUserCmdLineArgs.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/log/DummyLogger.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
+#include "rdbms/wrapper/ConnFactoryFactory.hpp"
 
 namespace cta {
 namespace catalogue {
diff --git a/catalogue/CreateSchemaCmd.cpp b/catalogue/CreateSchemaCmd.cpp
index 2e03dab2afdf4a38094eec3d569303c9a7b6adc5..cdd9e046160ba71f79b6b72524568f27e9899361 100644
--- a/catalogue/CreateSchemaCmd.cpp
+++ b/catalogue/CreateSchemaCmd.cpp
@@ -16,14 +16,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "rdbms/ConnFactoryFactory.hpp"
 #include "catalogue/CreateSchemaCmd.hpp"
 #include "catalogue/CreateSchemaCmdLineArgs.hpp"
 #include "catalogue/OracleCatalogueSchema.hpp"
 #include "catalogue/SqliteCatalogueSchema.hpp"
 #include "common/exception/Exception.hpp"
-
-#include <iostream>
+#include "rdbms/ConnPool.hpp"
+#include "rdbms/Login.hpp"
 
 namespace cta {
 namespace catalogue {
@@ -53,10 +52,11 @@ int CreateSchemaCmd::exceptionThrowingMain(const int argc, char *const *const ar
   }
 
   const auto login = rdbms::Login::parseFile(cmdLineArgs.dbConfigPath);
-  auto factory = rdbms::ConnFactoryFactory::create(login);
-  auto conn = factory->create();
+  const uint64_t maxNbConns = 1;
+  rdbms::ConnPool connPool(login, maxNbConns);
+  auto conn = connPool.getConn();;
 
-  const bool ctaCatalogueTableExists = tableExists("CTA_CATALOGUE", *conn);
+  const bool ctaCatalogueTableExists = tableExists("CTA_CATALOGUE", conn);
 
   if(ctaCatalogueTableExists) {
     std::cerr << "Cannot create the database schema because the CTA_CATALOGUE table already exists" << std::endl;
@@ -68,13 +68,13 @@ int CreateSchemaCmd::exceptionThrowingMain(const int argc, char *const *const ar
   case rdbms::Login::DBTYPE_SQLITE:
     {
        SqliteCatalogueSchema schema;
-       conn->executeNonQueries(schema.sql);
+       conn.executeNonQueries(schema.sql);
     }
     break;
   case rdbms::Login::DBTYPE_ORACLE:
     {
       OracleCatalogueSchema schema;
-      conn->executeNonQueries(schema.sql);
+      conn.executeNonQueries(schema.sql);
     }
     break;
   case rdbms::Login::DBTYPE_NONE:
diff --git a/catalogue/DropSchemaCmd.cpp b/catalogue/DropSchemaCmd.cpp
index 1380c7b816e453f82cdc5c3dcfe1962d96833b7d..c698c8bbe8ed028dc580a2fa4f6ae2bb6ad8f78c 100644
--- a/catalogue/DropSchemaCmd.cpp
+++ b/catalogue/DropSchemaCmd.cpp
@@ -22,11 +22,9 @@
 #include "catalogue/DropSchemaCmdLineArgs.hpp"
 #include "catalogue/DropSqliteCatalogueSchema.hpp"
 #include "common/exception/Exception.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
-#include "rdbms/OcciConn.hpp"
+#include "rdbms/ConnPool.hpp"
 
 #include <algorithm>
-#include <rdbms/OcciConn.hpp>
 
 namespace cta {
 namespace catalogue {
@@ -59,45 +57,20 @@ int DropSchemaCmd::exceptionThrowingMain(const int argc, char *const *const argv
   }
 
   const rdbms::Login dbLogin = rdbms::Login::parseFile(cmdLineArgs.dbConfigPath);
-  auto factory = rdbms::ConnFactoryFactory::create(dbLogin);
-  auto conn = factory->create();
+  const uint64_t maxNbConns = 1;
+  rdbms::ConnPool connPool(dbLogin, maxNbConns);
+  auto conn = connPool.getConn();
 
   // Abort if the schema is already dropped
-  switch(dbLogin.dbType) {
-  case rdbms::Login::DBTYPE_IN_MEMORY:
-  case rdbms::Login::DBTYPE_SQLITE:
-    if (conn->getTableNames().empty()) {
-      m_out << "Database contains no tables." << std::endl <<
-        "Assuming the schema has already been dropped." << std::endl;
-      return 0;
-    }
-    break;
-  case rdbms::Login::DBTYPE_ORACLE:
-    {
-      rdbms::OcciConn *const occiConn = dynamic_cast<rdbms::OcciConn *>(conn.get());
-      if(nullptr == occiConn) {
-        throw exception::Exception("Failed to down cast rdbms::conn to rdbms::OcciConn");
-      }
-      if(occiConn->getTableNames().empty() && occiConn->getSequenceNames().empty()) {
-        m_out << "Database contains no tables and no sequences." << std::endl <<
-          "Assuming the schema has already been dropped." << std::endl;
-        return 0;
-      }
-    }
-    break;
-  case rdbms::Login::DBTYPE_NONE:
-    throw exception::Exception("Cannot delete the schema of  catalogue database without a database type");
-  default:
-    {
-      exception::Exception ex;
-      ex.getMessage() << "Unknown database type: value=" << dbLogin.dbType;
-      throw ex;
-    }
+  if(conn.getTableNames().empty() && conn.getSequenceNames().empty()) {
+    m_out << "Database contains no tables and no sequences." << std::endl <<
+      "Assuming the schema has already been dropped." << std::endl;
+    return 0;
   }
 
   if(userConfirmsDropOfSchema(dbLogin)) {
     m_out << "DROPPING the schema of the CTA calalogue database" << std::endl;
-    dropCatalogueSchema(dbLogin.dbType, *conn);
+    dropCatalogueSchema(dbLogin.dbType, conn);
   } else {
     m_out << "Aborting" << std::endl;
   }
@@ -186,7 +159,7 @@ void DropSchemaCmd::dropDatabaseTables(rdbms::Conn &conn, const std::list<std::s
     for(auto tableToDrop : tablesToDrop) {
       const bool tableToDropIsInDb = tablesInDb.end() != std::find(tablesInDb.begin(), tablesInDb.end(), tableToDrop);
       if(tableToDropIsInDb) {
-        conn.executeNonQuery(std::string("DROP TABLE ") + tableToDrop, rdbms::Stmt::AutocommitMode::ON);
+        conn.executeNonQuery(std::string("DROP TABLE ") + tableToDrop, rdbms::AutocommitMode::ON);
         m_out << "Dropped table " << tableToDrop << std::endl;
       }
     }
@@ -220,8 +193,7 @@ void DropSchemaCmd::dropOracleCatalogueSchema(rdbms::Conn &conn) {
     dropDatabaseTables(conn, tablesToDrop);
 
     std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ"};
-    rdbms::OcciConn &occiConn = dynamic_cast<rdbms::OcciConn &>(conn);
-    dropDatabaseSequences(occiConn, sequencesToDrop);
+    dropDatabaseSequences(conn, sequencesToDrop);
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
   }
@@ -230,14 +202,14 @@ void DropSchemaCmd::dropOracleCatalogueSchema(rdbms::Conn &conn) {
 //------------------------------------------------------------------------------
 // dropDatabaseSequences
 //------------------------------------------------------------------------------
-void DropSchemaCmd::dropDatabaseSequences(rdbms::OcciConn &conn, const std::list<std::string> &sequencesToDrop) {
+void DropSchemaCmd::dropDatabaseSequences(rdbms::Conn &conn, const std::list<std::string> &sequencesToDrop) {
   try {
     std::list<std::string> sequencesInDb = conn.getSequenceNames();
     for(auto sequenceToDrop : sequencesToDrop) {
       const bool sequenceToDropIsInDb = sequencesInDb.end() != std::find(sequencesInDb.begin(), sequencesInDb.end(),
         sequenceToDrop);
       if(sequenceToDropIsInDb) {
-        conn.executeNonQuery(std::string("DROP SEQUENCE ") + sequenceToDrop, rdbms::Stmt::AutocommitMode::ON);
+        conn.executeNonQuery(std::string("DROP SEQUENCE ") + sequenceToDrop, rdbms::AutocommitMode::ON);
         m_out << "Dropped sequence " << sequenceToDrop << std::endl;
       }
     }
diff --git a/catalogue/DropSchemaCmd.hpp b/catalogue/DropSchemaCmd.hpp
index 760aa3b3dc0fca5383eee65c9b70bef056e22d15..a2e1c669279ce6729f5d4d676659cca792eefb72 100644
--- a/catalogue/DropSchemaCmd.hpp
+++ b/catalogue/DropSchemaCmd.hpp
@@ -22,7 +22,6 @@
 #include "catalogue/CmdLineTool.hpp"
 #include "rdbms/Conn.hpp"
 #include "rdbms/Login.hpp"
-#include "rdbms/OcciConn.hpp"
 
 namespace cta {
 namespace catalogue {
@@ -109,9 +108,10 @@ private:
   /**
    * Drops the database sequences with the specified names.
    *
+   * @param conn The database connection.
    * @param seqeuncesToDrop The names of the database sequences to be dropped.
    */
-  void dropDatabaseSequences(rdbms::OcciConn &conn, const std::list<std::string> &sequencesToDrop);
+  void dropDatabaseSequences(rdbms::Conn &conn, const std::list<std::string> &sequencesToDrop);
 
 }; // class DropSchemaCmd
 
diff --git a/catalogue/InMemoryCatalogue.cpp b/catalogue/InMemoryCatalogue.cpp
index a88201c16d9fd366da2037168523da84126072df..69eeb195103a9fff734d880278768a63f91c97d6 100644
--- a/catalogue/InMemoryCatalogue.cpp
+++ b/catalogue/InMemoryCatalogue.cpp
@@ -17,9 +17,6 @@
  */
 
 #include "catalogue/InMemoryCatalogue.hpp"
-#include "catalogue/SqliteCatalogueSchema.hpp"
-#include "rdbms/SqliteConn.hpp"
-#include "rdbms/SqliteConnFactory.hpp"
 
 namespace cta {
 namespace catalogue {
diff --git a/catalogue/OracleCatalogue.cpp b/catalogue/OracleCatalogue.cpp
index 8f6627776b27caca7f1ca8b5e1dc12379bd0d273..308baaea692a8ca488bdffec41bd9d66736218c1 100644
--- a/catalogue/OracleCatalogue.cpp
+++ b/catalogue/OracleCatalogue.cpp
@@ -25,14 +25,90 @@
 #include "common/Timer.hpp"
 #include "common/utils/utils.hpp"
 #include "rdbms/AutoRollback.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
-#include "rdbms/OcciStmt.hpp"
+#include "rdbms/wrapper/OcciColumn.hpp"
+#include "rdbms/wrapper/OcciStmt.hpp"
 
 #include <string.h>
 
 namespace cta {
 namespace catalogue {
 
+namespace {
+  /**
+   * Structure used to assemble a batch of rows to insert into the TAPE_FILE
+   * table.
+   */
+  struct TapeFileBatch {
+    size_t nbRows;
+    rdbms::wrapper::OcciColumn vid;
+    rdbms::wrapper::OcciColumn fSeq;
+    rdbms::wrapper::OcciColumn blockId;
+    rdbms::wrapper::OcciColumn compressedSize;
+    rdbms::wrapper::OcciColumn copyNb;
+    rdbms::wrapper::OcciColumn creationTime;
+    rdbms::wrapper::OcciColumn archiveFileId;
+
+    /**
+     * Constructor.
+     *
+     * @param nbRowsValue  The Number of rows to be inserted.
+     */
+    TapeFileBatch(const size_t nbRowsValue):
+      nbRows(nbRowsValue),
+      vid("VID", nbRows),
+      fSeq("FSEQ", nbRows),
+      blockId("BLOCK_ID", nbRows),
+      compressedSize("COMPRESSED_SIZE_IN_BYTES", nbRows),
+      copyNb("COPY_NB", nbRows),
+      creationTime("CREATION_TIME", nbRows),
+      archiveFileId("ARCHIVE_FILE_ID", nbRows) {
+    }
+  }; // struct TapeFileBatch
+
+  /**
+   * Structure used to assemble a batch of rows to insert into the ARCHIVE_FILE
+   * table.
+   */
+  struct ArchiveFileBatch {
+    size_t nbRows;
+    rdbms::wrapper::OcciColumn archiveFileId;
+    rdbms::wrapper::OcciColumn diskInstance;
+    rdbms::wrapper::OcciColumn diskFileId;
+    rdbms::wrapper::OcciColumn diskFilePath;
+    rdbms::wrapper::OcciColumn diskFileUser;
+    rdbms::wrapper::OcciColumn diskFileGroup;
+    rdbms::wrapper::OcciColumn diskFileRecoveryBlob;
+    rdbms::wrapper::OcciColumn size;
+    rdbms::wrapper::OcciColumn checksumType;
+    rdbms::wrapper::OcciColumn checksumValue;
+    rdbms::wrapper::OcciColumn storageClassName;
+    rdbms::wrapper::OcciColumn creationTime;
+    rdbms::wrapper::OcciColumn reconciliationTime;
+
+    /**
+     * Constructor.
+     *
+     * @param nbRowsValue  The Number of rows to be inserted.
+     */
+    ArchiveFileBatch(const size_t nbRowsValue):
+      nbRows(nbRowsValue),
+      archiveFileId("ARCHIVE_FILE_ID", nbRows),
+      diskInstance("DISK_INSTANCE_NAME", nbRows),
+      diskFileId("DISK_FILE_ID", nbRows),
+      diskFilePath("DISK_FILE_PATH", nbRows),
+      diskFileUser("DISK_FILE_USER", nbRows),
+      diskFileGroup("DISK_FILE_GROUP", nbRows),
+      diskFileRecoveryBlob("DISK_FILE_RECOVERY_BLOB", nbRows),
+      size("SIZE_IN_BYTES", nbRows),
+      checksumType("CHECKSUM_TYPE", nbRows),
+      checksumValue("CHECKSUM_VALUE", nbRows),
+      storageClassName("STORAGE_CLASS_NAME", nbRows),
+      creationTime("CREATION_TIME", nbRows),
+      reconciliationTime("RECONCILIATION_TIME", nbRows) {
+    }
+  }; // struct ArchiveFileBatch
+} // anonymous namespace
+
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
@@ -45,7 +121,7 @@ OracleCatalogue::OracleCatalogue(
   const uint64_t nbArchiveFileListingConns):
   RdbmsCatalogue(
     log,
-    rdbms::ConnFactoryFactory::create(rdbms::Login(rdbms::Login::DBTYPE_ORACLE, username, password, database)),
+    rdbms::Login(rdbms::Login::DBTYPE_ORACLE, username, password, database),
     nbConns,
     nbArchiveFileListingConns) {
 
@@ -94,11 +170,11 @@ void OracleCatalogue::deleteArchiveFile(const std::string &diskInstanceName, con
     utils::Timer t;
     auto conn = m_connPool.getConn();
     const auto getConnTime = t.secs(utils::Timer::resetCounter);
-    auto selectStmt = conn.createStmt(selectSql, rdbms::Stmt::AutocommitMode::OFF);
+    auto selectStmt = conn.createStmt(selectSql, rdbms::AutocommitMode::OFF);
     const auto createStmtTime = t.secs();
-    selectStmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
+    selectStmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
     t.reset();
-    rdbms::Rset selectRset = selectStmt->executeQuery();
+    rdbms::Rset selectRset = selectStmt.executeQuery();
     const auto selectFromArchiveFileTime = t.secs();
     std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile;
     while(selectRset.next()) {
@@ -189,17 +265,17 @@ void OracleCatalogue::deleteArchiveFile(const std::string &diskInstanceName, con
     t.reset();
     {
       const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
-      stmt->executeNonQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
+      stmt.executeNonQuery();
     }
     const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter);
 
     {
       const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
-      stmt->executeNonQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
+      stmt.executeNonQuery();
     }
     const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter);
 
@@ -284,12 +360,12 @@ void OracleCatalogue::deleteArchiveFileByDiskFileId(const std::string &diskInsta
     utils::Timer t;
     auto conn = m_connPool.getConn();
     const auto getConnTime = t.secs(utils::Timer::resetCounter);
-    auto selectStmt = conn.createStmt(selectSql, rdbms::Stmt::AutocommitMode::OFF);
+    auto selectStmt = conn.createStmt(selectSql, rdbms::AutocommitMode::OFF);
     const auto createStmtTime = t.secs();
-    selectStmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    selectStmt->bindString(":DISK_FILE_ID", diskFileId);
+    selectStmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    selectStmt.bindString(":DISK_FILE_ID", diskFileId);
     t.reset();
-    rdbms::Rset selectRset = selectStmt->executeQuery();
+    rdbms::Rset selectRset = selectStmt.executeQuery();
     const auto selectFromArchiveFileTime = t.secs();
     std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile;
     while(selectRset.next()) {
@@ -339,17 +415,17 @@ void OracleCatalogue::deleteArchiveFileByDiskFileId(const std::string &diskInsta
     t.reset();
     {
       const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFile->archiveFileID);
-      stmt->executeNonQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFile->archiveFileID);
+      stmt.executeNonQuery();
     }
     const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter);
 
     {
       const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFile->archiveFileID);
-      stmt->executeNonQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFile->archiveFileID);
+      stmt.executeNonQuery();
     }
     const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter);
 
@@ -399,15 +475,15 @@ void OracleCatalogue::deleteArchiveFileByDiskFileId(const std::string &diskInsta
 //------------------------------------------------------------------------------
 // getNextArchiveFileId
 //------------------------------------------------------------------------------
-uint64_t OracleCatalogue::getNextArchiveFileId(rdbms::PooledConn &conn) {
+uint64_t OracleCatalogue::getNextArchiveFileId(rdbms::Conn &conn) {
   try {
     const char *const sql =
       "SELECT "
         "ARCHIVE_FILE_ID_SEQ.NEXTVAL AS ARCHIVE_FILE_ID "
       "FROM "
         "DUAL";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     if (!rset.next()) {
       throw exception::Exception(std::string("Result set is unexpectedly empty"));
     }
@@ -421,7 +497,7 @@ uint64_t OracleCatalogue::getNextArchiveFileId(rdbms::PooledConn &conn) {
 //------------------------------------------------------------------------------
 // selectTapeForUpdate
 //------------------------------------------------------------------------------
-common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(rdbms::PooledConn &conn, const std::string &vid) {
+common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) {
   try {
     const char *const sql =
       "SELECT "
@@ -459,9 +535,9 @@ common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(rdbms::PooledC
       "WHERE "
         "VID = :VID "
       "FOR UPDATE";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":VID", vid);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":VID", vid);
+    auto rset = stmt.executeQuery();
     if (!rset.next()) {
       throw exception::Exception(std::string("The tape with VID " + vid + " does not exist"));
     }
@@ -568,10 +644,10 @@ void OracleCatalogue::filesWrittenToTape(const std::set<TapeFileWritten> &events
     auto lastEventItor = events.cend();
     lastEventItor--;
     const TapeFileWritten &lastEvent = *lastEventItor;
-    updateTape(conn, rdbms::Stmt::AutocommitMode::OFF, lastEvent.vid, lastEvent.fSeq, totalCompressedBytesWritten,
+    updateTape(conn, rdbms::AutocommitMode::OFF, lastEvent.vid, lastEvent.fSeq, totalCompressedBytesWritten,
       lastEvent.tapeDrive);
 
-    idempotentBatchInsertArchiveFiles(conn, rdbms::Stmt::AutocommitMode::OFF, events);
+    idempotentBatchInsertArchiveFiles(conn, rdbms::AutocommitMode::OFF, events);
 
     // Store the value of each field
     i = 0;
@@ -603,8 +679,8 @@ void OracleCatalogue::filesWrittenToTape(const std::set<TapeFileWritten> &events
         ":COPY_NB,"
         ":CREATION_TIME,"
         ":ARCHIVE_FILE_ID)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    rdbms::OcciStmt &occiStmt = dynamic_cast<rdbms::OcciStmt &>(*stmt);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    rdbms::wrapper::OcciStmt &occiStmt = dynamic_cast<rdbms::wrapper::OcciStmt &>(stmt.getStmt());
     occiStmt.setColumn(tapeFileBatch.vid);
     occiStmt.setColumn(tapeFileBatch.fSeq);
     occiStmt.setColumn(tapeFileBatch.blockId);
@@ -626,8 +702,8 @@ void OracleCatalogue::filesWrittenToTape(const std::set<TapeFileWritten> &events
 //------------------------------------------------------------------------------
 // idempotentBatchInsertArchiveFiles
 //------------------------------------------------------------------------------
-void OracleCatalogue::idempotentBatchInsertArchiveFiles(rdbms::PooledConn &conn,
-  const rdbms::Stmt::AutocommitMode autocommitMode, const std::set<TapeFileWritten> &events) {
+void OracleCatalogue::idempotentBatchInsertArchiveFiles(rdbms::Conn &conn,
+  const rdbms::AutocommitMode autocommitMode, const std::set<TapeFileWritten> &events) {
   try {
     ArchiveFileBatch archiveFileBatch(events.size());
     const time_t now = time(nullptr);
@@ -701,7 +777,7 @@ void OracleCatalogue::idempotentBatchInsertArchiveFiles(rdbms::PooledConn &conn,
         ":CREATION_TIME,"
         ":RECONCILIATION_TIME)";
     auto stmt = conn.createStmt(sql, autocommitMode);
-    rdbms::OcciStmt &occiStmt = dynamic_cast<rdbms::OcciStmt &>(*stmt);
+    rdbms::wrapper::OcciStmt &occiStmt = dynamic_cast<rdbms::wrapper::OcciStmt &>(stmt.getStmt());
     occiStmt->setBatchErrorMode(true);
 
     occiStmt.setColumn(archiveFileBatch.archiveFileId);
diff --git a/catalogue/OracleCatalogue.hpp b/catalogue/OracleCatalogue.hpp
index b9587cd54b8b5dc436047483f8065ee373985190..99a404752a8cb398e46e9fb007840298676dc9ce 100644
--- a/catalogue/OracleCatalogue.hpp
+++ b/catalogue/OracleCatalogue.hpp
@@ -19,8 +19,7 @@
 #pragma once
 
 #include "catalogue/RdbmsCatalogue.hpp"
-#include "rdbms/OcciColumn.hpp"
-#include "rdbms/PooledConn.hpp"
+#include "rdbms/Conn.hpp"
 
 #include <occi.h>
 #include <string.h>
@@ -117,7 +116,7 @@ public:
    * @return A unique archive ID that can be used by a new archive file within
    * the catalogue.
    */
-  uint64_t getNextArchiveFileId(rdbms::PooledConn &conn) override;
+  uint64_t getNextArchiveFileId(rdbms::Conn &conn) override;
 
   /**
    * Notifies the catalogue that the specified files have been written to tape.
@@ -134,81 +133,7 @@ private:
    * @param conn The database connection.
    * @param vid The volume identifier of the tape.
    */
-  common::dataStructures::Tape selectTapeForUpdate(rdbms::PooledConn &conn, const std::string &vid);
-
-  /**
-   * Structure used to assemble a batch of rows to insert into the TAPE_FILE
-   * table.
-   */
-  struct TapeFileBatch {
-    size_t nbRows;
-    rdbms::OcciColumn vid;
-    rdbms::OcciColumn fSeq;
-    rdbms::OcciColumn blockId;
-    rdbms::OcciColumn compressedSize;
-    rdbms::OcciColumn copyNb;
-    rdbms::OcciColumn creationTime;
-    rdbms::OcciColumn archiveFileId;
-
-    /**
-     * Constructor.
-     *
-     * @param nbRowsValue  The Number of rows to be inserted.
-     */
-    TapeFileBatch(const size_t nbRowsValue):
-      nbRows(nbRowsValue),
-      vid("VID", nbRows),
-      fSeq("FSEQ", nbRows),
-      blockId("BLOCK_ID", nbRows),
-      compressedSize("COMPRESSED_SIZE_IN_BYTES", nbRows),
-      copyNb("COPY_NB", nbRows),
-      creationTime("CREATION_TIME", nbRows),
-      archiveFileId("ARCHIVE_FILE_ID", nbRows) {
-    }
-  }; // struct TapeFileBatch
-
-  /**
-   * Structure used to assemble a batch of rows to insert into the ARCHIVE_FILE
-   * table.
-   */
-  struct ArchiveFileBatch {
-    size_t nbRows;
-    rdbms::OcciColumn archiveFileId;
-    rdbms::OcciColumn diskInstance;
-    rdbms::OcciColumn diskFileId;
-    rdbms::OcciColumn diskFilePath;
-    rdbms::OcciColumn diskFileUser;
-    rdbms::OcciColumn diskFileGroup;
-    rdbms::OcciColumn diskFileRecoveryBlob;
-    rdbms::OcciColumn size;
-    rdbms::OcciColumn checksumType;
-    rdbms::OcciColumn checksumValue;
-    rdbms::OcciColumn storageClassName;
-    rdbms::OcciColumn creationTime;
-    rdbms::OcciColumn reconciliationTime;
-
-    /**
-     * Constructor.
-     *
-     * @param nbRowsValue  The Number of rows to be inserted.
-     */
-    ArchiveFileBatch(const size_t nbRowsValue):
-      nbRows(nbRowsValue),
-      archiveFileId("ARCHIVE_FILE_ID", nbRows),
-      diskInstance("DISK_INSTANCE_NAME", nbRows),
-      diskFileId("DISK_FILE_ID", nbRows),
-      diskFilePath("DISK_FILE_PATH", nbRows),
-      diskFileUser("DISK_FILE_USER", nbRows),
-      diskFileGroup("DISK_FILE_GROUP", nbRows),
-      diskFileRecoveryBlob("DISK_FILE_RECOVERY_BLOB", nbRows),
-      size("SIZE_IN_BYTES", nbRows),
-      checksumType("CHECKSUM_TYPE", nbRows),
-      checksumValue("CHECKSUM_VALUE", nbRows),
-      storageClassName("STORAGE_CLASS_NAME", nbRows),
-      creationTime("CREATION_TIME", nbRows),
-      reconciliationTime("RECONCILIATION_TIME", nbRows) {
-    }
-  }; // struct ArchiveFileBatch
+  common::dataStructures::Tape selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid);
 
   /**
    * Batch inserts rows into the ARCHIVE_FILE table that correspond to the
@@ -227,7 +152,7 @@ private:
    * @param autocommitMode The autocommit mode of the SQL insert statement.
    * @param events The tape file written events.
    */
-  void idempotentBatchInsertArchiveFiles(rdbms::PooledConn &conn, const rdbms::Stmt::AutocommitMode autocommitMode,
+  void idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, const rdbms::AutocommitMode autocommitMode,
     const std::set<TapeFileWritten> &events);
 
 }; // class OracleCatalogue
diff --git a/catalogue/PollDatabaseCmd.cpp b/catalogue/PollDatabaseCmd.cpp
index bd680a770cfe6dbed7ee3950c004c5ec183ce573..5f796a6f404fdfd54adeb542b09058116c4f34f8 100644
--- a/catalogue/PollDatabaseCmd.cpp
+++ b/catalogue/PollDatabaseCmd.cpp
@@ -19,7 +19,6 @@
 #include "catalogue/CatalogueFactory.hpp"
 #include "catalogue/PollDatabaseCmd.hpp"
 #include "catalogue/PollDatabaseCmdLineArgs.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
 #include "rdbms/ConnPool.hpp"
 
 #include <unistd.h>
@@ -52,9 +51,8 @@ int PollDatabaseCmd::exceptionThrowingMain(const int argc, char *const *const ar
   }
 
   const auto dbLogin = rdbms::Login::parseFile(cmdLineArgs.dbConfigPath);
-  auto factory = rdbms::ConnFactoryFactory::create(dbLogin); 
   const uint64_t nbConns = 2;
-  rdbms::ConnPool connPool(*factory, nbConns);
+  rdbms::ConnPool connPool(dbLogin, nbConns);
 
   uint32_t elapsedSeconds = 0;
   for(uint32_t i = 0; i < cmdLineArgs.numberOfSecondsToKeepPolling; i++) {
diff --git a/catalogue/RdbmsArchiveFileItorImpl.cpp b/catalogue/RdbmsArchiveFileItorImpl.cpp
index 61cec15416ffe9cb4c46b2c16d903da6b48bcb8f..03516f2c0ba97fed59fb0a2b4a8d45ea6e0462e9 100644
--- a/catalogue/RdbmsArchiveFileItorImpl.cpp
+++ b/catalogue/RdbmsArchiveFileItorImpl.cpp
@@ -198,38 +198,38 @@ RdbmsArchiveFileItorImpl::RdbmsArchiveFileItorImpl(
     }
 
     auto conn = connPool.getConn();
-    m_stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    m_stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
     if(searchCriteria.archiveFileId) {
-      m_stmt->bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value());
+      m_stmt.bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value());
     }
     if(searchCriteria.diskInstance) {
-      m_stmt->bindString(":DISK_INSTANCE_NAME", searchCriteria.diskInstance.value());
+      m_stmt.bindString(":DISK_INSTANCE_NAME", searchCriteria.diskInstance.value());
     }
     if(searchCriteria.diskFileId) {
-      m_stmt->bindString(":DISK_FILE_ID", searchCriteria.diskFileId.value());
+      m_stmt.bindString(":DISK_FILE_ID", searchCriteria.diskFileId.value());
     }
     if(searchCriteria.diskFilePath) {
-      m_stmt->bindString(":DISK_FILE_PATH", searchCriteria.diskFilePath.value());
+      m_stmt.bindString(":DISK_FILE_PATH", searchCriteria.diskFilePath.value());
     }
     if(searchCriteria.diskFileUser) {
-      m_stmt->bindString(":DISK_FILE_USER", searchCriteria.diskFileUser.value());
+      m_stmt.bindString(":DISK_FILE_USER", searchCriteria.diskFileUser.value());
     }
     if(searchCriteria.diskFileGroup) {
-      m_stmt->bindString(":DISK_FILE_GROUP", searchCriteria.diskFileGroup.value());
+      m_stmt.bindString(":DISK_FILE_GROUP", searchCriteria.diskFileGroup.value());
     }
     if(searchCriteria.storageClass) {
-      m_stmt->bindString(":STORAGE_CLASS_NAME", searchCriteria.storageClass.value());
+      m_stmt.bindString(":STORAGE_CLASS_NAME", searchCriteria.storageClass.value());
     }
     if(searchCriteria.vid) {
-      m_stmt->bindString(":VID", searchCriteria.vid.value());
+      m_stmt.bindString(":VID", searchCriteria.vid.value());
     }
     if(searchCriteria.tapeFileCopyNb) {
-      m_stmt->bindUint64(":TAPE_FILE_COPY_NB", searchCriteria.tapeFileCopyNb.value());
+      m_stmt.bindUint64(":TAPE_FILE_COPY_NB", searchCriteria.tapeFileCopyNb.value());
     }
     if(searchCriteria.tapePool) {
-      m_stmt->bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value());
+      m_stmt.bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value());
     }
-    m_rset = m_stmt->executeQuery();
+    m_rset = m_stmt.executeQuery();
 
     m_rsetIsEmpty = !m_rset.next();
   } catch(exception::Exception &ex) {
diff --git a/catalogue/RdbmsArchiveFileItorImpl.hpp b/catalogue/RdbmsArchiveFileItorImpl.hpp
index 059dbc038fc26fd80ed5d146e6ed99f4d53e85e4..decca68918438ec6c40ad8ca3184bc50e7f3af9f 100644
--- a/catalogue/RdbmsArchiveFileItorImpl.hpp
+++ b/catalogue/RdbmsArchiveFileItorImpl.hpp
@@ -23,8 +23,8 @@
 #include "catalogue/TapeFileSearchCriteria.hpp"
 #include "common/log/Logger.hpp"
 #include "rdbms/ConnPool.hpp"
-#include "rdbms/Rset.hpp"
 #include "rdbms/Stmt.hpp"
+#include "rdbms/Rset.hpp"
 
 namespace cta {
 namespace catalogue {
@@ -97,7 +97,7 @@ private:
   /**
    * The database statement.
    */
-  std::unique_ptr<rdbms::Stmt> m_stmt;
+  rdbms::Stmt m_stmt;
 
   /**
    * The result set of archive files that is to be iterated over.
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index 23e34822911ee2198a626dc66b8c18ff9c1c56eb..39415e5cc38048cadfcd2f4df3b861df856d6901 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -41,13 +41,12 @@ namespace catalogue {
 //------------------------------------------------------------------------------
 RdbmsCatalogue::RdbmsCatalogue(
   log::Logger &log,
-  std::unique_ptr<rdbms::ConnFactory> connFactory,
+  const rdbms::Login &login,
   const uint64_t nbConns,
   const uint64_t nbArchiveFileListingConns):
   Catalogue(log),
-  m_connFactory(std::move(connFactory)),
-  m_connPool(*m_connFactory, nbConns),
-  m_archiveFileListingConnPool(*m_connFactory, nbArchiveFileListingConns) {
+  m_connPool(login, nbConns),
+  m_archiveFileListingConnPool(login, nbArchiveFileListingConns) {
 }
 
 //------------------------------------------------------------------------------
@@ -95,21 +94,21 @@ void RdbmsCatalogue::createAdminUser(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":ADMIN_USER_NAME", username);
+    stmt.bindString(":ADMIN_USER_NAME", username);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch (exception::Exception &ex) {
@@ -120,7 +119,7 @@ void RdbmsCatalogue::createAdminUser(
 //------------------------------------------------------------------------------
 // adminUserExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::adminUserExists(rdbms::PooledConn &conn, const std::string adminUsername) const {
+bool RdbmsCatalogue::adminUserExists(rdbms::Conn &conn, const std::string adminUsername) const {
   try {
     const char *const sql =
       "SELECT "
@@ -129,9 +128,9 @@ bool RdbmsCatalogue::adminUserExists(rdbms::PooledConn &conn, const std::string
         "ADMIN_USER "
       "WHERE "
         "ADMIN_USER_NAME = :ADMIN_USER_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":ADMIN_USER_NAME", adminUsername);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":ADMIN_USER_NAME", adminUsername);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -145,11 +144,11 @@ void RdbmsCatalogue::deleteAdminUser(const std::string &username) {
   try {
     const char *const sql = "DELETE FROM ADMIN_USER WHERE ADMIN_USER_NAME = :ADMIN_USER_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":ADMIN_USER_NAME", username);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":ADMIN_USER_NAME", username);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete admin-user ") + username + " because they do not exist");
     }
   } catch(exception::UserError &) {
@@ -183,8 +182,8 @@ std::list<common::dataStructures::AdminUser> RdbmsCatalogue::getAdminUsers() con
       "ORDER BY "
         "ADMIN_USER_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       common::dataStructures::AdminUser admin;
 
@@ -222,15 +221,15 @@ void RdbmsCatalogue::modifyAdminUserComment(const common::dataStructures::Securi
       "WHERE "
         "ADMIN_USER_NAME = :ADMIN_USER_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":ADMIN_USER_NAME", username);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":ADMIN_USER_NAME", username);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify admin user ") + username + " because they do not exist");
     }
   } catch(exception::UserError &) {
@@ -279,21 +278,21 @@ void RdbmsCatalogue::createAdminHost(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":ADMIN_HOST_NAME", hostName);
+    stmt.bindString(":ADMIN_HOST_NAME", hostName);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch (exception::Exception &ex) {
@@ -304,7 +303,7 @@ void RdbmsCatalogue::createAdminHost(
 //------------------------------------------------------------------------------
 // adminHostExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::adminHostExists(rdbms::PooledConn &conn, const std::string adminHost) const {
+bool RdbmsCatalogue::adminHostExists(rdbms::Conn &conn, const std::string adminHost) const {
   try {
     const char *const sql =
       "SELECT "
@@ -313,9 +312,9 @@ bool RdbmsCatalogue::adminHostExists(rdbms::PooledConn &conn, const std::string
         "ADMIN_HOST "
       "WHERE "
         "ADMIN_HOST_NAME = :ADMIN_HOST_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":ADMIN_HOST_NAME", adminHost);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":ADMIN_HOST_NAME", adminHost);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -329,11 +328,11 @@ void RdbmsCatalogue::deleteAdminHost(const std::string &hostName) {
   try {
     const char *const sql = "DELETE FROM ADMIN_HOST WHERE ADMIN_HOST_NAME = :ADMIN_HOST_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":ADMIN_HOST_NAME", hostName);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":ADMIN_HOST_NAME", hostName);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete admin-host ") + hostName + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -367,8 +366,8 @@ std::list<common::dataStructures::AdminHost> RdbmsCatalogue::getAdminHosts() con
       "ORDER BY "
         "ADMIN_HOST_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       common::dataStructures::AdminHost host;
 
@@ -406,15 +405,15 @@ void RdbmsCatalogue::modifyAdminHostComment(const common::dataStructures::Securi
       "WHERE "
         "ADMIN_HOST_NAME = :ADMIN_HOST_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":ADMIN_HOST_NAME", hostName);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":ADMIN_HOST_NAME", hostName);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify admin host ") + hostName + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -466,23 +465,23 @@ void RdbmsCatalogue::createStorageClass(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":DISK_INSTANCE_NAME", storageClass.diskInstance);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClass.name);
-    stmt->bindUint64(":NB_COPIES", storageClass.nbCopies);
+    stmt.bindString(":DISK_INSTANCE_NAME", storageClass.diskInstance);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClass.name);
+    stmt.bindUint64(":NB_COPIES", storageClass.nbCopies);
 
-    stmt->bindString(":USER_COMMENT", storageClass.comment);
+    stmt.bindString(":USER_COMMENT", storageClass.comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch (exception::Exception &ex) {
@@ -493,7 +492,7 @@ void RdbmsCatalogue::createStorageClass(
 //------------------------------------------------------------------------------
 // storageClassExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::storageClassExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+bool RdbmsCatalogue::storageClassExists(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &storageClassName) const {
   try {
     const char *const sql =
@@ -505,10 +504,10 @@ bool RdbmsCatalogue::storageClassExists(rdbms::PooledConn &conn, const std::stri
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -527,13 +526,13 @@ void RdbmsCatalogue::deleteStorageClass(const std::string &diskInstanceName, con
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql,rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql,rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
 
-    stmt->executeNonQuery();
-    if(0 == stmt->getNbAffectedRows()) {
+    stmt.executeNonQuery();
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete storage-class ") + diskInstanceName + ":" +
         storageClassName + " because it does not exist");
     }
@@ -571,8 +570,8 @@ std::list<common::dataStructures::StorageClass>
       "ORDER BY "
         "DISK_INSTANCE_NAME, STORAGE_CLASS_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       common::dataStructures::StorageClass storageClass;
 
@@ -613,16 +612,16 @@ void RdbmsCatalogue::modifyStorageClassNbCopies(const common::dataStructures::Se
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":NB_COPIES", nbCopies);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":DISK_INSTANCE_NAME", instanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindUint64(":NB_COPIES", nbCopies);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify storage class ") + instanceName + ":" + name +
         " because it does not exist");
     }
@@ -650,16 +649,16 @@ void RdbmsCatalogue::modifyStorageClassComment(const common::dataStructures::Sec
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":DISK_INSTANCE_NAME", instanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify storage class ") + instanceName + ":" + name +
         " because it does not exist");
     }
@@ -716,23 +715,23 @@ void RdbmsCatalogue::createTapePool(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":TAPE_POOL_NAME", name);
-    stmt->bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes);
-    stmt->bindBool(":IS_ENCRYPTED", encryptionValue);
+    stmt.bindString(":TAPE_POOL_NAME", name);
+    stmt.bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes);
+    stmt.bindBool(":IS_ENCRYPTED", encryptionValue);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch(exception::Exception &ex) {
@@ -755,7 +754,7 @@ bool RdbmsCatalogue::tapePoolExists(const std::string &tapePoolName) const {
 //------------------------------------------------------------------------------
 // tapePoolExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::tapePoolExists(rdbms::PooledConn &conn, const std::string &tapePoolName) const {
+bool RdbmsCatalogue::tapePoolExists(rdbms::Conn &conn, const std::string &tapePoolName) const {
   try {
     const char *const sql =
       "SELECT "
@@ -764,9 +763,9 @@ bool RdbmsCatalogue::tapePoolExists(rdbms::PooledConn &conn, const std::string &
         "TAPE_POOL "
       "WHERE "
         "TAPE_POOL_NAME = :TAPE_POOL_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":TAPE_POOL_NAME", tapePoolName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -776,7 +775,7 @@ bool RdbmsCatalogue::tapePoolExists(rdbms::PooledConn &conn, const std::string &
 //------------------------------------------------------------------------------
 // archiveFileExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::archiveFileIdExists(rdbms::PooledConn &conn, const uint64_t archiveFileId) const {
+bool RdbmsCatalogue::archiveFileIdExists(rdbms::Conn &conn, const uint64_t archiveFileId) const {
   try {
     const char *const sql =
       "SELECT "
@@ -785,9 +784,9 @@ bool RdbmsCatalogue::archiveFileIdExists(rdbms::PooledConn &conn, const uint64_t
         "ARCHIVE_FILE "
       "WHERE "
         "ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -797,7 +796,7 @@ bool RdbmsCatalogue::archiveFileIdExists(rdbms::PooledConn &conn, const uint64_t
 //------------------------------------------------------------------------------
 // diskFileIdExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::diskFileIdExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+bool RdbmsCatalogue::diskFileIdExists(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &diskFileId) const {
   try {
     const char *const sql =
@@ -809,10 +808,10 @@ bool RdbmsCatalogue::diskFileIdExists(rdbms::PooledConn &conn, const std::string
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "DISK_FILE_ID = :DISK_FILE_ID";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":DISK_FILE_ID", diskFileId);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":DISK_FILE_ID", diskFileId);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -822,7 +821,7 @@ bool RdbmsCatalogue::diskFileIdExists(rdbms::PooledConn &conn, const std::string
 //------------------------------------------------------------------------------
 // diskFilePathExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::diskFilePathExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+bool RdbmsCatalogue::diskFilePathExists(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &diskFilePath) const {
   try {
     const char *const sql =
@@ -834,10 +833,10 @@ bool RdbmsCatalogue::diskFilePathExists(rdbms::PooledConn &conn, const std::stri
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "DISK_FILE_PATH = :DISK_FILE_PATH";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":DISK_FILE_PATH", diskFilePath);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":DISK_FILE_PATH", diskFilePath);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -847,7 +846,7 @@ bool RdbmsCatalogue::diskFilePathExists(rdbms::PooledConn &conn, const std::stri
 //------------------------------------------------------------------------------
 // diskFileUserExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::diskFileUserExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+bool RdbmsCatalogue::diskFileUserExists(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &diskFileUser) const {
   try {
     const char *const sql =
@@ -859,10 +858,10 @@ bool RdbmsCatalogue::diskFileUserExists(rdbms::PooledConn &conn, const std::stri
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "DISK_FILE_USER = :DISK_FILE_USER";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":DISK_FILE_USER", diskFileUser);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":DISK_FILE_USER", diskFileUser);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -872,7 +871,7 @@ bool RdbmsCatalogue::diskFileUserExists(rdbms::PooledConn &conn, const std::stri
 //------------------------------------------------------------------------------
 // diskFileGroupExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::diskFileGroupExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+bool RdbmsCatalogue::diskFileGroupExists(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &diskFileGroup) const {
   try {
     const char *const sql =
@@ -884,10 +883,10 @@ bool RdbmsCatalogue::diskFileGroupExists(rdbms::PooledConn &conn, const std::str
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "DISK_FILE_GROUP = :DISK_FILE_GROUP";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":DISK_FILE_GROUP", diskFileGroup);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":DISK_FILE_GROUP", diskFileGroup);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -897,7 +896,7 @@ bool RdbmsCatalogue::diskFileGroupExists(rdbms::PooledConn &conn, const std::str
 //------------------------------------------------------------------------------
 // archiveRouteExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::archiveRouteExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+bool RdbmsCatalogue::archiveRouteExists(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &storageClassName, const uint64_t copyNb) const {
   try {
     const char *const sql =
@@ -911,11 +910,11 @@ bool RdbmsCatalogue::archiveRouteExists(rdbms::PooledConn &conn, const std::stri
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND "
         "COPY_NB = :COPY_NB";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
-    stmt->bindUint64(":COPY_NB", copyNb);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
+    stmt.bindUint64(":COPY_NB", copyNb);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -929,11 +928,11 @@ void RdbmsCatalogue::deleteTapePool(const std::string &name) {
   try {
     const char *const sql = "DELETE FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":TAPE_POOL_NAME", name);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":TAPE_POOL_NAME", name);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete tape-pool ") + name + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -987,8 +986,8 @@ std::list<TapePool> RdbmsCatalogue::getTapePools() const {
         "TAPE_POOL_NAME";
 
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       TapePool pool;
 
@@ -1031,15 +1030,15 @@ void RdbmsCatalogue::modifyTapePoolNbPartialTapes(const common::dataStructures::
       "WHERE "
         "TAPE_POOL_NAME = :TAPE_POOL_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":TAPE_POOL_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":TAPE_POOL_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -1064,15 +1063,15 @@ void RdbmsCatalogue::modifyTapePoolComment(const common::dataStructures::Securit
       "WHERE "
         "TAPE_POOL_NAME = :TAPE_POOL_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":TAPE_POOL_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":TAPE_POOL_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -1098,15 +1097,15 @@ void RdbmsCatalogue::setTapePoolEncryption(const common::dataStructures::Securit
       "WHERE "
         "TAPE_POOL_NAME = :TAPE_POOL_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindBool(":IS_ENCRYPTED", encryptionValue);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":TAPE_POOL_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindBool(":IS_ENCRYPTED", encryptionValue);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":TAPE_POOL_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -1180,24 +1179,24 @@ void RdbmsCatalogue::createArchiveRoute(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
-    stmt->bindUint64(":COPY_NB", copyNb);
-    stmt->bindString(":TAPE_POOL_NAME", tapePoolName);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
+    stmt.bindUint64(":COPY_NB", copyNb);
+    stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch(exception::Exception &ex) {
@@ -1219,13 +1218,13 @@ void RdbmsCatalogue::deleteArchiveRoute(const std::string &diskInstanceName, con
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND "
         "COPY_NB = :COPY_NB";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
-    stmt->bindUint64(":COPY_NB", copyNb);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
+    stmt.bindUint64(":COPY_NB", copyNb);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       exception::UserError ue;
       ue.getMessage() << "Cannot delete archive route for storage-class " << diskInstanceName + ":" + storageClassName +
         " and copy number " << copyNb << " because it does not exist";
@@ -1265,8 +1264,8 @@ std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes
       "ORDER BY "
         "DISK_INSTANCE_NAME, STORAGE_CLASS_NAME, COPY_NB";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       common::dataStructures::ArchiveRoute route;
 
@@ -1310,17 +1309,17 @@ void RdbmsCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND "
         "COPY_NB = :COPY_NB";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":TAPE_POOL_NAME", tapePoolName);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":DISK_INSTANCE_NAME", instanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
-    stmt->bindUint64(":COPY_NB", copyNb);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
+    stmt.bindUint64(":COPY_NB", copyNb);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       exception::UserError ue;
       ue.getMessage() << "Cannot modify archive route for storage-class " << instanceName + ":" + storageClassName +
         " and copy number " << copyNb << " because it does not exist";
@@ -1352,17 +1351,17 @@ void RdbmsCatalogue::modifyArchiveRouteComment(const common::dataStructures::Sec
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND "
         "COPY_NB = :COPY_NB";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":DISK_INSTANCE_NAME", instanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
-    stmt->bindUint64(":COPY_NB", copyNb);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
+    stmt.bindUint64(":COPY_NB", copyNb);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       exception::UserError ue;
       ue.getMessage() << "Cannot modify archive route for storage-class " << instanceName + ":" + storageClassName +
         " and copy number " << copyNb << " because it does not exist";
@@ -1414,21 +1413,21 @@ void RdbmsCatalogue::createLogicalLibrary(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":LOGICAL_LIBRARY_NAME", name);
+    stmt.bindString(":LOGICAL_LIBRARY_NAME", name);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch(std::exception &ex) {
@@ -1439,7 +1438,7 @@ void RdbmsCatalogue::createLogicalLibrary(
 //------------------------------------------------------------------------------
 // logicalLibraryExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::logicalLibraryExists(rdbms::PooledConn &conn, const std::string &logicalLibraryName) const {
+bool RdbmsCatalogue::logicalLibraryExists(rdbms::Conn &conn, const std::string &logicalLibraryName) const {
   try {
     const char *const sql =
       "SELECT "
@@ -1448,9 +1447,9 @@ bool RdbmsCatalogue::logicalLibraryExists(rdbms::PooledConn &conn, const std::st
         "LOGICAL_LIBRARY "
       "WHERE "
         "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -1464,11 +1463,11 @@ void RdbmsCatalogue::deleteLogicalLibrary(const std::string &name) {
   try {
     const char *const sql = "DELETE FROM LOGICAL_LIBRARY WHERE LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":LOGICAL_LIBRARY_NAME", name);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":LOGICAL_LIBRARY_NAME", name);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete logical-library ") + name + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -1503,8 +1502,8 @@ std::list<common::dataStructures::LogicalLibrary>
       "ORDER BY "
         "LOGICAL_LIBRARY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       common::dataStructures::LogicalLibrary lib;
 
@@ -1542,15 +1541,15 @@ void RdbmsCatalogue::modifyLogicalLibraryComment(const common::dataStructures::S
       "WHERE "
         "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":LOGICAL_LIBRARY_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LOGICAL_LIBRARY_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify logical library ") + name + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -1626,28 +1625,28 @@ void RdbmsCatalogue::createTape(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":VID", vid);
-    stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
-    stmt->bindString(":TAPE_POOL_NAME", tapePoolName);
-    stmt->bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
-    stmt->bindUint64(":DATA_IN_BYTES", 0);
-    stmt->bindUint64(":LAST_FSEQ", 0);
-    stmt->bindBool(":IS_DISABLED", disabled);
-    stmt->bindBool(":IS_FULL", full);
+    stmt.bindString(":VID", vid);
+    stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
+    stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
+    stmt.bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
+    stmt.bindUint64(":DATA_IN_BYTES", 0);
+    stmt.bindUint64(":LAST_FSEQ", 0);
+    stmt.bindBool(":IS_DISABLED", disabled);
+    stmt.bindBool(":IS_FULL", full);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch(exception::Exception &ex) {
@@ -1670,7 +1669,7 @@ bool RdbmsCatalogue::tapeExists(const std::string &vid) const {
 //------------------------------------------------------------------------------
 // tapeExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::tapeExists(rdbms::PooledConn &conn, const std::string &vid) const {
+bool RdbmsCatalogue::tapeExists(rdbms::Conn &conn, const std::string &vid) const {
   try {
     const char *const sql =
       "SELECT "
@@ -1679,9 +1678,9 @@ bool RdbmsCatalogue::tapeExists(rdbms::PooledConn &conn, const std::string &vid)
         "TAPE "
       "WHERE "
         "VID = :VID";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":VID", vid);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":VID", vid);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -1695,11 +1694,11 @@ void RdbmsCatalogue::deleteTape(const std::string &vid) {
   try {
     const char *const sql = "DELETE FROM TAPE WHERE VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -1724,7 +1723,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(const TapeSearc
 //------------------------------------------------------------------------------
 // getTapes
 //------------------------------------------------------------------------------
-std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::PooledConn &conn,
+std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::Conn &conn,
   const TapeSearchCriteria &searchCriteria) const {
   try {
     std::list<common::dataStructures::Tape> tapes;
@@ -1810,17 +1809,17 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::PooledCo
 
     sql += " ORDER BY VID";
 
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
 
-    if(searchCriteria.vid) stmt->bindString(":VID", searchCriteria.vid.value());
-    if(searchCriteria.logicalLibrary) stmt->bindString(":LOGICAL_LIBRARY_NAME", searchCriteria.logicalLibrary.value());
-    if(searchCriteria.tapePool) stmt->bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value());
-    if(searchCriteria.capacityInBytes) stmt->bindUint64(":CAPACITY_IN_BYTES", searchCriteria.capacityInBytes.value());
-    if(searchCriteria.disabled) stmt->bindBool(":IS_DISABLED", searchCriteria.disabled.value());
-    if(searchCriteria.full) stmt->bindBool(":IS_FULL", searchCriteria.full.value());
-    if(searchCriteria.lbp) stmt->bindBool(":LBP_IS_ON", searchCriteria.lbp.value());
+    if(searchCriteria.vid) stmt.bindString(":VID", searchCriteria.vid.value());
+    if(searchCriteria.logicalLibrary) stmt.bindString(":LOGICAL_LIBRARY_NAME", searchCriteria.logicalLibrary.value());
+    if(searchCriteria.tapePool) stmt.bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value());
+    if(searchCriteria.capacityInBytes) stmt.bindUint64(":CAPACITY_IN_BYTES", searchCriteria.capacityInBytes.value());
+    if(searchCriteria.disabled) stmt.bindBool(":IS_DISABLED", searchCriteria.disabled.value());
+    if(searchCriteria.full) stmt.bindBool(":IS_FULL", searchCriteria.full.value());
+    if(searchCriteria.lbp) stmt.bindBool(":LBP_IS_ON", searchCriteria.lbp.value());
 
-    auto rset = stmt->executeQuery();
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       common::dataStructures::Tape tape;
 
@@ -1910,17 +1909,17 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getTapesByVid(const std::se
     }
 
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
 
     {
       uint64_t vidNb = 1;
       for(auto &vid : vids) {
-        stmt->bindString(":VID" + std::to_string(vidNb), vid);
+        stmt.bindString(":VID" + std::to_string(vidNb), vid);
         vidNb++;
       }
     }
 
-    auto rset = stmt->executeQuery();
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       common::dataStructures::Tape tape;
 
@@ -1979,16 +1978,16 @@ void RdbmsCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity
         "IS_FULL != 0 AND "
         "NOT EXISTS (SELECT VID FROM TAPE_FILE WHERE VID = :SELECT_VID)";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":UPDATE_VID", vid);
-    stmt->bindString(":SELECT_VID", vid);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":UPDATE_VID", vid);
+    stmt.bindString(":SELECT_VID", vid);
+    stmt.executeNonQuery();
 
     // If the update failed due to a user error
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       // Try to determine the user error
       //
       // Please note that this is a best effort diagnosis because there is no
@@ -2067,15 +2066,15 @@ void RdbmsCatalogue::modifyTapeLogicalLibraryName(const common::dataStructures::
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2101,15 +2100,15 @@ void RdbmsCatalogue::modifyTapeTapePoolName(const common::dataStructures::Securi
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":TAPE_POOL_NAME", tapePoolName);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2135,15 +2134,15 @@ void RdbmsCatalogue::modifyTapeCapacityInBytes(const common::dataStructures::Sec
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2169,15 +2168,15 @@ void RdbmsCatalogue::modifyTapeEncryptionKey(const common::dataStructures::Secur
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":ENCRYPTION_KEY", encryptionKey);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":ENCRYPTION_KEY", encryptionKey);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2200,13 +2199,13 @@ void RdbmsCatalogue::tapeMountedForArchive(const std::string &vid, const std::st
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":LAST_WRITE_DRIVE", drive);
-    stmt->bindUint64(":LAST_WRITE_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":LAST_WRITE_DRIVE", drive);
+    stmt.bindUint64(":LAST_WRITE_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2229,13 +2228,13 @@ void RdbmsCatalogue::tapeMountedForRetrieve(const std::string &vid, const std::s
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":LAST_READ_DRIVE", drive);
-    stmt->bindUint64(":LAST_READ_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":LAST_READ_DRIVE", drive);
+    stmt.bindUint64(":LAST_READ_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2261,15 +2260,15 @@ void RdbmsCatalogue::setTapeFull(const common::dataStructures::SecurityIdentity
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindBool(":IS_FULL", fullValue);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindBool(":IS_FULL", fullValue);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2290,11 +2289,11 @@ void RdbmsCatalogue::noSpaceLeftOnTape(const std::string &vid) {
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::Exception(std::string("Tape ") + vid + " does not exist");
     }
   } catch (exception::Exception &ex) {
@@ -2318,15 +2317,15 @@ void RdbmsCatalogue::setTapeDisabled(const common::dataStructures::SecurityIdent
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindBool(":IS_DISABLED", disabledValue);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindBool(":IS_DISABLED", disabledValue);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2352,15 +2351,15 @@ void RdbmsCatalogue::modifyTapeComment(const common::dataStructures::SecurityIde
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -2387,16 +2386,16 @@ void RdbmsCatalogue::modifyRequesterMountRulePolicy(const common::dataStructures
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_NAME = :REQUESTER_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":MOUNT_POLICY_NAME", mountPolicy);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":DISK_INSTANCE_NAME", instanceName);
-    stmt->bindString(":REQUESTER_NAME", requesterName);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":MOUNT_POLICY_NAME", mountPolicy);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
+    stmt.bindString(":REQUESTER_NAME", requesterName);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify requester mount rule ") + instanceName + ":" +
         requesterName + " because it does not exist");
     }
@@ -2424,16 +2423,16 @@ void RdbmsCatalogue::modifyRequesteMountRuleComment(const common::dataStructures
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_NAME = :REQUESTER_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":DISK_INSTANCE_NAME", instanceName);
-    stmt->bindString(":REQUESTER_NAME", requesterName);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
+    stmt.bindString(":REQUESTER_NAME", requesterName);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify requester mount rule ") + instanceName + ":" +
         requesterName + " because it does not exist");
     }
@@ -2461,16 +2460,16 @@ void RdbmsCatalogue::modifyRequesterGroupMountRulePolicy(const common::dataStruc
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":MOUNT_POLICY_NAME", mountPolicy);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":DISK_INSTANCE_NAME", instanceName);
-    stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":MOUNT_POLICY_NAME", mountPolicy);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
+    stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify requester group mount rule ") + instanceName + ":" +
         requesterGroupName + " because it does not exist");
     }
@@ -2498,16 +2497,16 @@ void RdbmsCatalogue::modifyRequesterGroupMountRuleComment(const common::dataStru
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":DISK_INSTANCE_NAME", instanceName);
-    stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
+    stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify requester group mount rule ") + instanceName + ":" +
         requesterGroupName + " because it does not exist");
     }
@@ -2578,29 +2577,29 @@ void RdbmsCatalogue::createMountPolicy(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":MOUNT_POLICY_NAME", name);
+    stmt.bindString(":MOUNT_POLICY_NAME", name);
 
-    stmt->bindUint64(":ARCHIVE_PRIORITY", archivePriority);
-    stmt->bindUint64(":ARCHIVE_MIN_REQUEST_AGE", minArchiveRequestAge);
+    stmt.bindUint64(":ARCHIVE_PRIORITY", archivePriority);
+    stmt.bindUint64(":ARCHIVE_MIN_REQUEST_AGE", minArchiveRequestAge);
 
-    stmt->bindUint64(":RETRIEVE_PRIORITY", retrievePriority);
-    stmt->bindUint64(":RETRIEVE_MIN_REQUEST_AGE", minRetrieveRequestAge);
+    stmt.bindUint64(":RETRIEVE_PRIORITY", retrievePriority);
+    stmt.bindUint64(":RETRIEVE_MIN_REQUEST_AGE", minRetrieveRequestAge);
 
-    stmt->bindUint64(":MAX_DRIVES_ALLOWED", maxDrivesAllowed);
+    stmt.bindUint64(":MAX_DRIVES_ALLOWED", maxDrivesAllowed);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch(exception::Exception &ex) {
@@ -2661,23 +2660,23 @@ void RdbmsCatalogue::createRequesterMountRule(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_NAME", requesterName);
-    stmt->bindString(":MOUNT_POLICY_NAME", mountPolicyName);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_NAME", requesterName);
+    stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch(exception::Exception &ex) {
@@ -2711,8 +2710,8 @@ std::list<common::dataStructures::RequesterMountRule> RdbmsCatalogue::getRequest
       "ORDER BY "
         "DISK_INSTANCE_NAME, REQUESTER_NAME, MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while(rset.next()) {
       common::dataStructures::RequesterMountRule rule;
 
@@ -2748,12 +2747,12 @@ void RdbmsCatalogue::deleteRequesterMountRule(const std::string &diskInstanceNam
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_NAME = :REQUESTER_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_NAME", requesterName);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_NAME", requesterName);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete mount rule for requester ") + diskInstanceName + ":" + requesterName +
         " because the rule does not exist");
     }
@@ -2816,23 +2815,23 @@ void RdbmsCatalogue::createRequesterGroupMountRule(
         ":LAST_UPDATE_USER_NAME,"
         ":LAST_UPDATE_HOST_NAME,"
         ":LAST_UPDATE_TIME)";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
 
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
-    stmt->bindString(":MOUNT_POLICY_NAME", mountPolicyName);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
+    stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName);
 
-    stmt->bindString(":USER_COMMENT", comment);
+    stmt.bindString(":USER_COMMENT", comment);
 
-    stmt->bindString(":CREATION_LOG_USER_NAME", admin.username);
-    stmt->bindString(":CREATION_LOG_HOST_NAME", admin.host);
-    stmt->bindUint64(":CREATION_LOG_TIME", now);
+    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
+    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
+    stmt.bindUint64(":CREATION_LOG_TIME", now);
 
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::UserError &) {
     throw;
   } catch(exception::Exception &ex) {
@@ -2844,7 +2843,7 @@ void RdbmsCatalogue::createRequesterGroupMountRule(
 // getRequesterGroupMountPolicy
 //------------------------------------------------------------------------------
 common::dataStructures::MountPolicy *RdbmsCatalogue::getRequesterGroupMountPolicy(
-  rdbms::PooledConn &conn,
+  rdbms::Conn &conn,
   const std::string &diskInstanceName,
   const std::string &requesterGroupName) const {
   try {
@@ -2878,10 +2877,10 @@ common::dataStructures::MountPolicy *RdbmsCatalogue::getRequesterGroupMountPolic
       "WHERE "
         "REQUESTER_GROUP_MOUNT_RULE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
+    auto rset = stmt.executeQuery();
     if(rset.next()) {
       auto policy = cta::make_unique<common::dataStructures::MountPolicy>();
 
@@ -2938,8 +2937,8 @@ std::list<common::dataStructures::RequesterGroupMountRule> RdbmsCatalogue::getRe
       "ORDER BY "
         "DISK_INSTANCE_NAME, REQUESTER_GROUP_NAME, MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while(rset.next()) {
       common::dataStructures::RequesterGroupMountRule rule;
 
@@ -2977,12 +2976,12 @@ void RdbmsCatalogue::deleteRequesterGroupMountRule(const std::string &diskInstan
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete the mount rule for requester group ") + diskInstanceName + ":" +
         requesterGroupName + " because it does not exist");
     }
@@ -2996,7 +2995,7 @@ void RdbmsCatalogue::deleteRequesterGroupMountRule(const std::string &diskInstan
 //------------------------------------------------------------------------------
 // mountPolicyExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::mountPolicyExists(rdbms::PooledConn &conn, const std::string &mountPolicyName) const {
+bool RdbmsCatalogue::mountPolicyExists(rdbms::Conn &conn, const std::string &mountPolicyName) const {
   try {
     const char *const sql =
       "SELECT "
@@ -3005,9 +3004,9 @@ bool RdbmsCatalogue::mountPolicyExists(rdbms::PooledConn &conn, const std::strin
         "MOUNT_POLICY "
       "WHERE "
         "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":MOUNT_POLICY_NAME", mountPolicyName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -3017,7 +3016,7 @@ bool RdbmsCatalogue::mountPolicyExists(rdbms::PooledConn &conn, const std::strin
 //------------------------------------------------------------------------------
 // requesterMountRuleExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::requesterMountRuleExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+bool RdbmsCatalogue::requesterMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &requesterName) const {
   try {
     const char *const sql =
@@ -3028,10 +3027,10 @@ bool RdbmsCatalogue::requesterMountRuleExists(rdbms::PooledConn &conn, const std
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_NAME = :REQUESTER_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_NAME", requesterName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_NAME", requesterName);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -3042,7 +3041,7 @@ bool RdbmsCatalogue::requesterMountRuleExists(rdbms::PooledConn &conn, const std
 // getRequesterMountPolicy
 //------------------------------------------------------------------------------
 common::dataStructures::MountPolicy *RdbmsCatalogue::getRequesterMountPolicy(
-  rdbms::PooledConn &conn,
+  rdbms::Conn &conn,
   const std::string &diskInstanceName,
   const std::string &requesterName) const {
   try {
@@ -3076,10 +3075,10 @@ common::dataStructures::MountPolicy *RdbmsCatalogue::getRequesterMountPolicy(
       "WHERE "
         "REQUESTER_MOUNT_RULE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_NAME", requesterName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_NAME", requesterName);
+    auto rset = stmt.executeQuery();
     if(rset.next()) {
       auto policy = cta::make_unique<common::dataStructures::MountPolicy>();
 
@@ -3116,7 +3115,7 @@ common::dataStructures::MountPolicy *RdbmsCatalogue::getRequesterMountPolicy(
 //------------------------------------------------------------------------------
 // requesterGroupMountRuleExists
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::requesterGroupMountRuleExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+bool RdbmsCatalogue::requesterGroupMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &requesterGroupName) const {
   try {
     const char *const sql =
@@ -3128,10 +3127,10 @@ bool RdbmsCatalogue::requesterGroupMountRuleExists(rdbms::PooledConn &conn, cons
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
+    auto rset = stmt.executeQuery();
     return rset.next();
   } catch (exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -3145,11 +3144,11 @@ void RdbmsCatalogue::deleteMountPolicy(const std::string &name) {
   try {
     const char *const sql = "DELETE FROM MOUNT_POLICY WHERE MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":MOUNT_POLICY_NAME", name);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":MOUNT_POLICY_NAME", name);
+    stmt.executeNonQuery();
 
-    if(0 == stmt->getNbAffectedRows()) {
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot delete mount policy ") + name + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -3191,8 +3190,8 @@ std::list<common::dataStructures::MountPolicy> RdbmsCatalogue::getMountPolicies(
       "ORDER BY "
         "MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       common::dataStructures::MountPolicy policy;
 
@@ -3241,15 +3240,15 @@ void RdbmsCatalogue::modifyMountPolicyArchivePriority(const common::dataStructur
       "WHERE "
         "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":ARCHIVE_PRIORITY", archivePriority);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":MOUNT_POLICY_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindUint64(":ARCHIVE_PRIORITY", archivePriority);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":MOUNT_POLICY_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist");
     }
   } catch(exception::UserError &) {
@@ -3275,15 +3274,15 @@ void RdbmsCatalogue::modifyMountPolicyArchiveMinRequestAge(const common::dataStr
       "WHERE "
         "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":ARCHIVE_MIN_REQUEST_AGE", minArchiveRequestAge);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":MOUNT_POLICY_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindUint64(":ARCHIVE_MIN_REQUEST_AGE", minArchiveRequestAge);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":MOUNT_POLICY_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist");
     }
   } catch(exception::UserError &) {
@@ -3309,15 +3308,15 @@ void RdbmsCatalogue::modifyMountPolicyRetrievePriority(const common::dataStructu
       "WHERE "
         "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":RETRIEVE_PRIORITY", retrievePriority);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":MOUNT_POLICY_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindUint64(":RETRIEVE_PRIORITY", retrievePriority);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":MOUNT_POLICY_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist");
     }
   } catch(exception::UserError &) {
@@ -3343,15 +3342,15 @@ void RdbmsCatalogue::modifyMountPolicyRetrieveMinRequestAge(const common::dataSt
       "WHERE "
         "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":RETRIEVE_MIN_REQUEST_AGE", minRetrieveRequestAge);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":MOUNT_POLICY_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindUint64(":RETRIEVE_MIN_REQUEST_AGE", minRetrieveRequestAge);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":MOUNT_POLICY_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist");
     }
   } catch(exception::UserError &) {
@@ -3377,15 +3376,15 @@ void RdbmsCatalogue::modifyMountPolicyMaxDrivesAllowed(const common::dataStructu
       "WHERE "
         "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":MAX_DRIVES_ALLOWED", maxDrivesAllowed);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":MOUNT_POLICY_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindUint64(":MAX_DRIVES_ALLOWED", maxDrivesAllowed);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":MOUNT_POLICY_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist");
     }
   } catch(exception::UserError &) {
@@ -3411,15 +3410,15 @@ void RdbmsCatalogue::modifyMountPolicyComment(const common::dataStructures::Secu
       "WHERE "
         "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":USER_COMMENT", comment);
-    stmt->bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt->bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt->bindUint64(":LAST_UPDATE_TIME", now);
-    stmt->bindString(":MOUNT_POLICY_NAME", name);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":USER_COMMENT", comment);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":MOUNT_POLICY_NAME", name);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist");
     }
   } catch(exception::UserError &) {
@@ -3432,7 +3431,7 @@ void RdbmsCatalogue::modifyMountPolicyComment(const common::dataStructures::Secu
 //------------------------------------------------------------------------------
 // insertArchiveFile
 //------------------------------------------------------------------------------
-void RdbmsCatalogue::insertArchiveFile(rdbms::PooledConn &conn, const rdbms::Stmt::AutocommitMode autocommitMode,
+void RdbmsCatalogue::insertArchiveFile(rdbms::Conn &conn, const rdbms::AutocommitMode autocommitMode,
   const ArchiveFileRow &row) {
   try {
     if(!storageClassExists(conn, row.diskInstance, row.storageClassName)) {
@@ -3472,21 +3471,21 @@ void RdbmsCatalogue::insertArchiveFile(rdbms::PooledConn &conn, const rdbms::Stm
         ":RECONCILIATION_TIME)";
     auto stmt = conn.createStmt(sql, autocommitMode);
 
-    stmt->bindUint64(":ARCHIVE_FILE_ID", row.archiveFileId);
-    stmt->bindString(":DISK_INSTANCE_NAME", row.diskInstance);
-    stmt->bindString(":DISK_FILE_ID", row.diskFileId);
-    stmt->bindString(":DISK_FILE_PATH", row.diskFilePath);
-    stmt->bindString(":DISK_FILE_USER", row.diskFileUser);
-    stmt->bindString(":DISK_FILE_GROUP", row.diskFileGroup);
-    stmt->bindString(":DISK_FILE_RECOVERY_BLOB", row.diskFileRecoveryBlob);
-    stmt->bindUint64(":SIZE_IN_BYTES", row.size);
-    stmt->bindString(":CHECKSUM_TYPE", row.checksumType);
-    stmt->bindString(":CHECKSUM_VALUE", row.checksumValue);
-    stmt->bindString(":STORAGE_CLASS_NAME", row.storageClassName);
-    stmt->bindUint64(":CREATION_TIME", now);
-    stmt->bindUint64(":RECONCILIATION_TIME", now);
-
-    stmt->executeNonQuery();
+    stmt.bindUint64(":ARCHIVE_FILE_ID", row.archiveFileId);
+    stmt.bindString(":DISK_INSTANCE_NAME", row.diskInstance);
+    stmt.bindString(":DISK_FILE_ID", row.diskFileId);
+    stmt.bindString(":DISK_FILE_PATH", row.diskFilePath);
+    stmt.bindString(":DISK_FILE_USER", row.diskFileUser);
+    stmt.bindString(":DISK_FILE_GROUP", row.diskFileGroup);
+    stmt.bindString(":DISK_FILE_RECOVERY_BLOB", row.diskFileRecoveryBlob);
+    stmt.bindUint64(":SIZE_IN_BYTES", row.size);
+    stmt.bindString(":CHECKSUM_TYPE", row.checksumType);
+    stmt.bindString(":CHECKSUM_VALUE", row.checksumValue);
+    stmt.bindString(":STORAGE_CLASS_NAME", row.storageClassName);
+    stmt.bindUint64(":CREATION_TIME", now);
+    stmt.bindUint64(":RECONCILIATION_TIME", now);
+
+    stmt.executeNonQuery();
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
   }
@@ -3677,38 +3676,38 @@ common::dataStructures::ArchiveFileSummary RdbmsCatalogue::getTapeFileSummary(
     }
 
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
     if(searchCriteria.archiveFileId) {
-      stmt->bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value());
+      stmt.bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value());
     }
     if(searchCriteria.diskInstance) {
-      stmt->bindString(":DISK_INSTANCE_NAME", searchCriteria.diskInstance.value());
+      stmt.bindString(":DISK_INSTANCE_NAME", searchCriteria.diskInstance.value());
     }
     if(searchCriteria.diskFileId) {
-      stmt->bindString(":DISK_FILE_ID", searchCriteria.diskFileId.value());
+      stmt.bindString(":DISK_FILE_ID", searchCriteria.diskFileId.value());
     }
     if(searchCriteria.diskFilePath) {
-      stmt->bindString(":DISK_FILE_PATH", searchCriteria.diskFilePath.value());
+      stmt.bindString(":DISK_FILE_PATH", searchCriteria.diskFilePath.value());
     }
     if(searchCriteria.diskFileUser) {
-      stmt->bindString(":DISK_FILE_USER", searchCriteria.diskFileUser.value());
+      stmt.bindString(":DISK_FILE_USER", searchCriteria.diskFileUser.value());
     }
     if(searchCriteria.diskFileGroup) {
-      stmt->bindString(":DISK_FILE_GROUP", searchCriteria.diskFileGroup.value());
+      stmt.bindString(":DISK_FILE_GROUP", searchCriteria.diskFileGroup.value());
     }
     if(searchCriteria.storageClass) {
-      stmt->bindString(":STORAGE_CLASS_NAME", searchCriteria.storageClass.value());
+      stmt.bindString(":STORAGE_CLASS_NAME", searchCriteria.storageClass.value());
     }
     if(searchCriteria.vid) {
-      stmt->bindString(":VID", searchCriteria.vid.value());
+      stmt.bindString(":VID", searchCriteria.vid.value());
     }
     if(searchCriteria.tapeFileCopyNb) {
-      stmt->bindUint64(":TAPE_FILE_COPY_NB", searchCriteria.tapeFileCopyNb.value());
+      stmt.bindUint64(":TAPE_FILE_COPY_NB", searchCriteria.tapeFileCopyNb.value());
     }
     if(searchCriteria.tapePool) {
-      stmt->bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value());
+      stmt.bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value());
     }
-    auto rset = stmt->executeQuery();
+    auto rset = stmt.executeQuery();
     if(!rset.next()) {
       throw exception::Exception("SELECT COUNT statement did not returned a row");
     }
@@ -3758,14 +3757,14 @@ void RdbmsCatalogue::tapeLabelled(const std::string &vid, const std::string &dri
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":LABEL_DRIVE", drive);
-    stmt->bindUint64(":LABEL_TIME", now);
-    stmt->bindBool(":LBP_IS_ON", lbpIsOn);
-    stmt->bindString(":VID", vid);
-    stmt->executeNonQuery();
-
-    if(0 == stmt->getNbAffectedRows()) {
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":LABEL_DRIVE", drive);
+    stmt.bindUint64(":LABEL_TIME", now);
+    stmt.bindBool(":LBP_IS_ON", lbpIsOn);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
       throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
     }
   } catch(exception::UserError &) {
@@ -3788,16 +3787,16 @@ common::dataStructures::ArchiveFileQueueCriteria RdbmsCatalogue::prepareForNewFi
 
     // Check that the number of archive routes is correct
     if(copyToPoolMap.empty()) {
-      exception::Exception ex;
-      ex.getMessage() << "Storage class " << diskInstanceName << ":" << storageClassName << " has no archive routes";
-      throw ex;
+      exception::UserError ue;
+      ue.getMessage() << "Storage class " << diskInstanceName << ":" << storageClassName << " has no archive routes";
+      throw ue;
     }
     if(copyToPoolMap.size() != expectedNbRoutes) {
-      exception::Exception ex;
-      ex.getMessage() << "Storage class " << diskInstanceName << ":" << storageClassName << " does not have the"
+      exception::UserError ue;
+      ue.getMessage() << "Storage class " << diskInstanceName << ":" << storageClassName << " does not have the"
         " expected number of archive routes routes: expected=" << expectedNbRoutes << ", actual=" <<
         copyToPoolMap.size();
-      throw ex;
+      throw ue;
     }
 
     const RequesterAndGroupMountPolicies mountPolicies = getMountPolicies(conn, diskInstanceName, user.name,
@@ -3831,7 +3830,7 @@ common::dataStructures::ArchiveFileQueueCriteria RdbmsCatalogue::prepareForNewFi
 //------------------------------------------------------------------------------
 // getTapeCopyToPoolMap
 //------------------------------------------------------------------------------
-common::dataStructures::TapeCopyToPoolMap RdbmsCatalogue::getTapeCopyToPoolMap(rdbms::PooledConn &conn,
+common::dataStructures::TapeCopyToPoolMap RdbmsCatalogue::getTapeCopyToPoolMap(rdbms::Conn &conn,
   const std::string &diskInstanceName, const std::string &storageClassName) const {
   try {
     common::dataStructures::TapeCopyToPoolMap copyToPoolMap;
@@ -3844,10 +3843,10 @@ common::dataStructures::TapeCopyToPoolMap RdbmsCatalogue::getTapeCopyToPoolMap(r
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       const uint64_t copyNb = rset.columnUint64("COPY_NB");
       const std::string tapePoolName = rset.columnString("TAPE_POOL_NAME");
@@ -3863,7 +3862,7 @@ common::dataStructures::TapeCopyToPoolMap RdbmsCatalogue::getTapeCopyToPoolMap(r
 //------------------------------------------------------------------------------
 // getExpectedNbArchiveRoutes
 //------------------------------------------------------------------------------
-uint64_t RdbmsCatalogue::getExpectedNbArchiveRoutes(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+uint64_t RdbmsCatalogue::getExpectedNbArchiveRoutes(rdbms::Conn &conn, const std::string &diskInstanceName,
   const std::string &storageClassName) const {
   try {
     const char *const sql =
@@ -3874,10 +3873,10 @@ uint64_t RdbmsCatalogue::getExpectedNbArchiveRoutes(rdbms::PooledConn &conn, con
       "WHERE "
         "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
+    auto rset = stmt.executeQuery();
     if(!rset.next()) {
       throw exception::Exception("Result set of SELECT COUNT(*) is empty");
     }
@@ -3891,8 +3890,8 @@ uint64_t RdbmsCatalogue::getExpectedNbArchiveRoutes(rdbms::PooledConn &conn, con
 // updateTape
 //------------------------------------------------------------------------------
 void RdbmsCatalogue::updateTape(
-  rdbms::PooledConn &conn,
-  const rdbms::Stmt::AutocommitMode autocommitMode,
+  rdbms::Conn &conn,
+  const rdbms::AutocommitMode autocommitMode,
   const std::string &vid,
   const uint64_t lastFSeq,
   const uint64_t compressedBytesWritten,
@@ -3908,12 +3907,12 @@ void RdbmsCatalogue::updateTape(
       "WHERE "
         "VID = :VID";
     auto stmt = conn.createStmt(sql, autocommitMode);
-    stmt->bindString(":VID", vid);
-    stmt->bindUint64(":LAST_FSEQ", lastFSeq);
-    stmt->bindUint64(":DATA_IN_BYTES", compressedBytesWritten);
-    stmt->bindString(":LAST_WRITE_DRIVE", tapeDrive);
-    stmt->bindUint64(":LAST_WRITE_TIME", now);
-    stmt->executeNonQuery();
+    stmt.bindString(":VID", vid);
+    stmt.bindUint64(":LAST_FSEQ", lastFSeq);
+    stmt.bindUint64(":DATA_IN_BYTES", compressedBytesWritten);
+    stmt.bindString(":LAST_WRITE_DRIVE", tapeDrive);
+    stmt.bindUint64(":LAST_WRITE_TIME", now);
+    stmt.executeNonQuery();
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) +  " failed: " + ex.getMessage().str());
   }
@@ -4045,7 +4044,7 @@ common::dataStructures::RetrieveFileQueueCriteria RdbmsCatalogue::prepareToRetri
 // getMountPolicies
 //------------------------------------------------------------------------------
 RequesterAndGroupMountPolicies RdbmsCatalogue::getMountPolicies(
-  rdbms::PooledConn &conn,
+  rdbms::Conn &conn,
   const std::string &diskInstanceName,
   const std::string &requesterName,
   const std::string &requesterGroupName) const {
@@ -4105,12 +4104,12 @@ RequesterAndGroupMountPolicies RdbmsCatalogue::getMountPolicies(
         "REQUESTER_GROUP_MOUNT_RULE.DISK_INSTANCE_NAME = :GROUP_DISK_INSTANCE_NAME AND "
         "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME";
 
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":REQUESTER_DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":GROUP_DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":REQUESTER_NAME", requesterName);
-    stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":REQUESTER_DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":GROUP_DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":REQUESTER_NAME", requesterName);
+    stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
+    auto rset = stmt.executeQuery();
 
     RequesterAndGroupMountPolicies policies;
     while(rset.next()) {
@@ -4154,7 +4153,7 @@ bool RdbmsCatalogue::isAdmin(const common::dataStructures::SecurityIdentity &adm
 //------------------------------------------------------------------------------
 // userIsAdmin
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::userIsAdmin(rdbms::PooledConn &conn, const std::string &userName) const {
+bool RdbmsCatalogue::userIsAdmin(rdbms::Conn &conn, const std::string &userName) const {
   const char *const sql =
     "SELECT "
       "ADMIN_USER_NAME AS ADMIN_USER_NAME "
@@ -4162,16 +4161,16 @@ bool RdbmsCatalogue::userIsAdmin(rdbms::PooledConn &conn, const std::string &use
       "ADMIN_USER "
     "WHERE "
       "ADMIN_USER_NAME = :ADMIN_USER_NAME";
-  auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-  stmt->bindString(":ADMIN_USER_NAME", userName);
-  auto rset = stmt->executeQuery();
+  auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+  stmt.bindString(":ADMIN_USER_NAME", userName);
+  auto rset = stmt.executeQuery();
   return rset.next();
 }
 
 //------------------------------------------------------------------------------
 // hostIsAdmin
 //------------------------------------------------------------------------------
-bool RdbmsCatalogue::hostIsAdmin(rdbms::PooledConn &conn, const std::string &hostName) const {
+bool RdbmsCatalogue::hostIsAdmin(rdbms::Conn &conn, const std::string &hostName) const {
   const char *const sql =
     "SELECT "
       "ADMIN_HOST_NAME AS ADMIN_HOST_NAME "
@@ -4179,9 +4178,9 @@ bool RdbmsCatalogue::hostIsAdmin(rdbms::PooledConn &conn, const std::string &hos
       "ADMIN_HOST "
     "WHERE "
       "ADMIN_HOST_NAME = :ADMIN_HOST_NAME";
-  auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-  stmt->bindString(":ADMIN_HOST_NAME", hostName);
-  auto rset = stmt->executeQuery();
+  auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+  stmt.bindString(":ADMIN_HOST_NAME", hostName);
+  auto rset = stmt.executeQuery();
   return rset.next();
 }
 
@@ -4208,9 +4207,9 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string &
         "IS_FULL = 0 AND "
         "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME";
     auto conn = m_connPool.getConn();
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
+    auto rset = stmt.executeQuery();
     while (rset.next()) {
       TapeForWriting tape;
       tape.vid = rset.columnString("VID");
@@ -4232,8 +4231,8 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string &
 // insertTapeFile
 //------------------------------------------------------------------------------
 void RdbmsCatalogue::insertTapeFile(
-  rdbms::PooledConn &conn,
-  const rdbms::Stmt::AutocommitMode autocommitMode,
+  rdbms::Conn &conn,
+  const rdbms::AutocommitMode autocommitMode,
   const common::dataStructures::TapeFile &tapeFile,
   const uint64_t archiveFileId) {
   try {
@@ -4257,15 +4256,15 @@ void RdbmsCatalogue::insertTapeFile(
         ":ARCHIVE_FILE_ID)";
     auto stmt = conn.createStmt(sql, autocommitMode);
 
-    stmt->bindString(":VID", tapeFile.vid);
-    stmt->bindUint64(":FSEQ", tapeFile.fSeq);
-    stmt->bindUint64(":BLOCK_ID", tapeFile.blockId);
-    stmt->bindUint64(":COMPRESSED_SIZE_IN_BYTES", tapeFile.compressedSize);
-    stmt->bindUint64(":COPY_NB", tapeFile.copyNb);
-    stmt->bindUint64(":CREATION_TIME", now);
-    stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
+    stmt.bindString(":VID", tapeFile.vid);
+    stmt.bindUint64(":FSEQ", tapeFile.fSeq);
+    stmt.bindUint64(":BLOCK_ID", tapeFile.blockId);
+    stmt.bindUint64(":COMPRESSED_SIZE_IN_BYTES", tapeFile.compressedSize);
+    stmt.bindUint64(":COPY_NB", tapeFile.copyNb);
+    stmt.bindUint64(":CREATION_TIME", now);
+    stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
 
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
   }
@@ -4274,7 +4273,7 @@ void RdbmsCatalogue::insertTapeFile(
 //------------------------------------------------------------------------------
 // setTapeLastFseq
 //------------------------------------------------------------------------------
-void RdbmsCatalogue::setTapeLastFSeq(rdbms::PooledConn &conn, const std::string &vid, const uint64_t lastFSeq) {
+void RdbmsCatalogue::setTapeLastFSeq(rdbms::Conn &conn, const std::string &vid, const uint64_t lastFSeq) {
   try {
     threading::MutexLocker locker(m_mutex);
 
@@ -4290,10 +4289,10 @@ void RdbmsCatalogue::setTapeLastFSeq(rdbms::PooledConn &conn, const std::string
         "LAST_FSEQ = :LAST_FSEQ "
       "WHERE "
         "VID=:VID";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindString(":VID", vid);
-    stmt->bindUint64(":LAST_FSEQ", lastFSeq);
-    stmt->executeNonQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt.bindString(":VID", vid);
+    stmt.bindUint64(":LAST_FSEQ", lastFSeq);
+    stmt.executeNonQuery();
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
   }
@@ -4302,7 +4301,7 @@ void RdbmsCatalogue::setTapeLastFSeq(rdbms::PooledConn &conn, const std::string
 //------------------------------------------------------------------------------
 // getTapeLastFSeq
 //------------------------------------------------------------------------------
-uint64_t RdbmsCatalogue::getTapeLastFSeq(rdbms::PooledConn &conn, const std::string &vid) const {
+uint64_t RdbmsCatalogue::getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const {
   try {
     const char *const sql =
       "SELECT "
@@ -4311,9 +4310,9 @@ uint64_t RdbmsCatalogue::getTapeLastFSeq(rdbms::PooledConn &conn, const std::str
         "TAPE "
       "WHERE "
         "VID = :VID";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":VID", vid);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":VID", vid);
+    auto rset = stmt.executeQuery();
     if(rset.next()) {
       return rset.columnUint64("LAST_FSEQ");
     } else {
@@ -4328,7 +4327,7 @@ uint64_t RdbmsCatalogue::getTapeLastFSeq(rdbms::PooledConn &conn, const std::str
 // getArchiveFileByArchiveId
 //------------------------------------------------------------------------------
 std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveFileByArchiveFileId(
-  rdbms::PooledConn &conn,
+  rdbms::Conn &conn,
   const uint64_t archiveFileId) const {
   try {
     const char *const sql =
@@ -4358,9 +4357,9 @@ std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveF
         "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID "
       "WHERE "
         "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
+    auto rset = stmt.executeQuery();
     std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile;
     while (rset.next()) {
       if(nullptr == archiveFile.get()) {
@@ -4408,7 +4407,7 @@ std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveF
 // getArchiveFileByDiskFileId
 //------------------------------------------------------------------------------
 std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveFileByDiskFileId(
-  rdbms::PooledConn &conn,
+  rdbms::Conn &conn,
   const std::string &diskInstanceName,
   const std::string &diskFileId) const {
   try {
@@ -4440,10 +4439,10 @@ std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveF
       "WHERE "
         "ARCHIVE_FILE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "ARCHIVE_FILE.DISK_FILE_ID = :DISK_FILE_ID";
-    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-    stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
-    stmt->bindString(":DISK_FILE_ID", diskFileId);
-    auto rset = stmt->executeQuery();
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
+    stmt.bindString(":DISK_FILE_ID", diskFileId);
+    auto rset = stmt.executeQuery();
     std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile;
     while (rset.next()) {
       if(nullptr == archiveFile.get()) {
@@ -4493,8 +4492,8 @@ std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveF
 void RdbmsCatalogue::ping() {
   const char *const sql = "SELECT COUNT(*) FROM CTA_CATALOGUE";
   auto conn = m_connPool.getConn();
-  auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-  auto rset = stmt->executeQuery();
+  auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+  auto rset = stmt.executeQuery();
 }
 
 //------------------------------------------------------------------------------
diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp
index c2318545d96d3c20d090006cec5525241161f905..738b78b4b8cc7060ec8b37226dd2e5ca1f2835b1 100644
--- a/catalogue/RdbmsCatalogue.hpp
+++ b/catalogue/RdbmsCatalogue.hpp
@@ -21,8 +21,8 @@
 #include "catalogue/Catalogue.hpp"
 #include "catalogue/RequesterAndGroupMountPolicies.hpp"
 #include "common/threading/Mutex.hpp"
-#include "rdbms/Conn.hpp"
 #include "rdbms/ConnPool.hpp"
+#include "rdbms/Login.hpp"
 
 #include <memory>
 
@@ -62,7 +62,8 @@ protected:
    * Protected constructor only to be called by sub-classes.
    *
    * @param log Object representing the API to the CTA logging system.
-   * @param connFactory The factory for creating new database connections.
+   * @param login The database login details to be used to create new
+   * connections.
    * @param nbConns The maximum number of concurrent connections to the
    * underlying relational database for all operations accept listing archive
    * files which can be relatively long operations.
@@ -72,7 +73,7 @@ protected:
    */
   RdbmsCatalogue(
     log::Logger &log,
-    std::unique_ptr<rdbms::ConnFactory> connFactory,
+    const rdbms::Login &login,
     const uint64_t nbConns,
     const uint64_t nbArchiveFileListingConns);
 
@@ -533,11 +534,6 @@ protected:
    */
   threading::Mutex m_mutex;
 
-  /**
-   * The database connection factory.
-   */
-  std::unique_ptr<rdbms::ConnFactory> m_connFactory;
-
   /**
    * The pool of connections to the underlying relational database to be used
    * for all operations accept listing archive files which can be relatively
@@ -558,7 +554,7 @@ protected:
    * @param adminUsername The name of the admin user.
    * @return True if the admin user exists.
    */
-  bool adminUserExists(rdbms::PooledConn &conn, const std::string adminUsername) const;
+  bool adminUserExists(rdbms::Conn &conn, const std::string adminUsername) const;
 
   /**
    * Returns true if the specified admin host exists.
@@ -567,7 +563,7 @@ protected:
    * @param adminHost The name of the admin host.
    * @return True if the admin host exists.
    */
-  bool adminHostExists(rdbms::PooledConn &conn, const std::string adminHost) const;
+  bool adminHostExists(rdbms::Conn &conn, const std::string adminHost) const;
 
   /**
    * Returns true if the specified storage class exists.
@@ -578,7 +574,7 @@ protected:
    * @param storageClassName The name of the storage class.
    * @return True if the storage class exists.
    */
-  bool storageClassExists(rdbms::PooledConn &conn, const std::string &diskInstanceName, const std::string &storageClassName)
+  bool storageClassExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &storageClassName)
     const;
 
   /**
@@ -596,7 +592,7 @@ protected:
    * @param tapePoolName The name of the tape pool.
    * @return True if the tape pool exists.
    */
-  bool tapePoolExists(rdbms::PooledConn &conn, const std::string &tapePoolName) const;
+  bool tapePoolExists(rdbms::Conn &conn, const std::string &tapePoolName) const;
 
   /**
    * Returns true if the specified archive file identifier exists.
@@ -605,7 +601,7 @@ protected:
    * @param archiveFileId The archive file identifier.
    * @return True if the archive file identifier exists.
    */
-  bool archiveFileIdExists(rdbms::PooledConn &conn, const uint64_t archiveFileId) const;
+  bool archiveFileIdExists(rdbms::Conn &conn, const uint64_t archiveFileId) const;
 
   /**
    * Returns true if the specified disk file identifier exists.
@@ -616,7 +612,7 @@ protected:
    * @param diskFileId The disk file identifier.
    * @return True if the disk file identifier exists.
    */
-  bool diskFileIdExists(rdbms::PooledConn &conn, const std::string &diskInstanceName, const std::string &diskFileId) const;
+  bool diskFileIdExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &diskFileId) const;
 
   /**
    * Returns true if the specified disk file path exists.
@@ -627,7 +623,7 @@ protected:
    * @param diskFilePath The disk file path.
    * @return True if the disk file path exists.
    */
-  bool diskFilePathExists(rdbms::PooledConn &conn, const std::string &diskInstanceName, const std::string &diskFilePath)
+  bool diskFilePathExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &diskFilePath)
     const;
 
   /**
@@ -639,7 +635,7 @@ protected:
    * @param diskFileUSer The name of the disk file user.
    * @return True if the disk file user exists.
    */
-  bool diskFileUserExists(rdbms::PooledConn &conn, const std::string &diskInstanceName, const std::string &diskFileUser)
+  bool diskFileUserExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &diskFileUser)
     const;
 
   /**
@@ -651,7 +647,7 @@ protected:
    * @param diskFileGroup The name of the disk file group.
    * @return True if the disk file group exists.
    */
-  bool diskFileGroupExists(rdbms::PooledConn &conn, const std::string &diskInstanceName, const std::string &diskFileGroup)
+  bool diskFileGroupExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &diskFileGroup)
     const;
 
   /**
@@ -665,7 +661,7 @@ protected:
    * @param copyNb The copy number of the tape file.
    * @return True if the archive route exists.
    */
-  bool archiveRouteExists(rdbms::PooledConn &conn, const std::string &diskInstanceName, const std::string &storageClassName,
+  bool archiveRouteExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &storageClassName,
     const uint64_t copyNb) const;
 
   /**
@@ -683,7 +679,7 @@ protected:
    * @param vid The volume identifier of the tape.
    * @return True if the tape exists.
    */
-  bool tapeExists(rdbms::PooledConn &conn, const std::string &vid) const;
+  bool tapeExists(rdbms::Conn &conn, const std::string &vid) const;
 
   /**
    * Returns the list of tapes that meet the specified search criteria.
@@ -692,7 +688,7 @@ protected:
    * @param searchCriteria The search criteria.
    * @return The list of tapes.
    */
-  std::list<common::dataStructures::Tape> getTapes(rdbms::PooledConn &conn, const TapeSearchCriteria &searchCriteria) const;
+  std::list<common::dataStructures::Tape> getTapes(rdbms::Conn &conn, const TapeSearchCriteria &searchCriteria) const;
 
   /**
    * Returns true if the specified logical library exists.
@@ -701,7 +697,7 @@ protected:
    * @param logicalLibraryName The name of the logical library.
    * @return True if the logical library exists.
    */
-  bool logicalLibraryExists(rdbms::PooledConn &conn, const std::string &logicalLibraryName) const;
+  bool logicalLibraryExists(rdbms::Conn &conn, const std::string &logicalLibraryName) const;
 
   /**
    * Returns true if the specified mount policy exists.
@@ -710,7 +706,7 @@ protected:
    * @param mountPolicyName The name of the mount policy
    * @return True if the mount policy exists.
    */
-  bool mountPolicyExists(rdbms::PooledConn &conn, const std::string &mountPolicyName) const;
+  bool mountPolicyExists(rdbms::Conn &conn, const std::string &mountPolicyName) const;
 
   /**
    * Returns true if the specified requester mount-rule exists.
@@ -721,7 +717,7 @@ protected:
    * to be unique within its disk instance.
    * @return True if the requester mount-rule exists.
    */
-  bool requesterMountRuleExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+  bool requesterMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName,
     const std::string &requesterName) const;
 
   /**
@@ -735,7 +731,7 @@ protected:
    * @return The mount policy or nullptr if one does not exists.
    */
   common::dataStructures::MountPolicy *getRequesterMountPolicy(
-    rdbms::PooledConn &conn,
+    rdbms::Conn &conn,
     const std::string &diskInstanceName,
     const std::string &requesterName) const;
 
@@ -749,7 +745,7 @@ protected:
    * guaranteed to be unique within its disk instance.
    * @return True if the requester-group mount-rule exists.
    */
-  bool requesterGroupMountRuleExists(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+  bool requesterGroupMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName,
     const std::string &requesterGroupName) const;
 
   /**
@@ -763,7 +759,7 @@ protected:
    * guaranteed to be unique within its disk instance.
    * @return The mount policy or nullptr if one does not exists.
    */
-  common::dataStructures::MountPolicy *getRequesterGroupMountPolicy(rdbms::PooledConn &conn,
+  common::dataStructures::MountPolicy *getRequesterGroupMountPolicy(rdbms::Conn &conn,
     const std::string &diskInstanceName, const std::string &requesterGroupName) const;
 
   /**
@@ -787,7 +783,7 @@ protected:
    * @param autocommitMode The autocommit mode of the SQL insert statement.
    * @param row The row to be inserted.
    */
-  void insertArchiveFile(rdbms::PooledConn &conn, const rdbms::Stmt::AutocommitMode autocommitMode,
+  void insertArchiveFile(rdbms::Conn &conn, const rdbms::AutocommitMode autocommitMode,
     const ArchiveFileRow &row);
 
   /**
@@ -803,7 +799,7 @@ protected:
    * table.
    * @return true if the specified user name is listed in the ADMIN_USER table.
    */
-  bool userIsAdmin(rdbms::PooledConn &conn, const std::string &userName) const;
+  bool userIsAdmin(rdbms::Conn &conn, const std::string &userName) const;
 
   /**
    * Returns true if the specified host name is listed in the ADMIN_HOST table.
@@ -813,7 +809,7 @@ protected:
    * table.
    * @return true if the specified host name is listed in the ADMIN_HOST table.
    */
-  bool hostIsAdmin(rdbms::PooledConn &conn, const std::string &userName) const;
+  bool hostIsAdmin(rdbms::Conn &conn, const std::string &userName) const;
 
   /**
    * Returns the expected number of archive routes for the specified storage
@@ -828,7 +824,7 @@ protected:
    * guaranteed to be unique within its disk instance.
    * @return The expected number of archive routes.
    */
-  uint64_t getExpectedNbArchiveRoutes(rdbms::PooledConn &conn, const std::string &diskInstanceName,
+  uint64_t getExpectedNbArchiveRoutes(rdbms::Conn &conn, const std::string &diskInstanceName,
     const std::string &storageClassNAme) const;
 
   /**
@@ -841,8 +837,8 @@ protected:
    * file is a copy.
    */
   void insertTapeFile(
-    rdbms::PooledConn &conn,
-    const rdbms::Stmt::AutocommitMode autocommitMode,
+    rdbms::Conn &conn,
+    const rdbms::AutocommitMode autocommitMode,
     const common::dataStructures::TapeFile &tapeFile,
     const uint64_t archiveFileId);
 
@@ -853,7 +849,7 @@ protected:
    * @param vid The volume identifier of the tape.
    * @param lastFseq The new value of the last FSeq.
    */
-  void setTapeLastFSeq(rdbms::PooledConn &conn, const std::string &vid, const uint64_t lastFSeq);
+  void setTapeLastFSeq(rdbms::Conn &conn, const std::string &vid, const uint64_t lastFSeq);
 
   /**
    * Returns the last FSeq of the specified tape.
@@ -862,7 +858,7 @@ protected:
    * @param vid The volume identifier of the tape.
    * @return The last FSeq.
    */
-  uint64_t getTapeLastFSeq(rdbms::PooledConn &conn, const std::string &vid) const;
+  uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const;
 
   /**
    * Updates the specified tape with the specified information.
@@ -877,8 +873,8 @@ protected:
    * @param tapeDrive The name of the tape drive that last wrote to the tape.
    */
   void updateTape(
-    rdbms::PooledConn &conn,
-    const rdbms::Stmt::AutocommitMode autocommitMode,
+    rdbms::Conn &conn,
+    const rdbms::AutocommitMode autocommitMode,
     const std::string &vid,
     const uint64_t lastFSeq,
     const uint64_t compressedBytesWritten,
@@ -894,7 +890,7 @@ protected:
    * an empty list.
    */
   std::unique_ptr<common::dataStructures::ArchiveFile> getArchiveFileByArchiveFileId(
-    rdbms::PooledConn &conn,
+    rdbms::Conn &conn,
     const uint64_t archiveFileId) const;
 
   /**
@@ -912,7 +908,7 @@ protected:
    * an empty list.
    */
   std::unique_ptr<common::dataStructures::ArchiveFile> getArchiveFileByDiskFileId(
-    rdbms::PooledConn &conn,
+    rdbms::Conn &conn,
     const std::string &diskInstance,
     const std::string &diskFileId) const;
 
@@ -929,7 +925,7 @@ protected:
    * @return The mount policies.
    */
   RequesterAndGroupMountPolicies getMountPolicies(
-    rdbms::PooledConn &conn,
+    rdbms::Conn &conn,
     const std::string &diskInstanceName,
     const std::string &requesterName,
     const std::string &requesterGroupName) const;
@@ -946,7 +942,7 @@ protected:
    * @return A unique archive ID that can be used by a new archive file within
    * the catalogue.
    */
-  virtual uint64_t getNextArchiveFileId(rdbms::PooledConn &conn) = 0;
+  virtual uint64_t getNextArchiveFileId(rdbms::Conn &conn) = 0;
 
   /**
    * Returns the mapping from tape copy to tape pool for the specified storage
@@ -961,7 +957,7 @@ protected:
    * class.
    */
   common::dataStructures::TapeCopyToPoolMap getTapeCopyToPoolMap(
-    rdbms::PooledConn &conn,
+    rdbms::Conn &conn,
     const std::string &diskInstanceName,
     const std::string &storageClassName) const;
 
diff --git a/catalogue/SchemaCreatingSqliteCatalogue.cpp b/catalogue/SchemaCreatingSqliteCatalogue.cpp
index 1f3d9ef0aa9334a46f682050b2766c0bbe4ba90e..e492e78fb9e7146f972d76535482cdc3e4c7d8d0 100644
--- a/catalogue/SchemaCreatingSqliteCatalogue.cpp
+++ b/catalogue/SchemaCreatingSqliteCatalogue.cpp
@@ -18,8 +18,6 @@
 
 #include "catalogue/SqliteCatalogueSchema.hpp"
 #include "catalogue/SchemaCreatingSqliteCatalogue.hpp"
-#include "rdbms/SqliteConn.hpp"
-#include "rdbms/SqliteConnFactory.hpp"
 
 namespace cta {
 namespace catalogue {
diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp
index e8b1241c2c09e978f1aeffe23958d25879000d9b..b923e49f71facba47e5d335dcf51427718d1487e 100644
--- a/catalogue/SqliteCatalogue.cpp
+++ b/catalogue/SqliteCatalogue.cpp
@@ -26,7 +26,6 @@
 #include "common/Timer.hpp"
 #include "common/utils/utils.hpp"
 #include "rdbms/AutoRollback.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
 
 namespace cta {
 namespace catalogue {
@@ -41,7 +40,7 @@ SqliteCatalogue::SqliteCatalogue(
   const uint64_t nbArchiveFileListingConns):
   RdbmsCatalogue(
     log,
-    rdbms::ConnFactoryFactory::create(rdbms::Login(rdbms::Login::DBTYPE_SQLITE, "", "", filename)),
+    rdbms::Login(rdbms::Login::DBTYPE_SQLITE, "", "", filename),
     nbConns,
     nbArchiveFileListingConns) {
 }
@@ -117,17 +116,17 @@ void SqliteCatalogue::deleteArchiveFile(const std::string &diskInstanceName, con
     t.reset();
     {
       const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
-      stmt->executeNonQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
+      stmt.executeNonQuery();
     }
     const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter);
 
     {
       const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
-      stmt->executeNonQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
+      stmt.executeNonQuery();
     }
     const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter);
 
@@ -198,17 +197,17 @@ void SqliteCatalogue::deleteArchiveFileByDiskFileId(const std::string &diskInsta
     t.reset();
     {
       const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFile->archiveFileID);
-      stmt->executeNonQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFile->archiveFileID);
+      stmt.executeNonQuery();
     }
     const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter);
 
     {
       const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFile->archiveFileID);
-      stmt->executeNonQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFile->archiveFileID);
+      stmt.executeNonQuery();
     }
     const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter);
 
@@ -257,7 +256,7 @@ void SqliteCatalogue::deleteArchiveFileByDiskFileId(const std::string &diskInsta
 //------------------------------------------------------------------------------
 // getNextArchiveFileId
 //------------------------------------------------------------------------------
-uint64_t SqliteCatalogue::getNextArchiveFileId(rdbms::PooledConn &conn) {
+uint64_t SqliteCatalogue::getNextArchiveFileId(rdbms::Conn &conn) {
   try {
     // The SQLite implemenation of getNextArchiveFileId() serializes access to
     // the SQLite database in order to avoid busy errors
@@ -265,7 +264,7 @@ uint64_t SqliteCatalogue::getNextArchiveFileId(rdbms::PooledConn &conn) {
 
     rdbms::AutoRollback autoRollback(conn);
 
-    conn.executeNonQuery("UPDATE ARCHIVE_FILE_ID SET ID = ID + 1", rdbms::Stmt::AutocommitMode::OFF);
+    conn.executeNonQuery("UPDATE ARCHIVE_FILE_ID SET ID = ID + 1", rdbms::AutocommitMode::OFF);
     uint64_t archiveFileId = 0;
     {
       const char *const sql =
@@ -273,8 +272,8 @@ uint64_t SqliteCatalogue::getNextArchiveFileId(rdbms::PooledConn &conn) {
           "ID AS ID "
         "FROM "
           "ARCHIVE_FILE_ID";
-      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
-      auto rset = stmt->executeQuery();
+      auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
+      auto rset = stmt.executeQuery();
       if(!rset.next()) {
         throw exception::Exception("ARCHIVE_FILE_ID table is empty");
       }
@@ -294,8 +293,8 @@ uint64_t SqliteCatalogue::getNextArchiveFileId(rdbms::PooledConn &conn) {
 //------------------------------------------------------------------------------
 // selectTapeForUpdate
 //------------------------------------------------------------------------------
-common::dataStructures::Tape SqliteCatalogue::selectTape(const rdbms::Stmt::AutocommitMode autocommitMode,
-  rdbms::PooledConn &conn, const std::string &vid) {
+common::dataStructures::Tape SqliteCatalogue::selectTape(const rdbms::AutocommitMode autocommitMode,
+  rdbms::Conn &conn, const std::string &vid) {
   try {
     const char *const sql =
       "SELECT "
@@ -334,8 +333,8 @@ common::dataStructures::Tape SqliteCatalogue::selectTape(const rdbms::Stmt::Auto
         "VID = :VID;";
 
     auto stmt = conn.createStmt(sql, autocommitMode);
-    stmt->bindString(":VID", vid);
-    auto rset = stmt->executeQuery();
+    stmt.bindString(":VID", vid);
+    auto rset = stmt.executeQuery();
     if (!rset.next()) {
       throw exception::Exception(std::string("The tape with VID " + vid + " does not exist"));
     }
@@ -407,7 +406,7 @@ void SqliteCatalogue::filesWrittenToTape(const std::set<TapeFileWritten> &events
     threading::MutexLocker locker(m_mutex);
     auto conn = m_connPool.getConn();
 
-    const auto tape = selectTape(rdbms::Stmt::AutocommitMode::ON, conn, firstEvent.vid);
+    const auto tape = selectTape(rdbms::AutocommitMode::ON, conn, firstEvent.vid);
     uint64_t expectedFSeq = tape.lastFSeq + 1;
     uint64_t totalCompressedBytesWritten = 0;
 
@@ -432,11 +431,11 @@ void SqliteCatalogue::filesWrittenToTape(const std::set<TapeFileWritten> &events
     auto lastEventItor = events.cend();
     lastEventItor--;
     const TapeFileWritten &lastEvent = *lastEventItor;
-    updateTape(conn, rdbms::Stmt::AutocommitMode::ON, lastEvent.vid, lastEvent.fSeq, totalCompressedBytesWritten,
+    updateTape(conn, rdbms::AutocommitMode::ON, lastEvent.vid, lastEvent.fSeq, totalCompressedBytesWritten,
       lastEvent.tapeDrive);
 
     for(const auto &event : events) {
-      fileWrittenToTape(rdbms::Stmt::AutocommitMode::ON, conn, event);
+      fileWrittenToTape(rdbms::AutocommitMode::ON, conn, event);
     }
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) +  " failed: " + ex.getMessage().str());
@@ -446,7 +445,7 @@ void SqliteCatalogue::filesWrittenToTape(const std::set<TapeFileWritten> &events
 //------------------------------------------------------------------------------
 // fileWrittenToTape
 //------------------------------------------------------------------------------
-void SqliteCatalogue::fileWrittenToTape(const rdbms::Stmt::AutocommitMode autocommitMode, rdbms::PooledConn &conn,
+void SqliteCatalogue::fileWrittenToTape(const rdbms::AutocommitMode autocommitMode, rdbms::Conn &conn,
   const TapeFileWritten &event) {
   try {
     checkTapeFileWrittenFieldsAreSet(event);
diff --git a/catalogue/SqliteCatalogue.hpp b/catalogue/SqliteCatalogue.hpp
index 86a6f49c970c7507a62dd6dc42a9d601109f6e70..a1d8d966d7f856f39ab7fb123f1deb3026e976ee 100644
--- a/catalogue/SqliteCatalogue.hpp
+++ b/catalogue/SqliteCatalogue.hpp
@@ -116,7 +116,7 @@ protected:
    * @return A unique archive ID that can be used by a new archive file within
    * the catalogue.
    */
-  uint64_t getNextArchiveFileId(rdbms::PooledConn &conn) override;
+  uint64_t getNextArchiveFileId(rdbms::Conn &conn) override;
 
   /**
    * Notifies the catalogue that the specified files have been written to tape.
@@ -134,7 +134,7 @@ private:
    * @param conn The database connection.
    * @param event The tape file written event.
    */
-  void fileWrittenToTape(const rdbms::Stmt::AutocommitMode autocommitMode, rdbms::PooledConn &conn,
+  void fileWrittenToTape(const rdbms::AutocommitMode autocommitMode, rdbms::Conn &conn,
     const TapeFileWritten &event);
 
   /**
@@ -144,7 +144,7 @@ private:
    * @param conn The database connection.
    * @param vid The volume identifier of the tape.
    */
-  common::dataStructures::Tape selectTape(const rdbms::Stmt::AutocommitMode autocommitMode, rdbms::PooledConn &conn,
+  common::dataStructures::Tape selectTape(const rdbms::AutocommitMode autocommitMode, rdbms::Conn &conn,
     const std::string &vid);
 
 }; // class SqliteCatalogue
diff --git a/cta.spec.in b/cta.spec.in
index 647cc3d133616bb6e775b142cb13c5020e2f88a6..ad1893c7d993461cd0f085ba641ee911ea33ae57 100644
--- a/cta.spec.in
+++ b/cta.spec.in
@@ -202,6 +202,7 @@ The shared libraries
 %{_libdir}/libctamessages.so*
 %{_libdir}/libctamessagesutils.so*
 %{_libdir}/libctardbms.so*
+%{_libdir}/libctardbmswrapper.so*
 %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cta/cta-catalogue.conf.example
 
 #CTA-lib installs libraries so we need ldconfig.
@@ -232,6 +233,7 @@ Unit tests and system tests with virtual tape drives
 %{_libdir}/libctainmemorycatalogueunittests.so*
 %{_libdir}/libctaobjectstoreunittests.so*
 %{_libdir}/libctardbmsunittests.so*
+%{_libdir}/libctardbmswrapperunittests.so*
 %{_libdir}/libctaschedulerunittests.so*
 %{_libdir}/libctatapeserverdaemonunittests.so*
 %{_libdir}/libctatapeserverdriveunittests.so*
diff --git a/rdbms/AutoRollback.cpp b/rdbms/AutoRollback.cpp
index d205f54dd0f4238fa09ab28087782628a0b59ad3..9cfb642497c9169ae27cf176f4bdf7e8586636aa 100644
--- a/rdbms/AutoRollback.cpp
+++ b/rdbms/AutoRollback.cpp
@@ -18,7 +18,7 @@
 
 #include "common/exception/Exception.hpp"
 #include "rdbms/AutoRollback.hpp"
-#include "rdbms/PooledConn.hpp"
+#include "rdbms/Conn.hpp"
 
 namespace cta {
 namespace rdbms {
@@ -26,7 +26,7 @@ namespace rdbms {
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-AutoRollback::AutoRollback(PooledConn &conn):
+AutoRollback::AutoRollback(Conn &conn):
   m_cancelled(false),
   m_conn(conn) {
 }
diff --git a/rdbms/AutoRollback.hpp b/rdbms/AutoRollback.hpp
index 155aa4da5efa7a6f6e5347fe924a451fa831ab57..5d7af16d867e4193688143fff9a832914129adf1 100644
--- a/rdbms/AutoRollback.hpp
+++ b/rdbms/AutoRollback.hpp
@@ -24,7 +24,7 @@ namespace rdbms {
 /**
  * Forward declaration.
  */
-class PooledConn;
+class Conn;
 
 /**
  * A class to automatically rollback a database connection when an instance of
@@ -38,7 +38,7 @@ public:
    *
    * @param conn The database connection.
    */
-  AutoRollback(PooledConn &conn);
+  AutoRollback(Conn &conn);
 
   /**
    * Prevent copying.
@@ -72,7 +72,7 @@ private:
   /**
    * The database connection or nullptr if no rollback should take place.
    */
-  PooledConn &m_conn;
+  Conn &m_conn;
 
 }; // class Login
 
diff --git a/rdbms/AutocommitMode.hpp b/rdbms/AutocommitMode.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6d392f1a86d7d5de09e7a5ac385c8227cc61a369
--- /dev/null
+++ b/rdbms/AutocommitMode.hpp
@@ -0,0 +1,33 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+namespace cta {
+namespace rdbms {
+
+/**
+ * A database statement can either have auto commiting mode turned on or off.
+ */
+enum class AutocommitMode {
+  ON,
+  OFF
+};
+
+} // namespace rdbms
+} // namespace cta
diff --git a/rdbms/CMakeLists.txt b/rdbms/CMakeLists.txt
index 3a4143140df1961acd071a2c90e94bfc10c096da..70dea64e10858cfc58ea0711a2194838e10fec42 100644
--- a/rdbms/CMakeLists.txt
+++ b/rdbms/CMakeLists.txt
@@ -15,70 +15,33 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 cmake_minimum_required (VERSION 2.6)
 
+add_subdirectory (wrapper)
+
 set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
 
 find_package (sqlite REQUIRED)
+find_package (oracle-instantclient REQUIRED)
 
-if(OCCI_SUPPORT)
-  find_package (oracle-instantclient REQUIRED)
-  include_directories (${ORACLE-INSTANTCLIENT_INCLUDE_DIRS})
-endif(OCCI_SUPPORT)
+include_directories (${ORACLE-INSTANTCLIENT_INCLUDE_DIRS})
 
 set (RDBMS_LIB_SRC_FILES
   AutoRollback.cpp
-  ColumnNameToIdx.cpp
-  ColumnNameToIdxAndType.cpp
   Conn.cpp
-  ConnFactory.cpp
   ConnPool.cpp
   Login.cpp
   LoginFactory.cpp
+  NullDbValue.cpp
   Rset.cpp
-  RsetImpl.cpp
   Stmt.cpp
-  NullDbValue.cpp
-  ParamNameToIdx.cpp
-  PooledConn.cpp
-  Sqlite.cpp
-  SqliteConn.cpp
-  SqliteConnFactory.cpp
-        SqliteRsetImpl.cpp
-  SqliteStmt.cpp)
-
-if (OCCI_SUPPORT)
-  set (RDBMS_LIB_SRC_FILES
-    ${RDBMS_LIB_SRC_FILES}
-    ConnFactoryFactory.cpp
-    OcciColumn.cpp
-    OcciConn.cpp
-    OcciConnFactory.cpp
-    OcciEnv.cpp
-    OcciEnvSingleton.cpp
-          OcciRsetImpl.cpp
-    OcciStmt.cpp)
-else (OCCI_SUPPORT)
-  set (RDBMS_LIB_SRC_FILES
-    ${RDBMS_LIB_SRC_FILES}
-    ConnFactoryFactory_OCCI_SUPPORT_OFF.cpp)
-endif (OCCI_SUPPORT)
+  StmtPool.cpp)
 
 add_library (ctardbms SHARED
   ${RDBMS_LIB_SRC_FILES})
 set_property(TARGET ctardbms PROPERTY SOVERSION "${CTA_SOVERSION}")
 set_property(TARGET ctardbms PROPERTY   VERSION "${CTA_LIBVERSION}")
 
-set (CTARDBMS_LINK_LIBRARIES
-  ctacommon
-  ${SQLITE_LIBRARIES})
-
-if (OCCI_SUPPORT)
-  set (CTARDBMS_LINK_LIBRARIES
-    ${CTARDBMS_LINK_LIBRARIES}
-    ${ORACLE-INSTANTCLIENT_LIBRARIES})
-endif (OCCI_SUPPORT)
-
 target_link_libraries (ctardbms
-  ${CTARDBMS_LINK_LIBRARIES})
+  ctardbmswrapper)
 
 install (TARGETS ctardbms DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
 
@@ -86,12 +49,7 @@ set(RDBMS_UNIT_TESTS_LIB_SRC_FILES
   ConnPoolTest.cpp
   ConnTest.cpp
   LoginTest.cpp
-  ParamNameToIdxTest.cpp
-  SqliteStmtTest.cpp)
-
-if (OCCI_SUPPORT)
-  list (APPEND RDBMS_UNIT_TESTS_LIB_SRC_FILES OcciColumnTest.cpp)
-endif (OCCI_SUPPORT)
+  StmtPoolTest.cpp)
 
 add_library (ctardbmsunittests SHARED
   ${RDBMS_UNIT_TESTS_LIB_SRC_FILES})
diff --git a/rdbms/Conn.cpp b/rdbms/Conn.cpp
index f70c14b855d45147253aa655e85826fc8f7cd47e..9e92793189701796c1f536c039f6c666dd2da311 100644
--- a/rdbms/Conn.cpp
+++ b/rdbms/Conn.cpp
@@ -17,18 +17,72 @@
  */
 
 #include "common/exception/Exception.hpp"
-#include "common/utils/utils.hpp"
+#include "common/utils/utils.cpp"
+#include "rdbms/ConnPool.hpp"
 #include "rdbms/Conn.hpp"
 
-#include <string>
-
 namespace cta {
 namespace rdbms {
 
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+Conn::Conn(std::unique_ptr<ConnAndStmts> connAndStmts, ConnPool *pool):
+  m_connAndStmts(std::move(connAndStmts)),
+  m_pool(pool) {
+}
+
+//------------------------------------------------------------------------------
+// move constructor
+//------------------------------------------------------------------------------
+Conn::Conn(Conn &&other):
+  m_connAndStmts(std::move(other.m_connAndStmts)),
+  m_pool(other.m_pool) {
+  other.m_pool = nullptr;
+}
+
 //------------------------------------------------------------------------------
 // destructor
 //------------------------------------------------------------------------------
-Conn::~Conn() throw() {
+Conn::~Conn() noexcept {
+  try {
+    // If this smart database connection currently points to a database connection then return it back to its pool
+    if(nullptr != m_pool && nullptr != m_connAndStmts) {
+      m_pool->returnConn(std::move(m_connAndStmts));
+    }
+  } catch(...) {
+  }
+}
+
+//------------------------------------------------------------------------------
+// operator=
+//------------------------------------------------------------------------------
+Conn &Conn::operator=(Conn &&rhs) {
+  // If the database connection is not the one already owned
+  if(rhs.m_connAndStmts != m_connAndStmts) {
+    // If this smart database connection currently points to a database connection then return it back to its pool
+    if(nullptr != m_pool && nullptr != m_connAndStmts && nullptr != m_connAndStmts->conn) {
+      m_pool->returnConn(std::move(m_connAndStmts));
+    }
+
+    // Take ownership of the new database connection
+    m_connAndStmts = std::move(rhs.m_connAndStmts);
+    m_pool = rhs.m_pool;
+
+    rhs.m_pool = nullptr;
+  }
+  return *this;
+}
+
+//------------------------------------------------------------------------------
+// createStmt
+//------------------------------------------------------------------------------
+Stmt Conn::createStmt(const std::string &sql, const AutocommitMode autocommitMode) {
+  if(nullptr != m_connAndStmts && nullptr != m_connAndStmts->conn) {
+    return m_connAndStmts->stmtPool->getStmt(*m_connAndStmts->conn, sql, autocommitMode);
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Conn does not contain a connection");
+  }
 }
 
 //------------------------------------------------------------------------------
@@ -46,7 +100,7 @@ void Conn::executeNonQueries(const std::string &sqlStmts) {
       searchPos = findResult + 1;
 
       if(0 < sqlStmt.size()) { // Ignore empty statements
-        executeNonQuery(sqlStmt, rdbms::Stmt::AutocommitMode::ON);
+        executeNonQuery(sqlStmt, AutocommitMode::ON);
       }
     }
 
@@ -58,14 +112,69 @@ void Conn::executeNonQueries(const std::string &sqlStmts) {
 //------------------------------------------------------------------------------
 // executeNonQuery
 //------------------------------------------------------------------------------
-void Conn::executeNonQuery(const std::string &sql, const Stmt::AutocommitMode autocommitMode) {
+void Conn::executeNonQuery(const std::string &sql, const AutocommitMode autocommitMode) {
   try {
     auto stmt = createStmt(sql, autocommitMode);
-    stmt->executeNonQuery();
+    stmt.executeNonQuery();
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.what());
   }
 }
 
+//------------------------------------------------------------------------------
+// commit
+//------------------------------------------------------------------------------
+void Conn::commit() {
+  if(nullptr != m_connAndStmts && nullptr != m_connAndStmts->conn) {
+    m_connAndStmts->conn->commit();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Conn does not contain a connection");
+  }
+}
+
+//------------------------------------------------------------------------------
+// commit
+//------------------------------------------------------------------------------
+void Conn::rollback() {
+  if(nullptr != m_connAndStmts && nullptr != m_connAndStmts->conn) {
+    m_connAndStmts->conn->rollback();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Conn does not contain a connection");
+  }
+} 
+
+//------------------------------------------------------------------------------
+// getTableNames
+//------------------------------------------------------------------------------
+std::list<std::string> Conn::getTableNames() {
+  if(nullptr != m_connAndStmts && nullptr != m_connAndStmts->conn) {
+    return m_connAndStmts->conn->getTableNames();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Conn does not contain a connection");
+  }
+}
+
+//------------------------------------------------------------------------------
+// isOpen
+//------------------------------------------------------------------------------
+bool Conn::isOpen() const {
+  if(nullptr != m_connAndStmts && nullptr != m_connAndStmts->conn) {
+    return m_connAndStmts->conn->isOpen();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Conn does not contain a connection");
+  }
+}
+
+//------------------------------------------------------------------------------
+// getSequenceNames
+//------------------------------------------------------------------------------
+std::list<std::string> Conn::getSequenceNames() {
+  if(nullptr != m_connAndStmts && nullptr != m_connAndStmts->conn) {
+    return m_connAndStmts->conn->getSequenceNames();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Conn does not contain a connection");
+  }
+}
+
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/Conn.hpp b/rdbms/Conn.hpp
index ac2740b90956e986c5efae66ac0031d32867b290..3d66a4fcc49832aec54d6c985db9adb183c89840 100644
--- a/rdbms/Conn.hpp
+++ b/rdbms/Conn.hpp
@@ -18,31 +18,65 @@
 
 #pragma once
 
-#include "Stmt.hpp"
+#include "rdbms/ConnAndStmts.hpp"
+#include "rdbms/Stmt.hpp"
 
-#include <atomic>
 #include <list>
 #include <memory>
-#include <string>
 
 namespace cta {
 namespace rdbms {
 
+class ConnPool;
+
 /**
- * Abstract class that specifies the interface to a database connection.
+ * A smart database connection that will automatically return the underlying
+ * database connection to its parent connection pool when it goes out of scope.
  */
 class Conn {
 public:
 
+  /**
+   * Constructor.
+   *
+   * @param connAndStmts The database connection and its pool of prepared
+   * statements.
+   * @param pool The database connection pool to which the connection
+   * should be returned.
+   */
+  Conn(std::unique_ptr<ConnAndStmts> connAndStmts, ConnPool *const pool);
+
+  /**
+   * Deletion of the copy constructor.
+   */
+  Conn(Conn &) = delete;
+
+  /**
+   * Move constructor.
+   *
+   * @param other The other object.
+   */
+  Conn(Conn &&other);
+
   /**
    * Destructor.
+   *
+   * Returns the database connection back to its pool.
    */
-  virtual ~Conn() throw() = 0;
+  ~Conn() noexcept;
 
   /**
-   * Idempotent close() method.  The destructor calls this method.
+   * Deletion of the copy assignment operator.
    */
-  virtual void close() = 0;
+  Conn &operator=(const Conn &) = delete;
+
+  /**
+   * Move assignment operator.
+   *
+   * @param rhs The object on the right-hand side of the operator.
+   * @return This object.
+   */
+  Conn &operator=(Conn &&rhs);
 
   /**
    * Creates a prepared statement.
@@ -51,7 +85,7 @@ public:
    * @param autocommitMode The autocommit mode of the statement.
    * @return The prepared statement.
    */
-  virtual std::unique_ptr<Stmt> createStmt(const std::string &sql, const Stmt::AutocommitMode autocommitMode) = 0;
+  Stmt createStmt(const std::string &sql, const AutocommitMode autocommitMode);
 
   /**
    * Convenience method that parses the specified string of multiple SQL
@@ -73,17 +107,17 @@ public:
    * @param sql The SQL statement.
    * @param autocommitMode The autocommit mode of the statement.
    */
-  void executeNonQuery(const std::string &sql, const Stmt::AutocommitMode autocommitMode);
+  void executeNonQuery(const std::string &sql, const AutocommitMode autocommitMode);
 
   /**
    * Commits the current transaction.
    */
-  virtual void commit() = 0;
+  void commit();
 
   /**
    * Rolls back the current transaction.
    */
-  virtual void rollback() = 0;
+  void rollback();
 
   /**
    * Returns the names of all the tables in the database schema in alphabetical
@@ -92,12 +126,36 @@ public:
    * @return The names of all the tables in the database schema in alphabetical
    * order.
    */
-  virtual std::list<std::string> getTableNames() = 0;
+  std::list<std::string> getTableNames();
 
   /**
    * Returns true if this connection is open.
    */
-  virtual bool isOpen() const = 0;
+  bool isOpen() const;
+
+  /**
+   * Returns the names of all the sequences in the database schema in
+   * alphabetical order.
+   *
+   * If the underlying database technologies does not supported sequences then
+   * this method simply returns an empty list.
+   *
+   * @return The names of all the sequences in the database schema in
+   * alphabetical order.
+   */
+  std::list<std::string> getSequenceNames();
+
+private:
+
+  /**
+   * The database connection and its pool of prepared statements.
+   */
+  std::unique_ptr<ConnAndStmts> m_connAndStmts;
+
+  /**
+   * The database connection pool to which the m_conn should be returned.
+   */
+  ConnPool *m_pool;
 
 }; // class Conn
 
diff --git a/rdbms/ConnAndStmts.hpp b/rdbms/ConnAndStmts.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b5aa5d20dd84043fb70e86493a0be1b38b99cbdd
--- /dev/null
+++ b/rdbms/ConnAndStmts.hpp
@@ -0,0 +1,98 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "rdbms/StmtPool.hpp"
+#include "rdbms/wrapper/Conn.hpp"
+
+#include <iostream>
+#include <memory>
+
+namespace cta {
+namespace rdbms {
+
+/**
+ * Class to enforce prepared statements are destroyed before their corresponding
+ * database connection.
+ */
+struct ConnAndStmts {
+
+  /**
+   * Constructor.
+   */
+  ConnAndStmts() {
+  }
+
+  /**
+   * Deletion of the copy constructor.
+   */
+  ConnAndStmts(ConnAndStmts &) = delete;
+
+  /**
+   * Move constructor.
+   *
+   * @param other The other object.
+   */
+  ConnAndStmts(ConnAndStmts &&other):
+    conn(std::move(other.conn)),
+    stmtPool(std::move(other.stmtPool)) {
+  }
+
+  /**
+   * Equality operator.
+   *
+   * @param rhs The object on the right hand side of the operator.
+   * @return True if equal.
+   */
+  bool operator==(const ConnAndStmts &rhs) {
+    return conn.get() == rhs.conn.get();
+  }
+
+  /**
+   * Inequality operator.
+   *
+   * @param rhs The object on the right hand side of the operator.
+   * @return True if not equal.
+   */
+  bool operator!=(const ConnAndStmts &rhs) {
+    return !operator==(rhs);
+  }
+
+  /**
+   * The database connection.
+   *
+   * The database connection must be destroyed after all of its corresponding
+   * prepared statements.  This means the conn member-variable must be declared
+   * before the stmtPool member-variable.
+   */
+  std::unique_ptr<wrapper::Conn> conn;
+
+  /**
+   * Pool of prepared statements.
+   *
+   * The prepared statements must be destroyed before their corresponding
+   * database connection.  This means the stmtPool member-variable must be
+   * declared after the conn member-variable.
+   */
+  std::unique_ptr<StmtPool> stmtPool;
+
+}; // class ConnAndStmts
+
+} // namespace rdbms
+} // namespace cta
diff --git a/rdbms/ConnPool.cpp b/rdbms/ConnPool.cpp
index 0be866bc728dcbbd7a2f72c103516a07bce4bc48..f8f80d56acdbf61434bc1a25f90043bb8c28eea5 100644
--- a/rdbms/ConnPool.cpp
+++ b/rdbms/ConnPool.cpp
@@ -17,8 +17,10 @@
  */
 
 #include "common/exception/Exception.hpp"
+#include "common/make_unique.hpp"
 #include "common/threading/MutexLocker.hpp"
 #include "rdbms/ConnPool.hpp"
+#include "rdbms/wrapper/ConnFactoryFactory.hpp"
 
 #include <memory>
 
@@ -28,15 +30,10 @@ namespace rdbms {
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-ConnPool::ConnPool(ConnFactory &connFactory, const uint64_t maxNbConns):
-  m_connFactory(connFactory),
+ConnPool::ConnPool(const Login &login, const uint64_t maxNbConns):
+  m_connFactory(wrapper::ConnFactoryFactory::create(login)),
   m_maxNbConns(maxNbConns),
-  m_nbConnsOnLoan(0) {
-  try {
-    createConns(m_maxNbConns);
-  } catch(exception::Exception &ex) {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
-  }
+  m_nbConnsOnLoan(0){
 }
 
 //------------------------------------------------------------------------------
@@ -45,7 +42,10 @@ ConnPool::ConnPool(ConnFactory &connFactory, const uint64_t maxNbConns):
 void ConnPool::createConns(const uint64_t nbConns) {
   try {
     for(uint64_t i = 0; i < nbConns; i++) {
-      m_conns.push_back(m_connFactory.create());
+      auto connAndStmts = cta::make_unique<ConnAndStmts>();
+      connAndStmts->conn = m_connFactory->create();
+      connAndStmts->stmtPool = cta::make_unique<StmtPool>();
+      m_connsAndStmts.push_back(std::move(connAndStmts));
     }
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -55,42 +55,50 @@ void ConnPool::createConns(const uint64_t nbConns) {
 //------------------------------------------------------------------------------
 // getConn
 //------------------------------------------------------------------------------
-PooledConn ConnPool::getConn() {
-  threading::MutexLocker locker(m_connsMutex);
+Conn ConnPool::getConn() {
+  threading::MutexLocker locker(m_connsAndStmtsMutex);
 
-  while(m_conns.size() == 0 && m_nbConnsOnLoan == m_maxNbConns) {
-    m_connsCv.wait(locker);
+  while(m_connsAndStmts.size() == 0 && m_nbConnsOnLoan == m_maxNbConns) {
+    m_connsAndStmtsCv.wait(locker);
   }
 
-  if(m_conns.size() == 0) {
-    m_conns.push_back(m_connFactory.create());
+  if(m_connsAndStmts.size() == 0) {
+    auto connAndStmts = cta::make_unique<ConnAndStmts>();
+    connAndStmts->conn = m_connFactory->create();
+    connAndStmts->stmtPool = cta::make_unique<StmtPool>();
+    m_connsAndStmts.push_back(std::move(connAndStmts));
   }
 
-  std::unique_ptr<Conn> conn = std::move(m_conns.front());
-  m_conns.pop_front();
+  std::unique_ptr<ConnAndStmts> connAndStmts = std::move(m_connsAndStmts.front());
+  m_connsAndStmts.pop_front();
   m_nbConnsOnLoan++;
-  if(conn->isOpen()) {
-    return PooledConn(std::move(conn), this);
+  if(connAndStmts->conn->isOpen()) {
+    return Conn(std::move(connAndStmts), this);
   } else {
-    return PooledConn(m_connFactory.create(), this);
+    auto newConnAndStmts = cta::make_unique<ConnAndStmts>();
+    newConnAndStmts->conn = m_connFactory->create();
+    newConnAndStmts->stmtPool = cta::make_unique<StmtPool>();
+    return Conn(std::move(newConnAndStmts), this);
   }
 }
 
 //------------------------------------------------------------------------------
 // returnConn
 //------------------------------------------------------------------------------
-void ConnPool::returnConn(std::unique_ptr<Conn> conn) {
+void ConnPool::returnConn(std::unique_ptr<ConnAndStmts> connAndStmts) {
   try {
     // If the connection is open
-    if(conn->isOpen()) {
+    if(connAndStmts->conn->isOpen()) {
 
       // Try to commit the connection and put it back in the pool
       try {
-        conn->commit();
+        connAndStmts->conn->commit();
       } catch(...) {
-        // If the commit failed then close the connection
+        // If the commit failed then destroy any prepare statements and then
+        // close the connection
         try {
-          conn->close();
+          connAndStmts->stmtPool->clear();
+          connAndStmts->conn->close();
         } catch(...) {
           // Ignore any exceptions
         }
@@ -99,25 +107,25 @@ void ConnPool::returnConn(std::unique_ptr<Conn> conn) {
         // connection, if there is one, has been lost.  Delete all the connections
         // currently in the pool because their underlying TCP/IP connections may
         // also have been lost.
-        threading::MutexLocker locker(m_connsMutex);
-        while(!m_conns.empty()) {
-          m_conns.pop_front();
+        threading::MutexLocker locker(m_connsAndStmtsMutex);
+        while(!m_connsAndStmts.empty()) {
+          m_connsAndStmts.pop_front();
         }
         if(0 == m_nbConnsOnLoan) {
           throw exception::Exception("Would have reached -1 connections on loan");
         }
         m_nbConnsOnLoan--;
-        m_connsCv.signal();
+        m_connsAndStmtsCv.signal();
         return;
       }
 
-      threading::MutexLocker locker(m_connsMutex);
+      threading::MutexLocker locker(m_connsAndStmtsMutex);
       if(0 == m_nbConnsOnLoan) {
         throw exception::Exception("Would have reached -1 connections on loan");
       }
       m_nbConnsOnLoan--;
-      m_conns.push_back(std::move(conn));
-      m_connsCv.signal();
+      m_connsAndStmts.push_back(std::move(connAndStmts));
+      m_connsAndStmtsCv.signal();
 
     // Else the connection is closed
     } else {
@@ -126,15 +134,15 @@ void ConnPool::returnConn(std::unique_ptr<Conn> conn) {
       // connection, if there is one, has been lost.  Delete all the connections
       // currently in the pool because their underlying TCP/IP connections may
       // also have been lost.
-      threading::MutexLocker locker(m_connsMutex);
-      while(!m_conns.empty()) {
-        m_conns.pop_front();
+      threading::MutexLocker locker(m_connsAndStmtsMutex);
+      while(!m_connsAndStmts.empty()) {
+        m_connsAndStmts.pop_front();
       }
       if(0 == m_nbConnsOnLoan) {
         throw exception::Exception("Would have reached -1 connections on loan");
       }
       m_nbConnsOnLoan--;
-      m_connsCv.signal();
+      m_connsAndStmtsCv.signal();
     }
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
diff --git a/rdbms/ConnPool.hpp b/rdbms/ConnPool.hpp
index 98917197e54506ab671f18b06b04c6876ad879d2..76344d0238f1b5ff99e9d2f65239691010723587 100644
--- a/rdbms/ConnPool.hpp
+++ b/rdbms/ConnPool.hpp
@@ -20,9 +20,10 @@
 
 #include "common/threading/CondVar.hpp"
 #include "common/threading/Mutex.hpp"
+#include "rdbms/ConnAndStmts.hpp"
 #include "rdbms/Conn.hpp"
-#include "rdbms/ConnFactory.hpp"
-#include "rdbms/PooledConn.hpp"
+#include "rdbms/wrapper/Conn.hpp"
+#include "rdbms/wrapper/ConnFactory.hpp"
 
 #include <list>
 #include <memory>
@@ -30,6 +31,8 @@
 namespace cta {
 namespace rdbms {
 
+class Login;
+
 /**
  * A pool of database connections.
  */
@@ -39,11 +42,12 @@ public:
   /**
    * Constructor.
    *
-   * @param connFactory The database connection factory.
+   * @param login The database login details to be used to create new
+   * connections.
    * @param maxNbConns The maximum number of database connections within the
    * pool.
    */
-  ConnPool(ConnFactory &connFactory, const uint64_t maxNbConns);
+  ConnPool(const Login &login, const uint64_t maxNbConns);
 
   /**
    * Takes a connection from the pool.
@@ -54,11 +58,11 @@ public:
    *
    * @return A connection from the pool.
    */
-  PooledConn getConn();
+  Conn getConn();
 
 private:
 
-  friend PooledConn;
+  friend Conn;
 
   /**
    * If the specified database connection is open, then this method calls
@@ -69,14 +73,14 @@ private:
    *
    * A closed connection is reopened when it is pulled from the pool.
    *
-   * @param conn The connection to be commited and returned to the pool.
+   * @param connAndStmts The connection to be commited and returned to the pool.
    */
-  void returnConn(std::unique_ptr<Conn> conn);
+  void returnConn(std::unique_ptr<ConnAndStmts> connAndStmts);
 
   /**
    * The database connection factory.
    */
-  ConnFactory &m_connFactory;
+  std::unique_ptr<wrapper::ConnFactory> m_connFactory;
 
   /**
    * The maximum number of database connections within the pool.
@@ -91,18 +95,18 @@ private:
   /**
    * Mutex used to serialize access to the database connections within the pool.
    */
-  threading::Mutex m_connsMutex;
+  threading::Mutex m_connsAndStmtsMutex;
 
   /**
    * Condition variable used by threads returning connections to the pool to
    * notify threads waiting for connections.
    */
-  threading::CondVar m_connsCv;
+  threading::CondVar m_connsAndStmtsCv;
 
   /**
    * The database connections within the pool.
    */
-  std::list< std::unique_ptr<Conn> > m_conns;
+  std::list<std::unique_ptr<ConnAndStmts> > m_connsAndStmts;
 
   /**
    * Creates the specified number of database connections with the pool.
diff --git a/rdbms/ConnPoolTest.cpp b/rdbms/ConnPoolTest.cpp
index e3a4b9d7c0870525a4f457e76d825a2c2eb35ccd..93d2d617abb1aee6edac2c8095db7e4a447202af 100644
--- a/rdbms/ConnPoolTest.cpp
+++ b/rdbms/ConnPoolTest.cpp
@@ -17,11 +17,10 @@
  */
 
 #include "common/exception/Exception.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
 #include "rdbms/ConnPool.hpp"
+#include "rdbms/Login.hpp"
 
 #include <gtest/gtest.h>
-#include <sstream>
 
 namespace unitTests {
 
@@ -39,24 +38,22 @@ TEST_F(cta_rdbms_ConnPoolTest, getPooledConn) {
   using namespace cta::rdbms;
 
   const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
-  auto connFactory = ConnFactoryFactory::create(login);
   const uint64_t nbConns = 2;
-  ConnPool pool(*connFactory, nbConns);
+  ConnPool pool(login, nbConns);
 
-  PooledConn conn = pool.getConn();
+  Conn conn = pool.getConn();
 }
 
 TEST_F(cta_rdbms_ConnPoolTest, assignment) {
   using namespace cta::rdbms;
 
   const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
-  auto connFactory = ConnFactoryFactory::create(login);
   const uint64_t nbConns = 2;
-  ConnPool pool(*connFactory, nbConns);
+  ConnPool pool(login, nbConns);
 
-  PooledConn conn = pool.getConn();
+  Conn conn = pool.getConn();
 
-  PooledConn conn2(nullptr, nullptr);
+  Conn conn2(nullptr, nullptr);
 
   conn2 = pool.getConn();
 }
@@ -65,13 +62,12 @@ TEST_F(cta_rdbms_ConnPoolTest, moveConstructor) {
   using namespace cta::rdbms;
 
   const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
-  auto connFactory = ConnFactoryFactory::create(login);
   const uint64_t nbConns = 2;
-  ConnPool pool(*connFactory, nbConns);
+  ConnPool pool(login, nbConns);
 
-  PooledConn conn = pool.getConn();
+  Conn conn = pool.getConn();
 
-  PooledConn conn2(std::move(conn));
+  Conn conn2(std::move(conn));
 }
 
 } // namespace unitTests
diff --git a/rdbms/ConnTest.cpp b/rdbms/ConnTest.cpp
index 0d0a953b915884c09493bf3fba165df61c0d7cef..322e893ee37c7d1c8f60d8985fc7777db804fea7 100644
--- a/rdbms/ConnTest.cpp
+++ b/rdbms/ConnTest.cpp
@@ -17,11 +17,10 @@
  */
 
 #include "common/exception/Exception.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
 #include "rdbms/ConnPool.hpp"
+#include "rdbms/Login.hpp"
 
 #include <gtest/gtest.h>
-#include <sstream>
 
 namespace unitTests {
 
@@ -35,6 +34,45 @@ protected:
   }
 };
 
+TEST_F(cta_rdbms_ConnTest, createTableInMemoryDatabase_executeNonQuery) {
+  using namespace cta::rdbms;
+
+  const std::string sql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER)";
+
+  {
+    const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+    const uint64_t maxNbConns = 1;
+    ConnPool connPool(login, maxNbConns);
+    auto conn = connPool.getConn();
+
+    ASSERT_TRUE(conn.getTableNames().empty());
+
+    conn.executeNonQuery(sql, AutocommitMode::ON);
+
+    ASSERT_EQ(1, conn.getTableNames().size());
+  }
+}
+
+TEST_F(cta_rdbms_ConnTest, createTableInMemoryDatabase_executeNonQueries) {
+  using namespace cta::rdbms;
+
+  const std::string sql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER);";
+
+  // First in-memory database
+  {
+    const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+    const uint64_t maxNbConns = 1;
+    ConnPool connPool(login, maxNbConns);
+    auto conn = connPool.getConn();
+
+    ASSERT_TRUE(conn.getTableNames().empty());
+
+    conn.executeNonQueries(sql);
+
+    ASSERT_EQ(1, conn.getTableNames().size());
+  }
+}
+
 TEST_F(cta_rdbms_ConnTest, createSameTableInTwoSeparateInMemoryDatabases_executeNonQuery) {
   using namespace cta::rdbms;
 
@@ -43,27 +81,29 @@ TEST_F(cta_rdbms_ConnTest, createSameTableInTwoSeparateInMemoryDatabases_execute
   // First in-memory database
   {
     const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
-    auto connFactory = ConnFactoryFactory::create(login);
-    auto conn = connFactory->create();
+    const uint64_t maxNbConns = 1;
+    ConnPool connPool(login, maxNbConns);
+    auto conn = connPool.getConn();
 
-    ASSERT_TRUE(conn->getTableNames().empty());
+    ASSERT_TRUE(conn.getTableNames().empty());
 
-    conn->executeNonQuery(sql, Stmt::AutocommitMode::ON);
+    conn.executeNonQuery(sql, AutocommitMode::ON);
 
-    ASSERT_EQ(1, conn->getTableNames().size());
+    ASSERT_EQ(1, conn.getTableNames().size());
   }
 
   // Second in-memory database
   {
     const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
-    auto connFactory = ConnFactoryFactory::create(login);
-    auto conn = connFactory->create();
+    const uint64_t maxNbConns = 1;
+    ConnPool connPool(login, maxNbConns);
+    auto conn = connPool.getConn();
 
-    ASSERT_TRUE(conn->getTableNames().empty());
+    ASSERT_TRUE(conn.getTableNames().empty());
 
-    conn->executeNonQuery(sql, Stmt::AutocommitMode::ON);
+    conn.executeNonQuery(sql, AutocommitMode::ON);
 
-    ASSERT_EQ(1, conn->getTableNames().size());
+    ASSERT_EQ(1, conn.getTableNames().size());
   }
 }
 
@@ -75,27 +115,29 @@ TEST_F(cta_rdbms_ConnTest, createSameTableInTwoSeparateInMemoryDatabases_execute
   // First in-memory database
   {
     const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
-    auto connFactory = ConnFactoryFactory::create(login);
-    auto conn = connFactory->create();
+    const uint64_t maxNbConns = 1;
+    ConnPool connPool(login, maxNbConns);
+    auto conn = connPool.getConn();
 
-    ASSERT_TRUE(conn->getTableNames().empty());
+    ASSERT_TRUE(conn.getTableNames().empty());
 
-    conn->executeNonQueries(sql);
+    conn.executeNonQueries(sql);
 
-    ASSERT_EQ(1, conn->getTableNames().size());
+    ASSERT_EQ(1, conn.getTableNames().size());
   }
 
   // Second in-memory database
   {
     const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
-    auto connFactory = ConnFactoryFactory::create(login);
-    auto conn = connFactory->create();
+    const uint64_t maxNbConns = 1;
+    ConnPool connPool(login, maxNbConns);
+    auto conn = connPool.getConn();
 
-    ASSERT_TRUE(conn->getTableNames().empty());
+    ASSERT_TRUE(conn.getTableNames().empty());
 
-    conn->executeNonQueries(sql);
+    conn.executeNonQueries(sql);
 
-    ASSERT_EQ(1, conn->getTableNames().size());
+    ASSERT_EQ(1, conn.getTableNames().size());
   }
 }
 
diff --git a/rdbms/Login.cpp b/rdbms/Login.cpp
index 25faa7389a7caac4c8eb750b1b7798757b5346d7..ee024f732e95b35f9d3eac1ef8d37cc08dfd53c2 100644
--- a/rdbms/Login.cpp
+++ b/rdbms/Login.cpp
@@ -16,9 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "Login.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/utils/utils.hpp"
+#include "Login.hpp"
 
 #include <fstream>
 
@@ -153,5 +153,5 @@ Login Login::parseOracleUserPassAndDb(const std::string &userPassAndDb) {
   return Login(DBTYPE_ORACLE, user, pass, db);
 }
 
-} // namesapce catalogue
+} // namespace catalogue
 } // namespace cta
diff --git a/rdbms/LoginFactory.cpp b/rdbms/LoginFactory.cpp
index d1acb5436bae67310aa4e78344ddfd5d3dda91db..b5eeb17b990a2d390736f43c766716c5c48ca7d4 100644
--- a/rdbms/LoginFactory.cpp
+++ b/rdbms/LoginFactory.cpp
@@ -16,7 +16,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "LoginFactory.hpp"
+#include "rdbms/LoginFactory.hpp"
 
 namespace cta {
 namespace rdbms {
diff --git a/rdbms/LoginFactory.hpp b/rdbms/LoginFactory.hpp
index 1959a134907aab0fde556784c5b5dc6897b4796c..7795d803301937f89dce0487a84065418a5ac791 100644
--- a/rdbms/LoginFactory.hpp
+++ b/rdbms/LoginFactory.hpp
@@ -18,7 +18,7 @@
 
 #pragma once
 
-#include "Login.hpp"
+#include "rdbms/Login.hpp"
 
 namespace cta {
 namespace rdbms {
diff --git a/rdbms/LoginTest.cpp b/rdbms/LoginTest.cpp
index a7a9a3460320dd072a9de8a260726e7b57a0ee64..e4a5430195afa74a2a1ba00ca2cb3e700147b27a 100644
--- a/rdbms/LoginTest.cpp
+++ b/rdbms/LoginTest.cpp
@@ -16,8 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "Login.hpp"
 #include "common/exception/Exception.hpp"
+#include "rdbms/Login.hpp"
 
 #include <gtest/gtest.h>
 #include <sstream>
diff --git a/rdbms/PooledConn.cpp b/rdbms/PooledConn.cpp
deleted file mode 100644
index dec6e9d9d2a9a5c01427dd9749ff896f0e8cc0cc..0000000000000000000000000000000000000000
--- a/rdbms/PooledConn.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * The CERN Tape Archive (CTA) project
- * Copyright (C) 2015  CERN
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * 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
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "common/exception/Exception.hpp"
-#include "rdbms/ConnPool.hpp"
-#include "rdbms/PooledConn.hpp"
-
-namespace cta {
-namespace rdbms {
-
-//------------------------------------------------------------------------------
-// constructor
-//------------------------------------------------------------------------------
-PooledConn::PooledConn(std::unique_ptr<Conn> conn, ConnPool *pool):
-  m_conn(conn.release()),
-  m_pool(pool) {
-}
-
-//------------------------------------------------------------------------------
-// move constructor
-//------------------------------------------------------------------------------
-PooledConn::PooledConn(PooledConn &&other):
-  m_conn(std::move(other.m_conn)),
-  m_pool(other.m_pool) {
-  other.m_pool = nullptr;
-}
-
-//------------------------------------------------------------------------------
-// destructor
-//------------------------------------------------------------------------------
-PooledConn::~PooledConn() noexcept {
-  try {
-    // If this smart database connection currently points to a database connection then return it back to its pool
-    if(nullptr != m_pool && nullptr != m_conn) {
-      m_pool->returnConn(std::move(m_conn));
-    }
-  } catch(...) {
-  }
-}
-
-//------------------------------------------------------------------------------
-// operator=
-//------------------------------------------------------------------------------
-PooledConn &PooledConn::operator=(PooledConn &&rhs) {
-  // If the database connection is not the one already owned
-  if(rhs.m_conn != m_conn) {
-    // If this smart database connection currently points to a database connection then return it back to its pool
-    if(nullptr != m_pool && nullptr != m_conn) {
-      m_pool->returnConn(std::move(m_conn));
-    }
-
-    // Take ownership of the new database connection
-    m_conn = std::move(rhs.m_conn);
-    m_pool = rhs.m_pool;
-
-    rhs.m_pool = nullptr;
-  }
-  return *this;
-}
-
-//------------------------------------------------------------------------------
-// createStmt
-//------------------------------------------------------------------------------
-std::unique_ptr<Stmt> PooledConn::createStmt(const std::string &sql,
-  const Stmt::AutocommitMode autocommitMode) {
-  if(nullptr != m_conn) {
-    return m_conn->createStmt(sql, autocommitMode);
-  } else {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: PooledConn does not contain a connection");
-  }
-}
-
-//------------------------------------------------------------------------------
-// executeNonQueries
-//------------------------------------------------------------------------------
-void PooledConn::executeNonQueries(const std::string &sqlStmts) {
-  if(nullptr != m_conn) {
-    return m_conn->executeNonQueries(sqlStmts);
-  } else {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: PooledConn does not contain a connection");
-  }
-}
-
-//------------------------------------------------------------------------------
-// executeNonQuery
-//------------------------------------------------------------------------------
-void PooledConn::executeNonQuery(const std::string &sql, const Stmt::AutocommitMode autocommitMode) {
-  if(nullptr != m_conn) {
-    return m_conn->executeNonQuery(sql, autocommitMode);
-  } else {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: PooledConn does not contain a connection");
-  }
-}
-
-//------------------------------------------------------------------------------
-// commit
-//------------------------------------------------------------------------------
-void PooledConn::commit() {
-  if(nullptr != m_conn) {
-    m_conn->commit();
-  } else {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: PooledConn does not contain a connection");
-  }
-}
-
-//------------------------------------------------------------------------------
-// commit
-//------------------------------------------------------------------------------
-void PooledConn::rollback() {
-  if(nullptr != m_conn) {
-    m_conn->rollback();
-  } else {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: PooledConn does not contain a connection");
-  }
-} 
-
-//------------------------------------------------------------------------------
-// getTableNames
-//------------------------------------------------------------------------------
-std::list<std::string> PooledConn::getTableNames() {
-  if(nullptr != m_conn) {
-    return m_conn->getTableNames();
-  } else {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: PooledConn does not contain a connection");
-  }
-}
-
-//------------------------------------------------------------------------------
-// isOpen
-//------------------------------------------------------------------------------
-bool PooledConn::isOpen() const {
-  if(nullptr != m_conn) {
-    return m_conn->isOpen();
-  } else {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: PooledConn does not contain a connection");
-  }
-}
-
-} // namespace rdbms
-} // namespace cta
diff --git a/rdbms/PooledConn.hpp b/rdbms/PooledConn.hpp
deleted file mode 100644
index 94c26c0d06a038fb8945e4f2be378ebd10f7bfd4..0000000000000000000000000000000000000000
--- a/rdbms/PooledConn.hpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * The CERN Tape Archive (CTA) project
- * Copyright (C) 2015  CERN
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * 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
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "rdbms/Stmt.hpp"
-
-#include <list>
-#include <memory>
-
-namespace cta {
-namespace rdbms {
-
-class Conn;
-
-class ConnPool;
-
-/**
- * A smart database connection that will automatically return the underlying
- * database connection to its parent connection pool when it goes out of scope.
- */
-class PooledConn {
-public:
-
-  /**
-   * Constructor.
-   *
-   * @param conn The database connection.
-   * @param pool The database connection pool to which the connection
-   * should be returned.
-   */
-  PooledConn(std::unique_ptr<Conn> conn, ConnPool *const pool);
-
-  /**
-   * Deletion of the copy constructor.
-   */
-  PooledConn(PooledConn &) = delete;
-
-  /**
-   * Move constructor.
-   *
-   * @param other The other object.
-   */
-  PooledConn(PooledConn &&other);
-
-  /**
-   * Destructor.
-   *
-   * Returns the database connection back to its pool.
-   */
-  ~PooledConn() noexcept;
-
-  /**
-   * Deletion of the copy assignment operator.
-   */
-  PooledConn &operator=(const PooledConn &) = delete;
-
-  /**
-   * Move assignment operator.
-   *
-   * @param rhs The object on the right-hand side of the operator.
-   * @return This object.
-   */
-  PooledConn &operator=(PooledConn &&rhs);
-
-  /**
-   * Creates a prepared statement.
-   *
-   * @param sql The SQL statement.
-   * @param autocommitMode The autocommit mode of the statement.
-   * @return The prepared statement.
-   */
-  std::unique_ptr<Stmt> createStmt(const std::string &sql, const Stmt::AutocommitMode autocommitMode);
-
-  /**
-   * Convenience method that parses the specified string of multiple SQL
-   * statements and calls executeNonQuery() for each individual statement found.
-   *
-   * Please note that each statement should be a non-query terminated by a
-   * semicolon and that each individual statement will be executed with
-   * autocommit ON.
-   *
-   * @param sqlStmts The SQL statements to be executed.
-   * @param autocommitMode The autocommit mode of the statement.
-   */
-  void executeNonQueries(const std::string &sqlStmts);
-
-  /**
-   * Convenience method that wraps Conn::createStmt() followed by
-   * Stmt::executeNonQuery().
-   *
-   * @param sql The SQL statement.
-   * @param autocommitMode The autocommit mode of the statement.
-   */
-  void executeNonQuery(const std::string &sql, const Stmt::AutocommitMode autocommitMode);
-
-  /**
-   * Commits the current transaction.
-   */
-  void commit();
-
-  /**
-   * Rolls back the current transaction.
-   */
-  void rollback();
-
-  /**
-   * Returns the names of all the tables in the database schema in alphabetical
-   * order.
-   *
-   * @return The names of all the tables in the database schema in alphabetical
-   * order.
-   */
-  std::list<std::string> getTableNames();
-
-  /**
-   * Returns true if this connection is open.
-   */
-  bool isOpen() const;
-
-private:
-
-  /**
-   * The database connection.
-   */
-  std::unique_ptr<Conn> m_conn;
-
-  /**
-   * The database connection pool to which the m_conn should be returned.
-   */
-  ConnPool *m_pool;
-
-}; // class PooledConn
-
-} // namespace rdbms
-} // namespace cta
diff --git a/rdbms/Rset.cpp b/rdbms/Rset.cpp
index 4b18232f1c03f788e089288eb393ec3fdd6b46f0..df390212897e5ed0f2e7aa5f4f647764bb9f76ac 100644
--- a/rdbms/Rset.cpp
+++ b/rdbms/Rset.cpp
@@ -16,10 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "Rset.hpp"
-#include "RsetImpl.hpp"
-#include "NullDbValue.hpp"
-
+#include "rdbms/NullDbValue.hpp"
+#include "rdbms/Rset.hpp"
+#include "rdbms/wrapper/Rset.hpp"
 
 namespace cta {
 namespace rdbms {
@@ -34,9 +33,9 @@ Rset::Rset():
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-Rset::Rset(RsetImpl *const impl):
-  m_impl(impl) {
-  if(nullptr == impl) {
+Rset::Rset(std::unique_ptr<wrapper::Rset> impl):
+  m_impl(std::move(impl)) {
+  if(nullptr == m_impl.get()) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: Pointer to implementation object is null");
   }
 }
@@ -45,23 +44,16 @@ Rset::Rset(RsetImpl *const impl):
 // constructor
 //------------------------------------------------------------------------------
 Rset::Rset(Rset &&other):
-  m_impl(other.m_impl) {
-  other.m_impl = nullptr;
-}
-
-//------------------------------------------------------------------------------
-// destructor
-//------------------------------------------------------------------------------
-Rset::~Rset() {
-  delete m_impl;
+  m_impl(std::move(other.m_impl)) {
 }
 
 //------------------------------------------------------------------------------
 // operator=
 //------------------------------------------------------------------------------
 Rset &Rset::operator=(Rset &&rhs) {
-  m_impl = rhs.m_impl;
-  rhs.m_impl = nullptr;
+  if(m_impl != rhs.m_impl) {
+    m_impl = std::move(rhs.m_impl);
+  }
   return *this;
 }
 
diff --git a/rdbms/Rset.hpp b/rdbms/Rset.hpp
index caa23d5443e3eb6424da58381df32093b1daf5b0..b8c9d1c4e9b1dd14e39bd0d2e06dec8997beff35 100644
--- a/rdbms/Rset.hpp
+++ b/rdbms/Rset.hpp
@@ -20,16 +20,16 @@
 
 #include "common/optional.hpp"
 
+#include <memory>
 #include <stdint.h>
 #include <string>
 
 namespace cta {
 namespace rdbms {
 
-/**
- * Forward declarartion.
- */
-class RsetImpl;
+namespace wrapper {
+  class Rset;
+}
 
 /**
  * A wrapper around an object that iterators over a result set from the
@@ -50,7 +50,7 @@ public:
    *
    * @param impl The object actually implementing this result set.
    */
-  Rset(RsetImpl *const impl);
+  Rset(std::unique_ptr<wrapper::Rset> impl);
 
   /**
    * Deletion of copy constructor.
@@ -64,11 +64,6 @@ public:
    */
   Rset(Rset &&other);
 
-  /**
-   * Destructor.
-   */
-  ~Rset() throw();
-
   /**
    * Deletion of copy assignment.
    */
@@ -176,7 +171,7 @@ private:
   /**
    * The object actually implementing this result set.
    */
-  RsetImpl *m_impl;
+  std::unique_ptr<wrapper::Rset> m_impl;
 
 }; // class Rset
 
diff --git a/rdbms/Stmt.cpp b/rdbms/Stmt.cpp
index 00a4e4f17b2a98befb262422b31fe99db4694d7e..34eac226fb333327990dc6024344896c9c576410 100644
--- a/rdbms/Stmt.cpp
+++ b/rdbms/Stmt.cpp
@@ -16,70 +16,203 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "Stmt.hpp"
+#include "common/exception/Exception.hpp"
+#include "rdbms/Stmt.hpp"
+#include "rdbms/StmtPool.hpp"
+#include "rdbms/wrapper/Stmt.hpp"
 
 namespace cta {
 namespace rdbms {
 
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 // constructor
-//------------------------------------------------------------------------------
-Stmt::Stmt(const std::string &sql, const AutocommitMode autocommitMode):
-  m_sql(sql),
-  m_autoCommitMode(autocommitMode),
-  m_paramNameToIdx(sql) {
+//-----------------------------------------------------------------------------
+Stmt::Stmt():
+  m_stmtPool(nullptr) {
 }
 
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// constructor
+//-----------------------------------------------------------------------------
+Stmt::Stmt(std::unique_ptr<wrapper::Stmt> stmt, StmtPool &stmtPool):
+  m_stmt(std::move(stmt)),
+  m_stmtPool(&stmtPool) {
+}
+
+//-----------------------------------------------------------------------------
+// constructor
+//-----------------------------------------------------------------------------
+Stmt::Stmt(Stmt &&other):
+  m_stmt(std::move(other.m_stmt)),
+  m_stmtPool(other.m_stmtPool){
+}
+
+//-----------------------------------------------------------------------------
 // destructor
-//------------------------------------------------------------------------------
-Stmt::~Stmt() throw() {
+//-----------------------------------------------------------------------------
+Stmt::~Stmt() noexcept {
+  try {
+    // If this smart prepared statement currently points to a prepared
+    // statement then return it back to its pool
+    if(nullptr != m_stmtPool && nullptr != m_stmt) {
+      m_stmtPool->returnStmt(std::move(m_stmt));
+    }
+  } catch(...) {
+    // Ignore any exceptions
+  }
 }
 
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// operator=
+//-----------------------------------------------------------------------------
+Stmt &Stmt::operator=(Stmt &&rhs) {
+  // If the cached statement is not already owned
+  if(rhs.m_stmt != m_stmt) {
+    // If this smart cached statement already points to cached statement, then
+    // return it back to its pool
+    if(nullptr != m_stmt && nullptr != m_stmtPool) {
+      m_stmtPool->returnStmt(std::move(m_stmt));
+    }
+
+    // Take ownership of the new cached statement
+    m_stmt = std::move(rhs.m_stmt);
+    m_stmtPool = rhs.m_stmtPool;
+
+    rhs.m_stmtPool = nullptr;
+  }
+
+  return *this;
+}
+
+//-----------------------------------------------------------------------------
 // getSql
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 const std::string &Stmt::getSql() const {
-  return m_sql;
+  if(nullptr != m_stmt) {
+    return m_stmt->getSql();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
 }
 
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 // getParamIdx
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 uint32_t Stmt::getParamIdx(const std::string &paramName) const {
-  return m_paramNameToIdx.getIdx(paramName);
+  if(nullptr != m_stmt) {
+    return m_stmt->getParamIdx(paramName);
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
 }
 
-//------------------------------------------------------------------------------
-// getSqlForException
-//------------------------------------------------------------------------------
-std::string Stmt::getSqlForException() const {
-  if(m_sql.length() <= c_maxSqlLenInExceptions) {
-    return m_sql;
+//-----------------------------------------------------------------------------
+// bindUint64
+//-----------------------------------------------------------------------------
+void Stmt::bindUint64(const std::string &paramName, const uint64_t paramValue) {
+  if(nullptr != m_stmt) {
+    return m_stmt->bindUint64(paramName, paramValue);
   } else {
-    if(c_maxSqlLenInExceptions >= 3) {
-      return m_sql.substr(0, c_maxSqlLenInExceptions - 3) + "...";
-    } else {
-      return std::string("..."). substr(0, c_maxSqlLenInExceptions);
-    }
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
+}
+
+//-----------------------------------------------------------------------------
+// bindOptionalUint64
+//-----------------------------------------------------------------------------
+void Stmt::bindOptionalUint64(const std::string &paramName, const optional<uint64_t> &paramValue) {
+  if(nullptr != m_stmt) {
+    return m_stmt->bindOptionalUint64(paramName, paramValue);
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
   }
 }
 
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 // bindBool
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 void Stmt::bindBool(const std::string &paramName, const bool paramValue) {
-  bindOptionalBool(paramName, paramValue);
+  if(nullptr != m_stmt) {
+    return m_stmt->bindBool(paramName, paramValue);
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
 }
 
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 // bindOptionalBool
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 void Stmt::bindOptionalBool(const std::string &paramName, const optional<bool> &paramValue) {
-  if(paramValue) {
-    bindOptionalUint64(paramName, paramValue.value() ? 1 : 0);
+  if(nullptr != m_stmt) {
+    return m_stmt->bindOptionalBool(paramName, paramValue);
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
+}
+
+//-----------------------------------------------------------------------------
+// bindString
+//-----------------------------------------------------------------------------
+void Stmt::bindString(const std::string &paramName, const std::string &paramValue) {
+  if(nullptr != m_stmt) {
+    return m_stmt->bindString(paramName, paramValue);
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
+}
+
+//-----------------------------------------------------------------------------
+// bindOptionalString
+//-----------------------------------------------------------------------------
+void Stmt::bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue) {
+  if(nullptr != m_stmt) {
+    return m_stmt->bindOptionalString(paramName, paramValue);
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
+}
+
+//-----------------------------------------------------------------------------
+// executeQuery
+//-----------------------------------------------------------------------------
+Rset Stmt::executeQuery() {
+  if(nullptr != m_stmt) {
+    return Rset(m_stmt->executeQuery());
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
+}
+
+//-----------------------------------------------------------------------------
+// executeNonQuery
+//-----------------------------------------------------------------------------
+void Stmt::executeNonQuery() {
+  if(nullptr != m_stmt) {
+    return m_stmt->executeNonQuery();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
+}
+
+//-----------------------------------------------------------------------------
+// getNbAffectedRows
+//-----------------------------------------------------------------------------
+uint64_t Stmt::getNbAffectedRows() const {
+  if(nullptr != m_stmt) {
+    return m_stmt->getNbAffectedRows();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
+  }
+}
+
+//-----------------------------------------------------------------------------
+// getStmt
+//-----------------------------------------------------------------------------
+wrapper::Stmt &Stmt::getStmt() {
+  if(nullptr != m_stmt) {
+    return *m_stmt;
   } else {
-    bindOptionalUint64(paramName, nullopt);
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement");
   }
 }
 
diff --git a/rdbms/Stmt.hpp b/rdbms/Stmt.hpp
index 8aa49c5c4dea4626b31ef547a8e6a201f2b55e51..899e2f83e6b88ec0df9ca9ec1435a02f73e188c6 100644
--- a/rdbms/Stmt.hpp
+++ b/rdbms/Stmt.hpp
@@ -18,50 +18,42 @@
 
 #pragma once
 
-#include "common/optional.hpp"
-#include "rdbms/ParamNameToIdx.hpp"
 #include "rdbms/Rset.hpp"
+#include "common/optional.hpp"
 
+#include <list>
 #include <memory>
-#include <stdint.h>
-#include <string>
+#include <mutex>
 
 namespace cta {
 namespace rdbms {
 
+namespace wrapper {
+  class Stmt;
+}
+
+class StmtPool;
+
 /**
- * Abstract class specifying the interface to a database statement.
+ * A smart database statement that will automatically return the underlying
+ * database statement to its parent database connection when it goes out of
+ * scope.
  */
 class Stmt {
 public:
 
-  /**
-   * A statement can either have auto commiting mode turned on or off.
-   */
-  enum class AutocommitMode {
-    ON,
-    OFF
-  };
-
   /**
    * Constructor.
-   *
-   * @param sql The SQL statement.
-   * @param autocommitMode The autocommit mode of the statement.
    */
-  Stmt(const std::string &sql, const AutocommitMode autocommitMode);
+  Stmt();
 
   /**
-   * Returns the autocommit mode of teh statement.
+   * Constructor.
    *
-   * @return The autocommit mode of teh statement.
+   * @param stmt The database statement.
+   * @param stmtPool The database statement pool to which the m_stmt should be returned.
    */
-  AutocommitMode getAutoCommitMode() const noexcept;
-
-  /**
-   * Destructor.
-   */
-  virtual ~Stmt() throw() = 0;
+  Stmt(std::unique_ptr<wrapper::Stmt> stmt, StmtPool &stmtPool);
 
   /**
    * Deletion of the copy constructor.
@@ -69,24 +61,31 @@ public:
   Stmt(Stmt &) = delete;
 
   /**
-   * Deletion of the move constructor.
+   * Move constructor.
+   *
+   * @param other The other object.
    */
-  Stmt(Stmt &&) = delete;
+  Stmt(Stmt &&other);
 
   /**
-   * Deletion of the copy assignment operator.
+   * Destructor.
+   *
+   * Returns the database statement back to its connection.
    */
-  Stmt &operator=(const Stmt &) = delete;
+  ~Stmt() noexcept;
 
   /**
-   * Deletion of the move assignment operator.
+   * Deletion of the copy assignment operator.
    */
-  Stmt &operator=(Stmt &&) = delete;
+  Stmt &operator=(const Stmt &) = delete;
 
   /**
-   * Idempotent close() method.  The destructor calls this method.
+   * Move assignment operator.
+   *
+   * @param rhs The object on the right-hand side of the operator.
+   * @return This object.
    */
-  virtual void close() = 0;
+  Stmt &operator=(Stmt &&rhs);
 
   /**
    * Returns the SQL statement.
@@ -109,7 +108,7 @@ public:
    * @param paramName The name of the parameter.
    * @param paramValue The value to be bound.
    */
-  virtual void bindUint64(const std::string &paramName, const uint64_t paramValue) = 0;
+  void bindUint64(const std::string &paramName, const uint64_t paramValue);
 
   /**
    * Binds an SQL parameter.
@@ -117,7 +116,7 @@ public:
    * @param paramName The name of the parameter.
    * @param paramValue The value to be bound.
    */
-  virtual void bindOptionalUint64(const std::string &paramName, const optional<uint64_t> &paramValue) = 0;
+  void bindOptionalUint64(const std::string &paramName, const optional<uint64_t> &paramValue);
 
   /**
    * Binds an SQL parameter.
@@ -145,7 +144,7 @@ public:
    * @param paramName The name of the parameter.
    * @param paramValue The value to be bound.
    */ 
-  virtual void bindString(const std::string &paramName, const std::string &paramValue) = 0;
+  void bindString(const std::string &paramName, const std::string &paramValue);
 
   /** 
    * Binds an SQL parameter of type optional-string.
@@ -157,19 +156,19 @@ public:
    * @param paramName The name of the parameter.
    * @param paramValue The value to be bound.
    */ 
-  virtual void bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue) = 0;
+  void bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue);
 
   /**
    *  Executes the statement and returns the result set.
    *
    *  @return The result set.
    */
-  virtual Rset executeQuery() = 0;
+  Rset executeQuery();
 
   /**
    * Executes the statement.
    */
-  virtual void executeNonQuery() = 0;
+  void executeNonQuery();
 
   /**
    * Returns the number of rows affected by the last execution of this
@@ -177,43 +176,25 @@ public:
    *
    * @return The number of affected rows.
    */
-  virtual uint64_t getNbAffectedRows() const = 0;
-
-protected:
-
-  /**
-   * The maximum length an SQL statement can have in exception error message.
-   */
-  const uint32_t c_maxSqlLenInExceptions = 80;
+  uint64_t getNbAffectedRows() const;
 
   /**
-   * Returns the SQL string to be used in an exception message.  The string
-   * will be clipped at a maxmum of c_maxSqlLenInExceptions characters.  If the
-   * string is actually clipped then the three last characters will be an
-   * replaced by an ellipsis of three dots, in other word "...".  These 3
-   * characters will indicate to the reader of the exception message that the
-   * SQL statement has been clipped.
-   *
-   * @return The SQL string to be used in an exception message.
+   * Returns a reference to the underlying statement object that is not pool
+   * aware.
    */
-  std::string getSqlForException() const;
+  wrapper::Stmt &getStmt();
 
 private:
 
   /**
-   * The SQL statement.
-   */
-  std::string m_sql;
-
-  /**
-   * The autocommit mode of the statement.
+   * The database statement.
    */
-  AutocommitMode m_autoCommitMode;
+  std::unique_ptr<wrapper::Stmt> m_stmt;
 
   /**
-   * Map from SQL parameter name to parameter index.
+   * The database statement pool to which the m_stmt should be returned.
    */
-  ParamNameToIdx m_paramNameToIdx;
+  StmtPool *m_stmtPool;
 
 }; // class Stmt
 
diff --git a/rdbms/StmtPool.cpp b/rdbms/StmtPool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..537efae8d32cadf20ec58c7f8fd24fc640306c6c
--- /dev/null
+++ b/rdbms/StmtPool.cpp
@@ -0,0 +1,93 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/exception/Exception.hpp"
+#include "common/threading/MutexLocker.hpp"
+#include "rdbms/wrapper/Conn.hpp"
+#include "rdbms/StmtPool.hpp"
+
+namespace cta {
+namespace rdbms {
+
+//------------------------------------------------------------------------------
+// getStmt
+//------------------------------------------------------------------------------
+Stmt StmtPool::getStmt(wrapper::Conn &conn, const std::string &sql, const AutocommitMode autocommitMode) {
+  const CachedStmtKey key(sql, autocommitMode);
+
+  threading::MutexLocker locker(m_stmtsMutex);
+
+  auto itor = m_stmts.find(key);
+
+  // If there is no prepared statement in the cache
+  if(itor == m_stmts.end()) {
+    auto stmt = conn.createStmt(sql, autocommitMode);
+    return Stmt(std::move(stmt), *this);
+  } else {
+    auto &stmtList = itor->second;
+    if(stmtList.empty()) {
+      throw exception::Exception(std::string(__FUNCTION__) + " failed: Unexpected empty list of cached statements");
+    }
+    auto stmt = std::move(stmtList.front());
+    stmtList.pop_front();
+
+    // If there are no more cached prepared statements then remove the empty list from the cache
+    if(stmtList.empty()) {
+      m_stmts.erase(itor);
+    }
+
+    return Stmt(std::move(stmt), *this);
+  }
+}
+
+//------------------------------------------------------------------------------
+// getNbStmts
+//------------------------------------------------------------------------------
+uint64_t StmtPool::getNbStmts() const {
+  threading::MutexLocker locker(m_stmtsMutex);
+
+  uint64_t nbStmts = 0;
+  for(const auto &maplet: m_stmts) {
+    auto &stmtList = maplet.second;
+    nbStmts += stmtList.size();
+  }
+  return nbStmts;
+}
+
+//------------------------------------------------------------------------------
+// returnStmt
+//------------------------------------------------------------------------------
+void StmtPool::returnStmt(std::unique_ptr<wrapper::Stmt> stmt) {
+  threading::MutexLocker locker(m_stmtsMutex);
+
+  const CachedStmtKey key(stmt->getSql(), stmt->getAutocommitMode());
+
+  stmt->clear();
+
+  m_stmts[key].push_back(std::move(stmt));
+}
+
+//------------------------------------------------------------------------------
+// clear
+//------------------------------------------------------------------------------
+void StmtPool::clear() {
+  m_stmts.clear();
+}
+
+} // namespace rdbms
+} // namespace cta
diff --git a/rdbms/StmtPool.hpp b/rdbms/StmtPool.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..04c8ce6cd53a1226df5f8077e764dc5f96a87d7f
--- /dev/null
+++ b/rdbms/StmtPool.hpp
@@ -0,0 +1,132 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "common/threading/CondVar.hpp"
+#include "common/threading/Mutex.hpp"
+#include "rdbms/AutocommitMode.hpp"
+#include "rdbms/Stmt.hpp"
+
+#include <iostream>
+#include <list>
+#include <map>
+#include <memory>
+#include <stdint.h>
+
+namespace cta {
+namespace rdbms {
+
+namespace wrapper {
+  class Conn;
+  class Stmt;
+}
+
+/**
+ * A pool of prepared database statements.
+ */
+class StmtPool {
+public:
+
+  /**
+   * Takes a database statement from the pool if one is present else a new
+   * statement will be prepared.
+   *
+   * @param conn The database connection to which the database statements
+   * @param sql The SQL statement.
+   * @param autocommitMode The autocommit mode of the statement.
+   * @return The prepared statement.
+   */
+  Stmt getStmt(wrapper::Conn &conn, const std::string &sql, const AutocommitMode autocommitMode);
+
+  /**
+   * Returns the number of cached statements currently in the pool.
+   *
+   * @return The number of cached statements currently in the pool.
+   */
+  uint64_t getNbStmts() const;
+
+  /**
+   * Clears the pooll of prepared statements which includes destroying those
+   * statements.
+   */
+  void clear();
+
+private:
+
+  friend Stmt;
+
+  /**
+   * Returns the specified statement to the pool.
+   *
+   * @param stmt The database statement to be returned to the pool.
+   */
+  void returnStmt(std::unique_ptr<wrapper::Stmt> stmt);
+
+  /**
+   * Mutex used to serialize access to the database statements within the pool.
+   */
+  mutable threading::Mutex m_stmtsMutex;
+
+  /**
+   * Key used to lookup prepares statements within the cache.
+   */
+  struct CachedStmtKey {
+    /**
+     * The SQL of the cached statement.
+     */
+    std::string sql;
+
+    /**
+     * The autocommit mode of the cached statement.
+     */
+    const AutocommitMode autocommitMode;
+
+    /**
+     * Constructor.
+     *
+     * @param s The SQL of the cached statement.
+     * @param a The autocommit mode of the cached statement.
+     */
+    CachedStmtKey(const std::string &s, const AutocommitMode a): sql(s), autocommitMode(a) {
+    }
+
+    /**
+     * Less than operator.
+     */
+    bool operator<(const CachedStmtKey &rhs) const {
+      if(sql != rhs.sql) {
+        return sql < rhs.sql;
+      } else {
+        return autocommitMode < rhs.autocommitMode;
+      }
+    }
+  };
+
+  /**
+   * The cached database statements.
+   *
+   * Please note that for a single key there maybe more than one cached
+   * statement, hence the map to list of statements.
+   */
+  std::map<CachedStmtKey, std::list< std::unique_ptr<wrapper::Stmt> > > m_stmts;
+
+}; // class StmtPool
+
+} // namespace rdbms
+} // namespace cta
diff --git a/rdbms/StmtPoolTest.cpp b/rdbms/StmtPoolTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..00bbc303804729772cf44d924776e09588de4800
--- /dev/null
+++ b/rdbms/StmtPoolTest.cpp
@@ -0,0 +1,234 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/exception/Exception.hpp"
+#include "rdbms/ConnPool.hpp"
+#include "rdbms/wrapper/ConnFactoryFactory.hpp"
+
+#include <gtest/gtest.h>
+#include <sstream>
+
+namespace unitTests {
+
+class cta_rdbms_StmtPoolTest : public ::testing::Test {
+protected:
+
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+  }
+};
+
+TEST_F(cta_rdbms_StmtPoolTest, getStmt) {
+  using namespace cta::rdbms;
+
+  const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+  auto connFactory = wrapper::ConnFactoryFactory::create(login);
+  auto conn = connFactory->create();
+  const std::string sql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER)";
+  StmtPool pool;
+  ASSERT_EQ(0, pool.getNbStmts());
+  {
+    auto stmt = pool.getStmt(*conn, sql, AutocommitMode::ON);
+    ASSERT_EQ(0, pool.getNbStmts());
+  }
+  ASSERT_EQ(1, pool.getNbStmts());
+}
+
+TEST_F(cta_rdbms_StmtPoolTest, moveAssignment) {
+  using namespace cta::rdbms;
+
+  const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+  auto connFactory = wrapper::ConnFactoryFactory::create(login);
+  auto conn = connFactory->create();
+  const std::string sql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER)";
+  StmtPool pool;
+  ASSERT_EQ(0, pool.getNbStmts());
+  {
+    Stmt stmt1 = pool.getStmt(*conn, sql, AutocommitMode::ON);
+    Stmt stmt2;
+    stmt2 = std::move(stmt1);
+    ASSERT_EQ(0, pool.getNbStmts());
+  }
+  ASSERT_EQ(1, pool.getNbStmts());
+}
+
+TEST_F(cta_rdbms_StmtPoolTest, moveConstructor) {
+  using namespace cta::rdbms;
+
+  const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+  auto connFactory = wrapper::ConnFactoryFactory::create(login);
+  auto conn = connFactory->create();
+  const std::string sql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER)";
+  StmtPool pool;
+  ASSERT_EQ(0, pool.getNbStmts());
+  {
+    Stmt stmt1 = pool.getStmt(*conn, sql, AutocommitMode::ON);
+    Stmt stmt2(std::move(stmt1));
+    ASSERT_EQ(0, pool.getNbStmts());
+  }
+  ASSERT_EQ(1, pool.getNbStmts());
+}
+
+TEST_F(cta_rdbms_StmtPoolTest, createSameTableInTwoSeparateInMemoryDatabases) {
+  using namespace cta::rdbms;
+
+  const std::string createTableSql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER)";
+  const std::string selectTableNamesSql =
+       "SELECT "
+        "NAME AS NAME "
+      "FROM "
+        "SQLITE_MASTER "
+      "WHERE "
+        "TYPE = 'table' "
+      "ORDER BY "
+        "NAME;";
+
+  // First in-memory database
+  {
+    const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+    auto connFactory = wrapper::ConnFactoryFactory::create(login);
+    auto conn = connFactory->create();
+
+    StmtPool pool;
+
+    {
+      Stmt stmt = pool.getStmt(*conn, selectTableNamesSql, AutocommitMode::ON);
+      auto rset = stmt.executeQuery();
+      std::list<std::string> names;
+      while(rset.next()) {
+        names.push_back(rset.columnString("NAME"));
+      }
+      ASSERT_EQ(0, names.size());
+    }
+
+    {
+      Stmt stmt = pool.getStmt(*conn, createTableSql, AutocommitMode::ON);
+      stmt.executeNonQuery();
+    }
+
+    {
+      Stmt stmt = pool.getStmt(*conn, selectTableNamesSql, AutocommitMode::ON);
+      auto rset = stmt.executeQuery();
+      std::list<std::string> names;
+      while(rset.next()) {
+        names.push_back(rset.columnString("NAME"));
+      }
+      ASSERT_EQ(1, names.size());
+      ASSERT_EQ("POOLED_STMT_TEST", names.front());
+    }
+  }
+
+  // Second in-memory database
+  {
+    const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+    auto connFactory = wrapper::ConnFactoryFactory::create(login);
+    auto conn = connFactory->create();
+
+    StmtPool pool;
+    {
+      Stmt stmt = pool.getStmt(*conn, selectTableNamesSql, AutocommitMode::ON);
+      auto rset = stmt.executeQuery();
+      std::list<std::string> names;
+      while(rset.next()) {
+        names.push_back(rset.columnString("NAME"));
+      }
+      ASSERT_EQ(0, names.size());
+    }
+
+    {
+      Stmt stmt = pool.getStmt(*conn, createTableSql, AutocommitMode::ON);
+      stmt.executeNonQuery();
+    }
+
+    {
+      Stmt stmt = pool.getStmt(*conn, selectTableNamesSql, AutocommitMode::ON);
+      auto rset = stmt.executeQuery();
+      std::list<std::string> names;
+      while(rset.next()) {
+        names.push_back(rset.columnString("NAME"));
+      }
+      ASSERT_EQ(1, names.size());
+      ASSERT_EQ("POOLED_STMT_TEST", names.front());
+    }
+  }
+}
+
+TEST_F(cta_rdbms_StmtPoolTest, createSameTableInTwoSeparateInMemoryDatabases_getTableNames) {
+  using namespace cta::rdbms;
+
+  const std::string createTableSql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER)";
+
+  // First in-memory database
+  {
+    const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+    auto connFactory = wrapper::ConnFactoryFactory::create(login);
+    auto conn = connFactory->create();
+
+    StmtPool pool;
+
+    ASSERT_TRUE(conn->getTableNames().empty());
+
+    {
+      Stmt stmt = pool.getStmt(*conn, createTableSql, AutocommitMode::ON);
+      stmt.executeNonQuery();
+    }
+
+    ASSERT_EQ(1, conn->getTableNames().size());
+  }
+
+  // Second in-memory database
+  {
+    const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+    auto connFactory = wrapper::ConnFactoryFactory::create(login);
+    auto conn = connFactory->create();
+
+    StmtPool pool;
+
+    ASSERT_TRUE(conn->getTableNames().empty());
+
+    {
+      Stmt stmt = pool.getStmt(*conn, createTableSql, AutocommitMode::ON);
+      stmt.executeNonQuery();
+    }
+
+    ASSERT_EQ(1, conn->getTableNames().size());
+  }
+}
+
+TEST_F(cta_rdbms_StmtPoolTest, sameSqlTwoCachedStmts) {
+  using namespace cta::rdbms;
+
+  const Login login(Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+  auto connFactory = wrapper::ConnFactoryFactory::create(login);
+  auto conn = connFactory->create();
+  const std::string sql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER)";
+  StmtPool pool;
+  ASSERT_EQ(0, pool.getNbStmts());
+  {
+    Stmt stmt1 = pool.getStmt(*conn, sql, AutocommitMode::ON);
+    Stmt stmt2 = pool.getStmt(*conn, sql, AutocommitMode::ON);
+    ASSERT_EQ(0, pool.getNbStmts());
+  }
+  ASSERT_EQ(2, pool.getNbStmts());
+}
+
+
+
+} // namespace unitTests
diff --git a/rdbms/wrapper/CMakeLists.txt b/rdbms/wrapper/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3777fa7068df4f6c9d899be92a2f5032285217ad
--- /dev/null
+++ b/rdbms/wrapper/CMakeLists.txt
@@ -0,0 +1,76 @@
+# The CERN Tape Archive (CTA) project
+# Copyright (C) 2015  CERN
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# 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
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+cmake_minimum_required (VERSION 2.6)
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
+
+find_package (sqlite REQUIRED)
+
+find_package (oracle-instantclient REQUIRED)
+include_directories (${ORACLE-INSTANTCLIENT_INCLUDE_DIRS})
+
+set (RDBMS_WRAPPER_LIB_SRC_FILES
+  ColumnNameToIdx.cpp
+  ColumnNameToIdxAndType.cpp
+  Conn.cpp
+  ConnFactory.cpp
+  Rset.cpp
+  Stmt.cpp
+  ParamNameToIdx.cpp
+  Sqlite.cpp
+  SqliteConn.cpp
+  SqliteConnFactory.cpp
+  SqliteRset.cpp
+  SqliteStmt.cpp)
+
+set (RDBMS_WRAPPER_LIB_SRC_FILES
+  ${RDBMS_WRAPPER_LIB_SRC_FILES}
+  ConnFactoryFactory.cpp
+  OcciColumn.cpp
+  OcciConn.cpp
+  OcciConnFactory.cpp
+  OcciEnv.cpp
+  OcciEnvSingleton.cpp
+  OcciRset.cpp
+  OcciStmt.cpp)
+
+add_library (ctardbmswrapper SHARED
+  ${RDBMS_WRAPPER_LIB_SRC_FILES})
+set_property(TARGET ctardbmswrapper PROPERTY SOVERSION "${CTA_SOVERSION}")
+set_property(TARGET ctardbmswrapper PROPERTY   VERSION "${CTA_LIBVERSION}")
+
+target_link_libraries (ctardbmswrapper
+  ctacommon
+  ${SQLITE_LIBRARIES}
+  ${ORACLE-INSTANTCLIENT_LIBRARIES})
+
+install (TARGETS ctardbmswrapper DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
+
+set(RDBMS_UNIT_TESTS_LIB_SRC_FILES
+  ConnTest.cpp
+  OcciColumnTest.cpp
+  ParamNameToIdxTest.cpp
+  SqliteStmtTest.cpp)
+
+add_library (ctardbmswrapperunittests SHARED
+  ${RDBMS_UNIT_TESTS_LIB_SRC_FILES})
+set_property(TARGET ctardbmswrapperunittests PROPERTY SOVERSION "${CTA_SOVERSION}")
+set_property(TARGET ctardbmswrapperunittests PROPERTY   VERSION "${CTA_LIBVERSION}")
+
+target_link_libraries (ctardbmswrapperunittests
+  ctacatalogue)
+
+install(TARGETS ctardbmswrapperunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
diff --git a/rdbms/ColumnNameToIdx.cpp b/rdbms/wrapper/ColumnNameToIdx.cpp
similarity index 95%
rename from rdbms/ColumnNameToIdx.cpp
rename to rdbms/wrapper/ColumnNameToIdx.cpp
index c0f7fb5c685a0307aa4ec5a1d53849cdf0edde8c..bae20d1512f4a1507d94b663930fd470ca7ca7e0 100644
--- a/rdbms/ColumnNameToIdx.cpp
+++ b/rdbms/wrapper/ColumnNameToIdx.cpp
@@ -16,11 +16,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "ColumnNameToIdx.hpp"
 #include "common/exception/Exception.hpp"
+#include "rdbms/wrapper/ColumnNameToIdx.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // add
@@ -50,5 +51,6 @@ bool ColumnNameToIdx::empty() const {
   return m_nameToIdx.empty();
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ColumnNameToIdx.hpp b/rdbms/wrapper/ColumnNameToIdx.hpp
similarity index 97%
rename from rdbms/ColumnNameToIdx.hpp
rename to rdbms/wrapper/ColumnNameToIdx.hpp
index 511beb6bec235100ec3fe789ce90ecc9a53a7d42..698964a14ef7be3a40ca0ed78da421a7b22f6361 100644
--- a/rdbms/ColumnNameToIdx.hpp
+++ b/rdbms/wrapper/ColumnNameToIdx.hpp
@@ -23,6 +23,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A map from column name to column index.
@@ -67,5 +68,6 @@ private:
 
 }; // class ColumnNameToIdx
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ColumnNameToIdxAndType.cpp b/rdbms/wrapper/ColumnNameToIdxAndType.cpp
similarity index 96%
rename from rdbms/ColumnNameToIdxAndType.cpp
rename to rdbms/wrapper/ColumnNameToIdxAndType.cpp
index 09f4842e1dface3674df5cb6913576f49f6f9124..5f02829aeac4d8082fe225f8a5c86ecf3a832527 100644
--- a/rdbms/ColumnNameToIdxAndType.cpp
+++ b/rdbms/wrapper/ColumnNameToIdxAndType.cpp
@@ -16,11 +16,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "ColumnNameToIdxAndType.hpp"
 #include "common/exception/Exception.hpp"
+#include "rdbms/wrapper/ColumnNameToIdxAndType.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // add
@@ -57,5 +58,6 @@ void ColumnNameToIdxAndType::clear() {
   m_nameToIdxAndType.clear();
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ColumnNameToIdxAndType.hpp b/rdbms/wrapper/ColumnNameToIdxAndType.hpp
similarity index 98%
rename from rdbms/ColumnNameToIdxAndType.hpp
rename to rdbms/wrapper/ColumnNameToIdxAndType.hpp
index d65f29a6c2d9a8b4ddce9a3a025ddb3ebae5c623..8c9478ef0f9f8fc1352d69c5a6b38dba6fe3af25 100644
--- a/rdbms/ColumnNameToIdxAndType.hpp
+++ b/rdbms/wrapper/ColumnNameToIdxAndType.hpp
@@ -21,6 +21,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A map from column name to column index and type.
@@ -96,5 +97,6 @@ private:
 
 }; // class ColumnNameToIdxAndType
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ConnFactoryFactory_OCCI_SUPPORT_OFF.cpp b/rdbms/wrapper/Conn.cpp
similarity index 50%
rename from rdbms/ConnFactoryFactory_OCCI_SUPPORT_OFF.cpp
rename to rdbms/wrapper/Conn.cpp
index 99c5c9acec0e5501dc4263278f43a8e16b39a627..f3af845a966ffbaaa0fea242a96f2216ee7e7802 100644
--- a/rdbms/ConnFactoryFactory_OCCI_SUPPORT_OFF.cpp
+++ b/rdbms/wrapper/Conn.cpp
@@ -17,38 +17,19 @@
  */
 
 #include "common/exception/Exception.hpp"
-#include "common/make_unique.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
-#include "rdbms/SqliteConnFactory.hpp"
+#include "common/utils/utils.hpp"
+#include "rdbms/wrapper/Conn.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
-// create
+// destructor
 //------------------------------------------------------------------------------
-std::unique_ptr<ConnFactory> ConnFactoryFactory::create(const Login &login) {
-  try {
-    switch(login.dbType) {
-    case rdbms::Login::DBTYPE_IN_MEMORY:
-      return cta::make_unique<SqliteConnFactory>(":memory:");
-    case rdbms::Login::DBTYPE_ORACLE:
-      throw exception::Exception("OCCI support disabled at compile time");
-    case rdbms::Login::DBTYPE_SQLITE:
-      return cta::make_unique<SqliteConnFactory>(login.database);
-    case rdbms::Login::DBTYPE_NONE:
-      throw exception::Exception("Cannot create a catalogue without a database type");
-    default:
-      {
-        exception::Exception ex;
-        ex.getMessage() << "Unknown database type: value=" << login.dbType;
-        throw ex;
-      }
-    }
-  } catch(exception::Exception &ex) {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
-  }
+Conn::~Conn() throw() {
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/wrapper/Conn.hpp b/rdbms/wrapper/Conn.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..708a25e076bc89ef6688ff31909b468c224ed753
--- /dev/null
+++ b/rdbms/wrapper/Conn.hpp
@@ -0,0 +1,97 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "rdbms/wrapper/Stmt.hpp"
+
+#include <atomic>
+#include <list>
+#include <memory>
+#include <string>
+
+namespace cta {
+namespace rdbms {
+namespace wrapper {
+
+/**
+ * Abstract class that specifies the interface to a database connection.
+ */
+class Conn {
+public:
+
+  /**
+   * Destructor.
+   */
+  virtual ~Conn() throw() = 0;
+
+  /**
+   * Idempotent close() method.  The destructor calls this method.
+   */
+  virtual void close() = 0;
+
+  /**
+   * Creates a prepared statement.
+   *
+   * @param sql The SQL statement.
+   * @param autocommitMode The autocommit mode of the statement.
+   * @return The prepared statement.
+   */
+  virtual std::unique_ptr<Stmt> createStmt(const std::string &sql, const AutocommitMode autocommitMode) = 0;
+
+  /**
+   * Commits the current transaction.
+   */
+  virtual void commit() = 0;
+
+  /**
+   * Rolls back the current transaction.
+   */
+  virtual void rollback() = 0;
+
+  /**
+   * Returns the names of all the tables in the database schema in alphabetical
+   * order.
+   *
+   * @return The names of all the tables in the database schema in alphabetical
+   * order.
+   */
+  virtual std::list<std::string> getTableNames() = 0;
+
+  /**
+   * Returns true if this connection is open.
+   */
+  virtual bool isOpen() const = 0;
+
+  /**
+   * Returns the names of all the sequences in the database schema in
+   * alphabetical order.
+   *
+   * If the underlying database technologies does not supported sequences then
+   * this method simply returns an empty list.
+   *
+   * @return The names of all the sequences in the database schema in
+   * alphabetical order.
+   */
+  virtual std::list<std::string> getSequenceNames()  = 0;
+
+}; // class Conn
+
+} // namespace wrapper
+} // namespace rdbms
+} // namespace cta
diff --git a/rdbms/ConnFactory.cpp b/rdbms/wrapper/ConnFactory.cpp
similarity index 92%
rename from rdbms/ConnFactory.cpp
rename to rdbms/wrapper/ConnFactory.cpp
index 69e15806a3b292fff99a109425e94ea9819b41b1..45f70c30ff9e07875fd6c22bcf689e899c83f4ea 100644
--- a/rdbms/ConnFactory.cpp
+++ b/rdbms/wrapper/ConnFactory.cpp
@@ -16,10 +16,11 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "ConnFactory.hpp"
+#include "rdbms/wrapper/ConnFactory.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // destructor
@@ -27,5 +28,6 @@ namespace rdbms {
 ConnFactory::~ConnFactory() throw() {
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ConnFactory.hpp b/rdbms/wrapper/ConnFactory.hpp
similarity index 93%
rename from rdbms/ConnFactory.hpp
rename to rdbms/wrapper/ConnFactory.hpp
index 79efb5b587a1c3aaad7d59223e3f9ee18c8feec9..a980b7e4f2c8614d885c11c1f62f44c9688894a8 100644
--- a/rdbms/ConnFactory.hpp
+++ b/rdbms/wrapper/ConnFactory.hpp
@@ -18,12 +18,13 @@
 
 #pragma once
 
-#include "Conn.hpp"
+#include "rdbms/wrapper/Conn.hpp"
 
 #include <memory>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Abstract class that specifies the interface of a factory of Conn objects.
@@ -45,5 +46,6 @@ public:
 
 }; // class ConnFactory
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ConnFactoryFactory.cpp b/rdbms/wrapper/ConnFactoryFactory.cpp
similarity index 85%
rename from rdbms/ConnFactoryFactory.cpp
rename to rdbms/wrapper/ConnFactoryFactory.cpp
index a63d6a8e92bda2fc1c6daca04945ea8c92a67929..95e2e10047ae27b71e9b8c8023287fdf8bca3af8 100644
--- a/rdbms/ConnFactoryFactory.cpp
+++ b/rdbms/wrapper/ConnFactoryFactory.cpp
@@ -18,12 +18,13 @@
 
 #include "common/exception/Exception.hpp"
 #include "common/make_unique.hpp"
-#include "rdbms/ConnFactoryFactory.hpp"
-#include "rdbms/OcciConnFactory.hpp"
-#include "rdbms/SqliteConnFactory.hpp"
+#include "rdbms/wrapper/ConnFactoryFactory.hpp"
+#include "rdbms/wrapper/OcciConnFactory.hpp"
+#include "rdbms/wrapper/SqliteConnFactory.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // create
@@ -31,13 +32,13 @@ namespace rdbms {
 std::unique_ptr<ConnFactory> ConnFactoryFactory::create(const Login &login) {
   try {
     switch(login.dbType) {
-    case rdbms::Login::DBTYPE_IN_MEMORY:
+    case Login::DBTYPE_IN_MEMORY:
       return cta::make_unique<SqliteConnFactory>("file::memory:?cache=shared");
-    case rdbms::Login::DBTYPE_ORACLE:
+    case Login::DBTYPE_ORACLE:
       return cta::make_unique<OcciConnFactory>(login.username, login.password, login.database);
-    case rdbms::Login::DBTYPE_SQLITE:
+    case Login::DBTYPE_SQLITE:
       return cta::make_unique<SqliteConnFactory>(login.database);
-    case rdbms::Login::DBTYPE_NONE:
+    case Login::DBTYPE_NONE:
       throw exception::Exception("Cannot create a catalogue without a database type");
     default:
       {
@@ -51,5 +52,6 @@ std::unique_ptr<ConnFactory> ConnFactoryFactory::create(const Login &login) {
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ConnFactoryFactory.hpp b/rdbms/wrapper/ConnFactoryFactory.hpp
similarity index 93%
rename from rdbms/ConnFactoryFactory.hpp
rename to rdbms/wrapper/ConnFactoryFactory.hpp
index cdacc5dafc9ecad608f54ccafb5a4f1823aab8df..49f96acc75ee2a36ba288c1a3568dbed6e011318 100644
--- a/rdbms/ConnFactoryFactory.hpp
+++ b/rdbms/wrapper/ConnFactoryFactory.hpp
@@ -18,13 +18,14 @@
 
 #pragma once
 
-#include "rdbms/ConnFactory.hpp"
+#include "rdbms/wrapper/ConnFactory.hpp"
 #include "rdbms/Login.hpp"
 
 #include <memory>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Abstract class that specifies the interface to a factory of ConnFactory objects.
@@ -43,5 +44,6 @@ public:
 
 }; // class ConnFactoryFactory
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/wrapper/ConnTest.cpp b/rdbms/wrapper/ConnTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1b5c46c501b483459fffadea169d98bb567b32de
--- /dev/null
+++ b/rdbms/wrapper/ConnTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/exception/Exception.hpp"
+#include "rdbms/wrapper/ConnFactoryFactory.hpp"
+
+#include <gtest/gtest.h>
+#include <sstream>
+
+namespace unitTests {
+
+class cta_rdbms_wrapper_ConnTest : public ::testing::Test {
+protected:
+
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+  }
+};
+
+TEST_F(cta_rdbms_wrapper_ConnTest, createSameTableInTwoSeparateInMemoryDatabases) {
+  using namespace cta;
+  using namespace cta::rdbms::wrapper;
+
+  const std::string sql = "CREATE TABLE POOLED_STMT_TEST(ID INTEGER)";
+
+  // First in-memory database
+  {
+    const rdbms::Login login(rdbms::Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+    auto connFactory = ConnFactoryFactory::create(login);
+    auto conn = connFactory->create();
+
+    ASSERT_TRUE(conn->getTableNames().empty());
+
+    auto stmt = conn->createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt->executeNonQuery();
+
+    ASSERT_EQ(1, conn->getTableNames().size());
+  }
+
+  // Second in-memory database
+  {
+    const rdbms::Login login(rdbms::Login::DBTYPE_SQLITE, "", "", "file::memory:?cache=shared");
+    auto connFactory = ConnFactoryFactory::create(login);
+    auto conn = connFactory->create();
+
+    ASSERT_TRUE(conn->getTableNames().empty());
+
+    auto stmt = conn->createStmt(sql, rdbms::AutocommitMode::ON);
+    stmt->executeNonQuery();
+
+    ASSERT_EQ(1, conn->getTableNames().size());
+  }
+}
+
+} // namespace unitTests
diff --git a/rdbms/OcciColumn.cpp b/rdbms/wrapper/OcciColumn.cpp
similarity index 98%
rename from rdbms/OcciColumn.cpp
rename to rdbms/wrapper/OcciColumn.cpp
index 7e29e1193857497356916e7ee28d6a7dd9bbf649..86c7f11902ae8eaffb3a6e94c32707dde38c5813 100644
--- a/rdbms/OcciColumn.cpp
+++ b/rdbms/wrapper/OcciColumn.cpp
@@ -17,10 +17,11 @@
  */
 
 #include "common/exception/Exception.hpp"
-#include "rdbms/OcciColumn.hpp"
+#include "rdbms/wrapper/OcciColumn.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -149,5 +150,6 @@ void OcciColumn::copyStrIntoField(const size_t index, const std::string &str) {
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciColumn.hpp b/rdbms/wrapper/OcciColumn.hpp
similarity index 98%
rename from rdbms/OcciColumn.hpp
rename to rdbms/wrapper/OcciColumn.hpp
index 4fa8f2059591172e3497c8c22b41d71ccdd7e478..af926721f4155beaf03b6d7ecd00d0d4dbb5f911 100644
--- a/rdbms/OcciColumn.hpp
+++ b/rdbms/wrapper/OcciColumn.hpp
@@ -18,14 +18,14 @@
 
 #pragma once
 
-#include "catalogue/RdbmsCatalogue.hpp"
-
+#include <memory>
 #include <occi.h>
 #include <string.h>
 #include <typeinfo>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A class to help with preparing batch inserts and updatesi with the OCCI
@@ -210,5 +210,6 @@ private:
 
 }; // OcciColumn
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciColumnTest.cpp b/rdbms/wrapper/OcciColumnTest.cpp
similarity index 77%
rename from rdbms/OcciColumnTest.cpp
rename to rdbms/wrapper/OcciColumnTest.cpp
index af834309fb1103148db4d73d3ddc8274d3a53fe2..29d5b870c15ee78a377dddce9380b3881a1c9d42 100644
--- a/rdbms/OcciColumnTest.cpp
+++ b/rdbms/wrapper/OcciColumnTest.cpp
@@ -16,13 +16,14 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "OcciColumn.hpp"
+#include "common/exception/Exception.hpp"
+#include "rdbms/wrapper/OcciColumn.hpp"
 
 #include <gtest/gtest.h>
 
 namespace unitTests {
 
-class cta_rdbms_OcciColumnTest : public ::testing::Test {
+class cta_rdbms_wrapper_OcciColumnTest : public ::testing::Test {
 protected:
 
   virtual void SetUp() {
@@ -32,9 +33,9 @@ protected:
   }
 };
 
-TEST_F(cta_rdbms_OcciColumnTest, getColName) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, getColName) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -43,9 +44,9 @@ TEST_F(cta_rdbms_OcciColumnTest, getColName) {
   ASSERT_EQ(colName, col.getColName());
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, getNbRows) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, getNbRows) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -54,9 +55,9 @@ TEST_F(cta_rdbms_OcciColumnTest, getNbRows) {
   ASSERT_EQ(nbRows, col.getNbRows());
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, setFieldLen) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, setFieldLen) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -69,9 +70,9 @@ TEST_F(cta_rdbms_OcciColumnTest, setFieldLen) {
   ASSERT_EQ(5, col.getMaxFieldLength());
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, setFieldLenToValueLen_stringValue) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, setFieldLenToValueLen_stringValue) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -84,9 +85,9 @@ TEST_F(cta_rdbms_OcciColumnTest, setFieldLenToValueLen_stringValue) {
   ASSERT_EQ(field0Value.length() + 1, col.getMaxFieldLength());
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, setFieldLenToValueLen_uint64_tValue) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, setFieldLenToValueLen_uint64_tValue) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -99,9 +100,9 @@ TEST_F(cta_rdbms_OcciColumnTest, setFieldLenToValueLen_uint64_tValue) {
   ASSERT_EQ(5, col.getMaxFieldLength());
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, setFieldLen_tooLate) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, setFieldLen_tooLate) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 2;
@@ -116,9 +117,9 @@ TEST_F(cta_rdbms_OcciColumnTest, setFieldLen_tooLate) {
   ASSERT_THROW(col.setFieldLenToValueLen(1, field1Value), exception::Exception);
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, setFieldLen_invalidIndex) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, setFieldLen_invalidIndex) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -128,9 +129,9 @@ TEST_F(cta_rdbms_OcciColumnTest, setFieldLen_invalidIndex) {
   ASSERT_THROW(col.setFieldLenToValueLen(1, field1Value), exception::Exception);
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, getFieldLengths) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, getFieldLengths) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 3;
@@ -150,9 +151,9 @@ TEST_F(cta_rdbms_OcciColumnTest, getFieldLengths) {
   ASSERT_EQ(4, fieldLens[2]);
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, getBuffer) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, getBuffer) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -165,9 +166,9 @@ TEST_F(cta_rdbms_OcciColumnTest, getBuffer) {
   ASSERT_NE(nullptr, buf);
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, getBuffer_tooEarly) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, getBuffer_tooEarly) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -176,9 +177,9 @@ TEST_F(cta_rdbms_OcciColumnTest, getBuffer_tooEarly) {
   ASSERT_THROW(col.getBuffer(), exception::Exception);
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, getMaxFieldLength) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, getMaxFieldLength) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 4;
@@ -196,9 +197,9 @@ TEST_F(cta_rdbms_OcciColumnTest, getMaxFieldLength) {
   ASSERT_EQ(4, col.getMaxFieldLength());
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, copyStrIntoField_1_oneField) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, copyStrIntoField_1_oneField) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
@@ -212,9 +213,9 @@ TEST_F(cta_rdbms_OcciColumnTest, copyStrIntoField_1_oneField) {
   ASSERT_EQ(field0Value, std::string(buf));
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, setFieldValue_twoFields) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, setFieldValue_twoFields) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 2;
@@ -234,9 +235,9 @@ TEST_F(cta_rdbms_OcciColumnTest, setFieldValue_twoFields) {
   ASSERT_EQ(field1Value, std::string(bufField1));
 }
 
-TEST_F(cta_rdbms_OcciColumnTest, setFieldValue_tooLong) {
+TEST_F(cta_rdbms_wrapper_OcciColumnTest, setFieldValue_tooLong) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const std::string colName = "TEST_COLUMN";
   const size_t nbRows = 1;
diff --git a/rdbms/OcciConn.cpp b/rdbms/wrapper/OcciConn.cpp
similarity index 91%
rename from rdbms/OcciConn.cpp
rename to rdbms/wrapper/OcciConn.cpp
index 36702ed5ccedad612c8ee5f9a2423d3b91ac5150..d042314fede06d04f334ef8f8ce6201c0f4294be 100644
--- a/rdbms/OcciConn.cpp
+++ b/rdbms/wrapper/OcciConn.cpp
@@ -19,15 +19,16 @@
 #include "common/exception/Exception.hpp"
 #include "common/make_unique.hpp"
 #include "common/threading/MutexLocker.hpp"
-#include "rdbms/OcciConn.hpp"
-#include "rdbms/OcciEnv.hpp"
-#include "rdbms/OcciStmt.hpp"
+#include "rdbms/wrapper/OcciConn.hpp"
+#include "rdbms/wrapper/OcciEnv.hpp"
+#include "rdbms/wrapper/OcciStmt.hpp"
 
 #include <stdexcept>
 #include <string>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -46,7 +47,7 @@ OcciConn::OcciConn(oracle::occi::Environment *const env, oracle::occi::Connectio
 //------------------------------------------------------------------------------
 OcciConn::~OcciConn() throw() {
   try {
-    close(); // Idempotent close() mthod
+    close(); // Idempotent close() method
   } catch(...) {
     // Destructor should not throw any exceptions
   }
@@ -67,7 +68,7 @@ void OcciConn::close() {
 //------------------------------------------------------------------------------
 // createStmt
 //------------------------------------------------------------------------------
-std::unique_ptr<Stmt> OcciConn::createStmt(const std::string &sql, Stmt::AutocommitMode autocommitMode) {
+std::unique_ptr<Stmt> OcciConn::createStmt(const std::string &sql, AutocommitMode autocommitMode) {
   try {
     threading::MutexLocker locker(m_mutex);
 
@@ -139,10 +140,13 @@ std::list<std::string> OcciConn::getTableNames() {
         "USER_TABLES "
       "ORDER BY "
         "TABLE_NAME";
-    auto stmt = createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = createStmt(sql, AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
-    while (rset.next()) {
-      names.push_back(rset.columnString("TABLE_NAME"));
+    while (rset->next()) {
+      auto name = rset->columnOptionalString("TABLE_NAME");
+      if(name) {
+        names.push_back(name.value());
+      }
     }
 
     return names;
@@ -164,10 +168,11 @@ std::list<std::string> OcciConn::getSequenceNames() {
         "USER_SEQUENCES "
       "ORDER BY "
         "SEQUENCE_NAME";
-    auto stmt = createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = createStmt(sql, AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
-    while (rset.next()) {
-      names.push_back(rset.columnString("SEQUENCE_NAME"));
+    while (rset->next()) {
+      auto name = rset->columnOptionalString("SEQUENCE_NAME");
+      names.push_back(name.value());
     }
 
     return names;
@@ -206,5 +211,6 @@ void OcciConn::closeStmt(oracle::occi::Statement *const stmt) {
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciConn.hpp b/rdbms/wrapper/OcciConn.hpp
similarity index 90%
rename from rdbms/OcciConn.hpp
rename to rdbms/wrapper/OcciConn.hpp
index 7e18d703a8224ebf1208a63e8470354f882e1e80..614a778fe2d34792f860ec56ea24834137d8c11c 100644
--- a/rdbms/OcciConn.hpp
+++ b/rdbms/wrapper/OcciConn.hpp
@@ -19,12 +19,13 @@
 #pragma once
 
 #include "common/threading/MutexLocker.hpp"
-#include "rdbms/Conn.hpp"
+#include "rdbms/wrapper/Conn.hpp"
 
 #include <occi.h>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Forward declaraion to avoid a circular dependency beween OcciConn and
@@ -66,7 +67,7 @@ public:
    * @param autocommitMode The autocommit mode of the statement.
    * @return The prepared statement.
    */
-  virtual std::unique_ptr<Stmt> createStmt(const std::string &sql, const Stmt::AutocommitMode autocommitMode) override;
+  virtual std::unique_ptr<Stmt> createStmt(const std::string &sql, const AutocommitMode autocommitMode) override;
 
   /**
    * Commits the current transaction.
@@ -96,10 +97,13 @@ public:
    * Returns the names of all the sequences in the database schema in
    * alphabetical order.
    *
+   * If the underlying database technologies does not supported sequences then
+   * this method simply returns an empty list.
+   *
    * @return The names of all the sequences in the database schema in
    * alphabetical order.
    */
-  std::list<std::string> getSequenceNames();
+  virtual std::list<std::string> getSequenceNames() override;
 
 private:
 
@@ -129,5 +133,6 @@ private:
 
 }; // class OcciConn
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciConnFactory.cpp b/rdbms/wrapper/OcciConnFactory.cpp
similarity index 93%
rename from rdbms/OcciConnFactory.cpp
rename to rdbms/wrapper/OcciConnFactory.cpp
index f1f7695261ef0541143d3326b8f4879a6bb96dd5..16f52edfa91197e88eb17a2c03a840671a525222 100644
--- a/rdbms/OcciConnFactory.cpp
+++ b/rdbms/wrapper/OcciConnFactory.cpp
@@ -18,11 +18,12 @@
 
 #include "common/exception/Exception.hpp"
 #include "common/make_unique.hpp"
-#include "OcciConnFactory.hpp"
-#include "OcciEnvSingleton.hpp"
+#include "rdbms/wrapper/OcciConnFactory.hpp"
+#include "rdbms/wrapper/OcciEnvSingleton.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -53,5 +54,6 @@ std::unique_ptr<Conn> OcciConnFactory::create() {
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciConnFactory.hpp b/rdbms/wrapper/OcciConnFactory.hpp
similarity index 95%
rename from rdbms/OcciConnFactory.hpp
rename to rdbms/wrapper/OcciConnFactory.hpp
index cb3e42a877e22994a0560f5a63456d3c9cc78f3a..9e7cab5a2543a9a35e35dd92d63340dbeaa8cd5d 100644
--- a/rdbms/OcciConnFactory.hpp
+++ b/rdbms/wrapper/OcciConnFactory.hpp
@@ -18,10 +18,11 @@
 
 #pragma once
 
-#include "ConnFactory.hpp"
+#include "rdbms/wrapper/ConnFactory.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A concrete factory of Conn objects.
@@ -72,5 +73,6 @@ private:
 
 }; // class OcciConnFactory
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciEnv.cpp b/rdbms/wrapper/OcciEnv.cpp
similarity index 95%
rename from rdbms/OcciEnv.cpp
rename to rdbms/wrapper/OcciEnv.cpp
index e290c6f13edacb01cc16466c2c020a2100aa6617..b322079fbbcdc75ec3e9f3c3ed97b28c61ee61d3 100644
--- a/rdbms/OcciEnv.cpp
+++ b/rdbms/wrapper/OcciEnv.cpp
@@ -16,13 +16,14 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "OcciConn.hpp"
-#include "OcciEnv.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/make_unique.hpp"
+#include "rdbms/wrapper/OcciConn.hpp"
+#include "rdbms/wrapper/OcciEnv.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -66,5 +67,6 @@ std::unique_ptr<Conn> OcciEnv::createConn(
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciEnv.hpp b/rdbms/wrapper/OcciEnv.hpp
similarity index 95%
rename from rdbms/OcciEnv.hpp
rename to rdbms/wrapper/OcciEnv.hpp
index 659e0862450141940ac2b68fe8a9d460876c3795..ae922ebc4f528d87ef4c4fb681cd762ede61af17 100644
--- a/rdbms/OcciEnv.hpp
+++ b/rdbms/wrapper/OcciEnv.hpp
@@ -18,13 +18,14 @@
 
 #pragma once
 
-#include "rdbms/Conn.hpp"
+#include "rdbms/wrapper/Conn.hpp"
 
 #include <memory>
 #include <occi.h>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A convenience wrapper around an OCCI environment.
@@ -71,5 +72,6 @@ private:
 
 }; // class OcciEnv
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciEnvSingleton.cpp b/rdbms/wrapper/OcciEnvSingleton.cpp
similarity index 96%
rename from rdbms/OcciEnvSingleton.cpp
rename to rdbms/wrapper/OcciEnvSingleton.cpp
index 84844fff7900ae3812c1c137b51a713dea336743..551ad0dd8df9929edcfc4ebfa4e061723fde7bd3 100644
--- a/rdbms/OcciEnvSingleton.cpp
+++ b/rdbms/wrapper/OcciEnvSingleton.cpp
@@ -16,12 +16,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "rdbms/OcciEnvSingleton.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/threading/MutexLocker.hpp"
+#include "rdbms/wrapper/OcciEnvSingleton.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // s_mutex
@@ -57,5 +58,6 @@ OcciEnvSingleton &OcciEnvSingleton::instance() {
 OcciEnvSingleton::OcciEnvSingleton() {
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciEnvSingleton.hpp b/rdbms/wrapper/OcciEnvSingleton.hpp
similarity index 95%
rename from rdbms/OcciEnvSingleton.hpp
rename to rdbms/wrapper/OcciEnvSingleton.hpp
index c6c36b2faa91edf2367955e3285a47b4fa16f5ab..a2afe8454a9c6c1071c838c162a43a314af097c9 100644
--- a/rdbms/OcciEnvSingleton.hpp
+++ b/rdbms/wrapper/OcciEnvSingleton.hpp
@@ -19,12 +19,13 @@
 #pragma once
 
 #include "common/threading/Mutex.hpp"
-#include "rdbms/OcciEnv.hpp"
+#include "rdbms/wrapper/OcciEnv.hpp"
 
 #include <memory>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A singleton version of OcciEnv.
@@ -67,5 +68,6 @@ private:
 
 }; // class OcciEnvSingleton
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciRsetImpl.cpp b/rdbms/wrapper/OcciRset.cpp
similarity index 90%
rename from rdbms/OcciRsetImpl.cpp
rename to rdbms/wrapper/OcciRset.cpp
index 12b11d90573976df1cd05e37cc602ae2814dfa17..788d1f5d0ec31dd5d7a337a87118fe128dbf33f8 100644
--- a/rdbms/OcciRsetImpl.cpp
+++ b/rdbms/wrapper/OcciRset.cpp
@@ -16,11 +16,11 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "NullDbValue.hpp"
-#include "OcciRsetImpl.hpp"
-#include "OcciStmt.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/utils/utils.hpp"
+#include "rdbms/NullDbValue.hpp"
+#include "rdbms/wrapper/OcciRset.hpp"
+#include "rdbms/wrapper/OcciStmt.hpp"
 
 #include <cstring>
 #include <map>
@@ -28,11 +28,12 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-OcciRsetImpl::OcciRsetImpl(OcciStmt &stmt, oracle::occi::ResultSet *const rset):
+OcciRset::OcciRset(OcciStmt &stmt, oracle::occi::ResultSet *const rset):
   m_stmt(stmt),
   m_rset(rset) {
   try {
@@ -49,7 +50,7 @@ OcciRsetImpl::OcciRsetImpl(OcciStmt &stmt, oracle::occi::ResultSet *const rset):
 //------------------------------------------------------------------------------
 // populateColNameToIdx
 //------------------------------------------------------------------------------
-void OcciRsetImpl::populateColNameToIdxMap() {
+void OcciRset::populateColNameToIdxMap() {
   using namespace oracle;
 
   try {
@@ -69,7 +70,7 @@ void OcciRsetImpl::populateColNameToIdxMap() {
 //------------------------------------------------------------------------------
 // destructor
 //------------------------------------------------------------------------------
-OcciRsetImpl::~OcciRsetImpl() throw() {
+OcciRset::~OcciRset() throw() {
   try {
     close(); // Idempotent close()
   } catch(...) {
@@ -80,14 +81,14 @@ OcciRsetImpl::~OcciRsetImpl() throw() {
 //------------------------------------------------------------------------------
 // getSql
 //------------------------------------------------------------------------------
-const std::string &OcciRsetImpl::getSql() const {
+const std::string &OcciRset::getSql() const {
   return m_stmt.getSql();
 }
 
 //------------------------------------------------------------------------------
 // next
 //------------------------------------------------------------------------------
-bool OcciRsetImpl::next() {
+bool OcciRset::next() {
   using namespace oracle;
 
   try {
@@ -102,7 +103,7 @@ bool OcciRsetImpl::next() {
 //------------------------------------------------------------------------------
 // columnIsNull
 //------------------------------------------------------------------------------
-bool OcciRsetImpl::columnIsNull(const std::string &colName) const {
+bool OcciRset::columnIsNull(const std::string &colName) const {
   try {
     const int colIdx = m_colNameToIdx.getIdx(colName);
     return m_rset->isNull(colIdx);
@@ -116,7 +117,7 @@ bool OcciRsetImpl::columnIsNull(const std::string &colName) const {
 //------------------------------------------------------------------------------
 // close
 //------------------------------------------------------------------------------
-void OcciRsetImpl::close() {
+void OcciRset::close() {
   threading::Mutex locker(m_mutex);
 
   if(nullptr != m_rset) {
@@ -128,7 +129,7 @@ void OcciRsetImpl::close() {
 //------------------------------------------------------------------------------
 // columnOptionalString
 //------------------------------------------------------------------------------
-optional<std::string> OcciRsetImpl::columnOptionalString(const std::string &colName) const {
+optional<std::string> OcciRset::columnOptionalString(const std::string &colName) const {
   try {
     const int colIdx = m_colNameToIdx.getIdx(colName);
     const std::string stringValue = m_rset->getString(colIdx);
@@ -148,7 +149,7 @@ optional<std::string> OcciRsetImpl::columnOptionalString(const std::string &colN
 //------------------------------------------------------------------------------
 // columnOptionalUint64
 //------------------------------------------------------------------------------
-optional<uint64_t> OcciRsetImpl::columnOptionalUint64(const std::string &colName) const {
+optional<uint64_t> OcciRset::columnOptionalUint64(const std::string &colName) const {
   try {
     threading::Mutex locker(m_mutex);
 
@@ -171,5 +172,6 @@ optional<uint64_t> OcciRsetImpl::columnOptionalUint64(const std::string &colName
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciRsetImpl.hpp b/rdbms/wrapper/OcciRset.hpp
similarity index 91%
rename from rdbms/OcciRsetImpl.hpp
rename to rdbms/wrapper/OcciRset.hpp
index d6cc3ca54827c2a849398b88f2473209ead03213..bad427edb7d5b0dfa3dfbc615b425920aeea4942 100644
--- a/rdbms/OcciRsetImpl.hpp
+++ b/rdbms/wrapper/OcciRset.hpp
@@ -19,14 +19,15 @@
 #pragma once
 
 #include "common/threading/Mutex.hpp"
-#include "rdbms/ColumnNameToIdx.hpp"
-#include "rdbms/RsetImpl.hpp"
+#include "rdbms/wrapper/ColumnNameToIdx.hpp"
+#include "rdbms/wrapper/Rset.hpp"
 
 #include <memory>
 #include <occi.h>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Forward declaration to avoid a circular dependency between OcciRset and
@@ -37,7 +38,7 @@ class OcciStmt;
 /**
  * A convenience wrapper around an OCCI result set.
  */
-class OcciRsetImpl: public RsetImpl {
+class OcciRset: public Rset {
 public:
 
   /**
@@ -49,12 +50,12 @@ public:
    * @param stmt The OCCI statement.
    * @param rset The OCCI result set.
    */
-  OcciRsetImpl(OcciStmt &stmt, oracle::occi::ResultSet *const rset);
+  OcciRset(OcciStmt &stmt, oracle::occi::ResultSet *const rset);
 
   /**
    * Destructor.
    */
-  virtual ~OcciRsetImpl() throw() override;
+  virtual ~OcciRset() throw() override;
 
   /**
    * Returns the SQL statement.
@@ -131,7 +132,8 @@ private:
    */
   void populateColNameToIdxMap();
 
-}; // class OcciRsetImpl
+}; // class OcciRset
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciStmt.cpp b/rdbms/wrapper/OcciStmt.cpp
similarity index 94%
rename from rdbms/OcciStmt.cpp
rename to rdbms/wrapper/OcciStmt.cpp
index 320be053b6f8e77b2d2ddf80b3e85bfd8e01a78d..3337affdf298bc5ee02a4acfa01caf4d740bf939 100644
--- a/rdbms/OcciStmt.cpp
+++ b/rdbms/wrapper/OcciStmt.cpp
@@ -19,10 +19,10 @@
 #include "common/exception/Exception.hpp"
 #include "common/make_unique.hpp"
 #include "common/threading/MutexLocker.hpp"
-#include "rdbms/OcciColumn.hpp"
-#include "rdbms/OcciConn.hpp"
-#include "rdbms/OcciRsetImpl.hpp"
-#include "rdbms/OcciStmt.hpp"
+#include "rdbms/wrapper/OcciColumn.hpp"
+#include "rdbms/wrapper/OcciConn.hpp"
+#include "rdbms/wrapper/OcciRset.hpp"
+#include "rdbms/wrapper/OcciStmt.hpp"
 
 #include <cstring>
 #include <map>
@@ -31,6 +31,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -79,6 +80,12 @@ OcciStmt::~OcciStmt() throw() {
   }
 }
 
+//------------------------------------------------------------------------------
+// clear
+//------------------------------------------------------------------------------
+void OcciStmt::clear() {
+}
+
 //------------------------------------------------------------------------------
 // close
 //------------------------------------------------------------------------------
@@ -170,11 +177,11 @@ void OcciStmt::bindOptionalString(const std::string &paramName, const optional<s
 //------------------------------------------------------------------------------
 // executeQuery
 //------------------------------------------------------------------------------
-Rset OcciStmt::executeQuery() {
+std::unique_ptr<Rset> OcciStmt::executeQuery() {
   using namespace oracle;
 
   try {
-    return Rset(new OcciRsetImpl(*this, m_stmt->executeQuery()));
+    return cta::make_unique<OcciRset>(*this, m_stmt->executeQuery());
   } catch(occi::SQLException &ex) {
     if(connShouldBeClosed(ex)) {
       // Close the statement first and then the connection
@@ -283,5 +290,6 @@ bool OcciStmt::connShouldBeClosed(const oracle::occi::SQLException &ex) {
   };
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciStmt.hpp b/rdbms/wrapper/OcciStmt.hpp
similarity index 94%
rename from rdbms/OcciStmt.hpp
rename to rdbms/wrapper/OcciStmt.hpp
index a180db9f3d877c0bec3f85af5415e75c5c45cd33..5b58998eed81a81ddb78ee77d939471bb992ce7b 100644
--- a/rdbms/OcciStmt.hpp
+++ b/rdbms/wrapper/OcciStmt.hpp
@@ -19,7 +19,7 @@
 #pragma once
 
 #include "common/threading/Mutex.hpp"
-#include "rdbms/Stmt.hpp"
+#include "rdbms/wrapper/Stmt.hpp"
 
 #include <memory>
 #include <occi.h>
@@ -27,6 +27,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Forward declaration to avoid a circular dependency between OcciStmt and
@@ -38,7 +39,7 @@ class OcciConn;
  * Forward declaration to avoid a circular dependency between OcciStmt and
  * OcciRset.
  */
-class OcciRsetImpl;
+class OcciRset;
 
 class OcciColumn;
 
@@ -72,6 +73,11 @@ public:
    */
   OcciStmt(const OcciStmt &) = delete;
 
+  /**
+   * Clears the prepared statement so that it is ready to be reused.
+   */
+  void clear() override;
+
   /**
    * Idempotent close() method.  The destructor calls this method.
    */
@@ -122,7 +128,7 @@ public:
    *
    *  @return The result set.
    */
-  Rset executeQuery() override;
+  std::unique_ptr<Rset> executeQuery() override;
 
   /**
    * Executes the statement.
@@ -186,5 +192,6 @@ private:
 
 }; // class OcciStmt
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ParamNameToIdx.cpp b/rdbms/wrapper/ParamNameToIdx.cpp
similarity index 97%
rename from rdbms/ParamNameToIdx.cpp
rename to rdbms/wrapper/ParamNameToIdx.cpp
index 8173850517892b63508bd352093c2da16c3ce16a..00aeadafa6f2095678813aac9788f6ba4ad1a488 100644
--- a/rdbms/ParamNameToIdx.cpp
+++ b/rdbms/wrapper/ParamNameToIdx.cpp
@@ -16,13 +16,14 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "ParamNameToIdx.hpp"
 #include "common/exception/Exception.hpp"
+#include "rdbms/wrapper/ParamNameToIdx.hpp"
 
 #include <sstream>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -90,5 +91,6 @@ uint32_t ParamNameToIdx::getIdx(const std::string &paramName) const {
   return itor->second;
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ParamNameToIdx.hpp b/rdbms/wrapper/ParamNameToIdx.hpp
similarity index 97%
rename from rdbms/ParamNameToIdx.hpp
rename to rdbms/wrapper/ParamNameToIdx.hpp
index 3ab4d175da2f1a2650f20702d14c2962c3184883..79c79eb6c910a5484998bf267a335a1005a635bc 100644
--- a/rdbms/ParamNameToIdx.hpp
+++ b/rdbms/wrapper/ParamNameToIdx.hpp
@@ -22,6 +22,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Map from SQL parameter name to parameter index.
@@ -65,5 +66,6 @@ private:
 
 }; // class ParamNameToIdx
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/ParamNameToIdxTest.cpp b/rdbms/wrapper/ParamNameToIdxTest.cpp
similarity index 88%
rename from rdbms/ParamNameToIdxTest.cpp
rename to rdbms/wrapper/ParamNameToIdxTest.cpp
index 7ded28ade1a364948f6f0e2cb76dec084ac4f9e8..380ab4a2bffb280df8440d5d31adb93cc037d787 100644
--- a/rdbms/ParamNameToIdxTest.cpp
+++ b/rdbms/wrapper/ParamNameToIdxTest.cpp
@@ -16,15 +16,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "ParamNameToIdx.hpp"
 #include "common/exception/Exception.hpp"
+#include "rdbms/wrapper/ParamNameToIdx.hpp"
 
 #include <gtest/gtest.h>
 #include <sstream>
 
 namespace unitTests {
 
-class cta_rdbms_ParamNameToIdxTest : public ::testing::Test {
+class cta_rdbms_wrapper_ParamNameToIdxTest : public ::testing::Test {
 protected:
 
   virtual void SetUp() {
@@ -34,8 +34,8 @@ protected:
   }
 };
 
-TEST_F(cta_rdbms_ParamNameToIdxTest, getIdx_existing_params) {
-  using namespace cta::rdbms;
+TEST_F(cta_rdbms_wrapper_ParamNameToIdxTest, getIdx_existing_params) {
+  using namespace cta::rdbms::wrapper;
 
   const char *const sql =
     "INSERT INTO ADMIN_USER("
@@ -80,9 +80,9 @@ TEST_F(cta_rdbms_ParamNameToIdxTest, getIdx_existing_params) {
   ASSERT_EQ(10, paramNameToIdx.getIdx(":LAST_UPDATE_TIME"));
 }
 
-TEST_F(cta_rdbms_ParamNameToIdxTest, getIdx_non_existing_param) {
+TEST_F(cta_rdbms_wrapper_ParamNameToIdxTest, getIdx_non_existing_param) {
   using namespace cta;
-  using namespace cta::rdbms;
+  using namespace cta::rdbms::wrapper;
 
   const char *const sql =
    "String containing no bind parameters";
diff --git a/rdbms/RsetImpl.cpp b/rdbms/wrapper/Rset.cpp
similarity index 90%
rename from rdbms/RsetImpl.cpp
rename to rdbms/wrapper/Rset.cpp
index 6eb67a189cb3c47d91b1fa85adef93a08470ba82..9448304a56cda20a241676166549e19803924c96 100644
--- a/rdbms/RsetImpl.cpp
+++ b/rdbms/wrapper/Rset.cpp
@@ -16,16 +16,18 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "rdbms/RsetImpl.hpp"
+#include "rdbms/wrapper/Rset.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // destructor
 //------------------------------------------------------------------------------
-RsetImpl::~RsetImpl() throw() {
+Rset::~Rset() throw() {
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/RsetImpl.hpp b/rdbms/wrapper/Rset.hpp
similarity index 95%
rename from rdbms/RsetImpl.hpp
rename to rdbms/wrapper/Rset.hpp
index 72db6ed246e8dbd6eb9a4a9bbb3d763c0dcaa8d0..bcc98870d73496dc43e156732aaa3d3cb843d0bb 100644
--- a/rdbms/RsetImpl.hpp
+++ b/rdbms/wrapper/Rset.hpp
@@ -25,18 +25,19 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Abstract class specifying the interface to an implementation of the result
  * set of an sql query.
  */
-class RsetImpl {
+class Rset {
 public:
 
   /**
    * Destructor.
    */
-  virtual ~RsetImpl() throw() = 0;
+  virtual ~Rset() throw() = 0;
 
   /**
    * Returns the SQL statement.
@@ -81,7 +82,8 @@ public:
    */
   virtual optional<uint64_t> columnOptionalUint64(const std::string &colName) const = 0;
 
-}; // class RsetImpl
+}; // class Rset
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/Sqlite.cpp b/rdbms/wrapper/Sqlite.cpp
similarity index 96%
rename from rdbms/Sqlite.cpp
rename to rdbms/wrapper/Sqlite.cpp
index 52ae52af15b6636c047478c0d894c77da0ccb16c..287aeab85b9933707c2759b735ec925bd47d9a72 100644
--- a/rdbms/Sqlite.cpp
+++ b/rdbms/wrapper/Sqlite.cpp
@@ -16,12 +16,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "Sqlite.hpp"
+#include "rdbms/wrapper/Sqlite.hpp"
 
 #include <sstream>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // rcToStr
@@ -33,7 +34,7 @@ std::string Sqlite::rcToStr(const int rc) {
     case SQLITE_AUTH:
       return "Authorization denied";
     case SQLITE_BUSY:
-      return "Failed to take locks";
+      return "Busy";
     case SQLITE_CANTOPEN:
       return "Cannot open database file";
     case SQLITE_CONSTRAINT:
@@ -90,5 +91,6 @@ std::string Sqlite::rcToStr(const int rc) {
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/Sqlite.hpp b/rdbms/wrapper/Sqlite.hpp
similarity index 96%
rename from rdbms/Sqlite.hpp
rename to rdbms/wrapper/Sqlite.hpp
index b69abf7991a649efac86a2ae712109c611eb7da2..93c46f975c9d20e7368a3290bd3fe61e23e02bff 100644
--- a/rdbms/Sqlite.hpp
+++ b/rdbms/wrapper/Sqlite.hpp
@@ -23,6 +23,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A helper class for working with SQLite.
@@ -40,5 +41,6 @@ public:
 
 }; // class SqlLiteStmt
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteConn.cpp b/rdbms/wrapper/SqliteConn.cpp
similarity index 81%
rename from rdbms/SqliteConn.cpp
rename to rdbms/wrapper/SqliteConn.cpp
index 3b08df7341d0cdb16c54a427f0f3907ed93be97f..98ad9a79c277754bb44d5f36bc47256708709aed 100644
--- a/rdbms/SqliteConn.cpp
+++ b/rdbms/wrapper/SqliteConn.cpp
@@ -19,14 +19,17 @@
 #include "common/exception/Exception.hpp"
 #include "common/make_unique.hpp"
 #include "common/threading/MutexLocker.hpp"
-#include "rdbms/SqliteConn.hpp"
-#include "rdbms/SqliteStmt.hpp"
+#include "rdbms/wrapper/Sqlite.hpp"
+#include "rdbms/wrapper/SqliteConn.hpp"
+#include "rdbms/wrapper/SqliteStmt.hpp"
 
+#include <iostream>
 #include <stdexcept>
 #include <string>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -66,7 +69,11 @@ SqliteConn::SqliteConn(const std::string &filename):
 // destructor
 //------------------------------------------------------------------------------
 SqliteConn::~SqliteConn() throw() {
-  close();
+  try {
+    close(); // Idempotent close() method
+  } catch(...) {
+    // Destructor should not throw any exceptions
+  }
 }
 
 //------------------------------------------------------------------------------
@@ -76,7 +83,12 @@ void SqliteConn::close() {
   threading::MutexLocker locker(m_mutex);
 
   if(nullptr != m_sqliteConn) {
-    sqlite3_close(m_sqliteConn);
+    const int closeRc = sqlite3_close(m_sqliteConn);
+    if(SQLITE_OK != closeRc) {
+      exception::Exception ex;
+      ex.getMessage() << "Failed to close SQLite connection: " << Sqlite::rcToStr(closeRc);
+      throw ex;
+    }
     m_sqliteConn = nullptr;
   }
 }
@@ -84,7 +96,7 @@ void SqliteConn::close() {
 //------------------------------------------------------------------------------
 // createStmt
 //------------------------------------------------------------------------------
-std::unique_ptr<Stmt> SqliteConn::createStmt(const std::string &sql, const Stmt::AutocommitMode autocommitMode) {
+std::unique_ptr<Stmt> SqliteConn::createStmt(const std::string &sql, const AutocommitMode autocommitMode) {
   try {
     threading::MutexLocker locker(m_mutex);
 
@@ -170,14 +182,14 @@ void SqliteConn::printSchema(std::ostream &os) {
       "ORDER BY "
         "TYPE, "
         "NAME;";
-    auto stmt = createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = createStmt(sql, AutocommitMode::ON);
     auto rset = stmt->executeQuery();
     os << "NAME, TYPE" << std::endl;
     os << "==========" << std::endl;
-    while (rset.next()) {
-      const std::string name = rset.columnString("NAME");
-      const std::string type = rset.columnString("TYPE");
-      os << name << ", " << type << std::endl;
+    while (rset->next()) {
+      const auto name = rset->columnOptionalString("NAME");
+      const auto type = rset->columnOptionalString("TYPE");
+      os << (name ? name.value() : "NULL") << ", " << (type ? type.value() : "NULL") << std::endl;
     }
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -198,11 +210,14 @@ std::list<std::string> SqliteConn::getTableNames() {
         "TYPE = 'table' "
       "ORDER BY "
         "NAME;";
-    auto stmt = createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = createStmt(sql, AutocommitMode::ON);
     auto rset = stmt->executeQuery();
     std::list<std::string> names;
-    while (rset.next()) {
-      names.push_back(rset.columnString("NAME"));
+    while (rset->next()) {
+      auto name = rset->columnOptionalString("NAME");
+      if(name) {
+        names.push_back(name.value());
+      }
     }
     return names;
   } catch(exception::Exception &ex) {
@@ -217,5 +232,17 @@ bool SqliteConn::isOpen() const {
   return nullptr != m_sqliteConn;
 }
 
+//------------------------------------------------------------------------------
+// getSequenceNames
+//------------------------------------------------------------------------------
+std::list<std::string> SqliteConn::getSequenceNames() {
+  try {
+    return std::list<std::string>();
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
+}
+
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteConn.hpp b/rdbms/wrapper/SqliteConn.hpp
similarity index 85%
rename from rdbms/SqliteConn.hpp
rename to rdbms/wrapper/SqliteConn.hpp
index d8f3df7bd997ec5a91e68d8eec42adb95b86996c..ee66e6749c80186e375446a710aa89e931c9748c 100644
--- a/rdbms/SqliteConn.hpp
+++ b/rdbms/wrapper/SqliteConn.hpp
@@ -19,12 +19,13 @@
 #pragma once
 
 #include "common/threading/Mutex.hpp"
-#include "rdbms/Conn.hpp"
+#include "rdbms/wrapper/Conn.hpp"
 
 #include <sqlite3.h>
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Forward declaration to avoid a circular dependency between SqliteConn and
@@ -68,7 +69,7 @@ public:
    * @param autocommitMode The autocommit mode of the statement.
    * @return The prepared statement.
    */
-  std::unique_ptr<Stmt> createStmt(const std::string &sql, const Stmt::AutocommitMode autocommitMode) override;
+  std::unique_ptr<Stmt> createStmt(const std::string &sql, const AutocommitMode autocommitMode) override;
 
   /**
    * Commits the current transaction.
@@ -94,6 +95,18 @@ public:
    */
   bool isOpen() const override;
 
+  /**
+   * Returns the names of all the sequences in the database schema in
+   * alphabetical order.
+   *
+   * If the underlying database technologies does not supported sequences then
+   * this method simply returns an empty list.
+   *
+   * @return The names of all the sequences in the database schema in
+   * alphabetical order.
+   */
+  std::list<std::string> getSequenceNames() override;
+
   /**
    * This ia an SqliteConn specific method that prints the database schema to
    * the specified output stream.
@@ -124,5 +137,6 @@ private:
 
 }; // class SqliteConn
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteConnFactory.cpp b/rdbms/wrapper/SqliteConnFactory.cpp
similarity index 93%
rename from rdbms/SqliteConnFactory.cpp
rename to rdbms/wrapper/SqliteConnFactory.cpp
index f7898e1087af491730f384d7905b510269a1fca9..72bdecd387f5f9aa66117c301330f1df0e634b72 100644
--- a/rdbms/SqliteConnFactory.cpp
+++ b/rdbms/wrapper/SqliteConnFactory.cpp
@@ -18,11 +18,12 @@
 
 #include "common/exception/Exception.hpp"
 #include "common/make_unique.hpp"
-#include "SqliteConn.hpp"
-#include "SqliteConnFactory.hpp"
+#include "rdbms/wrapper/SqliteConn.hpp"
+#include "rdbms/wrapper/SqliteConnFactory.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -48,5 +49,6 @@ std::unique_ptr<Conn> SqliteConnFactory::create() {
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteConnFactory.hpp b/rdbms/wrapper/SqliteConnFactory.hpp
similarity index 94%
rename from rdbms/SqliteConnFactory.hpp
rename to rdbms/wrapper/SqliteConnFactory.hpp
index a1838c9921cfc7a016d8e3b58a710dc6e0dfcc1d..b04c5e98a6fa856025c667b0f3e054658ce913b4 100644
--- a/rdbms/SqliteConnFactory.hpp
+++ b/rdbms/wrapper/SqliteConnFactory.hpp
@@ -18,10 +18,11 @@
 
 #pragma once
 
-#include "ConnFactory.hpp"
+#include "rdbms/wrapper/ConnFactory.hpp"
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A concrete factory of Conn objects.
@@ -57,5 +58,6 @@ private:
 
 }; // class SqliteConnFactory
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteRsetImpl.cpp b/rdbms/wrapper/SqliteRset.cpp
similarity index 91%
rename from rdbms/SqliteRsetImpl.cpp
rename to rdbms/wrapper/SqliteRset.cpp
index f16144e65dc01c403e2a1468d92b965b53176260..1a45e1ffb63dd7ef297afc3311d3a01755d17ae1 100644
--- a/rdbms/SqliteRsetImpl.cpp
+++ b/rdbms/wrapper/SqliteRset.cpp
@@ -16,12 +16,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "NullDbValue.hpp"
-#include "Sqlite.hpp"
-#include "SqliteRsetImpl.hpp"
-#include "SqliteStmt.hpp"
 #include "common/exception/Exception.hpp"
 #include "common/exception/Errnum.hpp"
+#include "rdbms/NullDbValue.hpp"
+#include "rdbms/wrapper/Sqlite.hpp"
+#include "rdbms/wrapper/SqliteRset.hpp"
+#include "rdbms/wrapper/SqliteStmt.hpp"
 
 #include <cstring>
 #include <sstream>
@@ -30,6 +30,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * A map from column name to column index and type.
@@ -120,31 +121,31 @@ private:
    */
   std::map<std::string, IdxAndType> m_nameToIdxAndType;
 
-}; // class SqliteRsetImpl::ColNameToIdx
+}; // class SqliteRset::ColNameToIdx
 
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-SqliteRsetImpl::SqliteRsetImpl(SqliteStmt &stmt): m_stmt(stmt) {
+SqliteRset::SqliteRset(SqliteStmt &stmt): m_stmt(stmt) {
 }
 
 //------------------------------------------------------------------------------
 // destructor.
 //------------------------------------------------------------------------------
-SqliteRsetImpl::~SqliteRsetImpl() throw() {
+SqliteRset::~SqliteRset() throw() {
 }
 
 //------------------------------------------------------------------------------
 // getSql
 //------------------------------------------------------------------------------
-const std::string &SqliteRsetImpl::getSql() const {
+const std::string &SqliteRset::getSql() const {
   return m_stmt.getSql();
 }
 
 //------------------------------------------------------------------------------
 // next
 //------------------------------------------------------------------------------
-bool SqliteRsetImpl::next() {
+bool SqliteRset::next() {
   try {
     const int stepRc = sqlite3_step(m_stmt.get());
 
@@ -159,7 +160,7 @@ bool SqliteRsetImpl::next() {
 
     return SQLITE_ROW == stepRc;
   } catch(exception::Exception &ex) {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() +
+    throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSqlForException() +
       ": " + ex.getMessage().str());
   }
 }
@@ -167,7 +168,7 @@ bool SqliteRsetImpl::next() {
 //------------------------------------------------------------------------------
 // clearAndPopulateColNameToIdxMap
 //------------------------------------------------------------------------------
-void SqliteRsetImpl::clearAndPopulateColNameToIdxAndTypeMap() {
+void SqliteRset::clearAndPopulateColNameToIdxAndTypeMap() {
   try {
     m_colNameToIdxAndType.clear();
 
@@ -197,7 +198,7 @@ void SqliteRsetImpl::clearAndPopulateColNameToIdxAndTypeMap() {
 //------------------------------------------------------------------------------
 // columnIsNull
 //------------------------------------------------------------------------------
-bool SqliteRsetImpl::columnIsNull(const std::string &colName) const {
+bool SqliteRset::columnIsNull(const std::string &colName) const {
   try {
     const ColumnNameToIdxAndType::IdxAndType idxAndType = m_colNameToIdxAndType.getIdxAndType(colName);
     return SQLITE_NULL == idxAndType.colType;
@@ -209,7 +210,7 @@ bool SqliteRsetImpl::columnIsNull(const std::string &colName) const {
 //------------------------------------------------------------------------------
 // columnOptionalString
 //------------------------------------------------------------------------------
-optional<std::string> SqliteRsetImpl::columnOptionalString(const std::string &colName) const {
+optional<std::string> SqliteRset::columnOptionalString(const std::string &colName) const {
   try {
     const ColumnNameToIdxAndType::IdxAndType idxAndType = m_colNameToIdxAndType.getIdxAndType(colName);
     if(SQLITE_NULL == idxAndType.colType) {
@@ -232,7 +233,7 @@ optional<std::string> SqliteRsetImpl::columnOptionalString(const std::string &co
 //------------------------------------------------------------------------------
 // columnOptionalUint64
 //------------------------------------------------------------------------------
-optional<uint64_t> SqliteRsetImpl::columnOptionalUint64(const std::string &colName) const {
+optional<uint64_t> SqliteRset::columnOptionalUint64(const std::string &colName) const {
   try {
     const ColumnNameToIdxAndType::IdxAndType idxAndType = m_colNameToIdxAndType.getIdxAndType(colName);
     if(SQLITE_NULL == idxAndType.colType) {
@@ -245,5 +246,6 @@ optional<uint64_t> SqliteRsetImpl::columnOptionalUint64(const std::string &colNa
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteRsetImpl.hpp b/rdbms/wrapper/SqliteRset.hpp
similarity index 92%
rename from rdbms/SqliteRsetImpl.hpp
rename to rdbms/wrapper/SqliteRset.hpp
index 8aaee093ec3fe6b053184b488e1e027fb9cb834b..0bda5b1e29543c6308096290212e46bdc2895d3e 100644
--- a/rdbms/SqliteRsetImpl.hpp
+++ b/rdbms/wrapper/SqliteRset.hpp
@@ -18,8 +18,8 @@
 
 #pragma once
 
-#include "rdbms/ColumnNameToIdxAndType.hpp"
-#include "rdbms/RsetImpl.hpp"
+#include "rdbms/wrapper/ColumnNameToIdxAndType.hpp"
+#include "rdbms/wrapper/Rset.hpp"
 
 #include <memory>
 #include <stdint.h>
@@ -27,6 +27,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 /**
  * Forward declaration.
@@ -36,7 +37,7 @@ class SqliteStmt;
 /**
  * The result set of an sql query.
  */
-class SqliteRsetImpl: public RsetImpl {
+class SqliteRset: public Rset {
 public:
 
   /**
@@ -44,12 +45,12 @@ public:
    *
    * @param stmt The prepared statement.
    */
-  SqliteRsetImpl(SqliteStmt &stmt);
+  SqliteRset(SqliteStmt &stmt);
 
   /**
    * Destructor.
    */
-  ~SqliteRsetImpl() throw() override;
+  ~SqliteRset() throw() override;
 
   /**
    * Returns the SQL statement.
@@ -113,5 +114,6 @@ private:
 
 }; // class SqlLiteRset
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteStmt.cpp b/rdbms/wrapper/SqliteStmt.cpp
similarity index 82%
rename from rdbms/SqliteStmt.cpp
rename to rdbms/wrapper/SqliteStmt.cpp
index 76b61a37945e315e273b180a4b93e1a5d49447f0..68886b2b4c32bc14fa4fe043ab524572eac6a104 100644
--- a/rdbms/SqliteStmt.cpp
+++ b/rdbms/wrapper/SqliteStmt.cpp
@@ -19,12 +19,13 @@
 #include "common/exception/Exception.hpp"
 #include "common/make_unique.hpp"
 #include "common/threading/MutexLocker.hpp"
-#include "rdbms/Sqlite.hpp"
-#include "rdbms/SqliteConn.hpp"
-#include "rdbms/SqliteRsetImpl.hpp"
-#include "rdbms/SqliteStmt.hpp"
+#include "rdbms/wrapper/Sqlite.hpp"
+#include "rdbms/wrapper/SqliteConn.hpp"
+#include "rdbms/wrapper/SqliteRset.hpp"
+#include "rdbms/wrapper/SqliteStmt.hpp"
 
 #include <cstring>
+#include <iostream>
 #include <stdexcept>
 #include <stdlib.h>
 #include <string>
@@ -32,6 +33,7 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 //------------------------------------------------------------------------------
 // constructor
@@ -114,15 +116,47 @@ SqliteStmt::~SqliteStmt() throw() {
   }
 }
 
+//------------------------------------------------------------------------------
+// clear
+//------------------------------------------------------------------------------
+void SqliteStmt::clear() {
+  try {
+    threading::MutexLocker locker(m_mutex);
+
+    if(nullptr != m_stmt) {
+      const int resetRc = sqlite3_reset(m_stmt);
+      if(SQLITE_OK != resetRc) {
+        exception::Exception ex;
+        ex.getMessage() <<"sqlite3_reset failed: " << Sqlite::rcToStr(resetRc);
+      }
+      const int clearBindingsRc = sqlite3_clear_bindings(m_stmt);
+      if(SQLITE_OK != clearBindingsRc) {
+        exception::Exception ex;
+        ex.getMessage() <<"sqlite3_clear_bindings failed: " << Sqlite::rcToStr(clearBindingsRc);
+      }
+    }
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
+}
+
 //------------------------------------------------------------------------------
 // close
 //------------------------------------------------------------------------------
 void SqliteStmt::close() {
-  threading::MutexLocker locker(m_mutex);
+  try {
+    threading::MutexLocker locker(m_mutex);
 
-  if(nullptr != m_stmt) {
-    sqlite3_finalize(m_stmt);
-    m_stmt = nullptr;
+    if (nullptr != m_stmt) {
+      const int finalizeRc = sqlite3_finalize(m_stmt);
+      if (SQLITE_OK != finalizeRc) {
+        exception::Exception ex;
+        ex.getMessage() <<"sqlite3_finalize failed: " << Sqlite::rcToStr(finalizeRc);
+      }
+      m_stmt = nullptr;
+    }
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
   }
 }
 
@@ -161,7 +195,9 @@ void SqliteStmt::bindOptionalUint64(const std::string &paramName, const optional
       bindRc = sqlite3_bind_null(m_stmt, paramIdx);
     }
     if(SQLITE_OK != bindRc) {
-      throw exception::Exception("sqlite3_bind_int64() failed");
+      exception::Exception ex;
+      ex.getMessage() << "sqlite3_bind_int64() failed: " << Sqlite::rcToStr(bindRc);
+      throw ex;
     }
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " +
@@ -197,7 +233,10 @@ void SqliteStmt::bindOptionalString(const std::string &paramName, const optional
       bindRc = sqlite3_bind_null(m_stmt, paramIdx);
     }
     if(SQLITE_OK != bindRc) {
-      throw exception::Exception("sqlite3_bind_text() failed");
+      exception::Exception ex;
+
+      ex.getMessage() << "sqlite3_bind_text() failed: " << Sqlite::rcToStr(bindRc);
+      throw ex;
     }
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " +
@@ -208,8 +247,8 @@ void SqliteStmt::bindOptionalString(const std::string &paramName, const optional
 //------------------------------------------------------------------------------
 // executeQuery
 //------------------------------------------------------------------------------
-Rset SqliteStmt::executeQuery() {
-  return Rset(new SqliteRsetImpl(*this));
+std::unique_ptr<Rset> SqliteStmt::executeQuery() {
+  return cta::make_unique<SqliteRset>(*this);
 }
 
 //------------------------------------------------------------------------------
@@ -262,5 +301,6 @@ void SqliteStmt::beginDeferredTransaction() {
   }
 }
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteStmt.hpp b/rdbms/wrapper/SqliteStmt.hpp
similarity index 94%
rename from rdbms/SqliteStmt.hpp
rename to rdbms/wrapper/SqliteStmt.hpp
index 3d0cee5ad7a5b209191612883703bedba070efcd..bf0bdb9b9965cb9ee8abb0cadb70ee9d6146f9ae 100644
--- a/rdbms/SqliteStmt.hpp
+++ b/rdbms/wrapper/SqliteStmt.hpp
@@ -19,7 +19,7 @@
 #pragma once
 
 #include "common/threading/Mutex.hpp"
-#include "rdbms/Stmt.hpp"
+#include "rdbms/wrapper/Stmt.hpp"
 
 #include <map>
 #include <memory>
@@ -28,9 +28,10 @@
 
 namespace cta {
 namespace rdbms {
+namespace wrapper {
 
 class SqliteConn;
-class SqliteRsetImpl;
+class SqliteRset;
 
 /**
  * A convenience wrapper around an SQLite prepared statement.
@@ -55,6 +56,11 @@ public:
    */
   ~SqliteStmt() throw() override;
 
+  /**
+   * Clears the prepared statement so that it is ready to be reused.
+   */
+  void clear() override;
+
   /**
    * Idempotent close() method.  The destructor calls this method.
    */
@@ -115,7 +121,7 @@ public:
    *
    * @return The result set.
    */
-  Rset executeQuery() override;
+  std::unique_ptr<Rset> executeQuery() override;
 
   /**
    * Executes the statement.
@@ -163,5 +169,6 @@ private:
 
 }; // class SqlLiteStmt
 
+} // namespace wrapper
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteStmtTest.cpp b/rdbms/wrapper/SqliteStmtTest.cpp
similarity index 63%
rename from rdbms/SqliteStmtTest.cpp
rename to rdbms/wrapper/SqliteStmtTest.cpp
index 9aaadca885731648adaf24faded12dc3479d12bf..0d7b7d32df283b5c8fe90d3771017f1c0e6a1c09 100644
--- a/rdbms/SqliteStmtTest.cpp
+++ b/rdbms/wrapper/SqliteStmtTest.cpp
@@ -16,16 +16,16 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "SqliteConn.hpp"
-#include "SqliteRsetImpl.hpp"
-#include "SqliteStmt.hpp"
+#include "rdbms/wrapper/SqliteConn.hpp"
+#include "rdbms/wrapper/SqliteRset.hpp"
+#include "rdbms/wrapper/SqliteStmt.hpp"
 
 #include <gtest/gtest.h>
 #include <memory>
 
 namespace unitTests {
 
-class cta_rdbms_SqliteStmtTest : public ::testing::Test {
+class cta_rdbms_wrapper_SqliteStmtTest : public ::testing::Test {
 protected:
 
   virtual void SetUp() {
@@ -35,8 +35,9 @@ protected:
   }
 };
 
-TEST_F(cta_rdbms_SqliteStmtTest, create_table) {
-  using namespace cta::rdbms;
+TEST_F(cta_rdbms_wrapper_SqliteStmtTest, create_table) {
+  using namespace cta;
+  using namespace cta::rdbms::wrapper;
   // Create a connection a memory resident database
   SqliteConn conn(":memory:");
 
@@ -49,12 +50,13 @@ TEST_F(cta_rdbms_SqliteStmtTest, create_table) {
         "SQLITE_MASTER "
       "WHERE "
         "TYPE = 'table';";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     auto rset = stmt->executeQuery();
-    ASSERT_TRUE(rset.next());
-    const uint64_t nbTables = rset.columnUint64("NB_TABLES");
-    ASSERT_EQ(0, nbTables);
-    ASSERT_FALSE(rset.next());
+    ASSERT_TRUE(rset->next());
+    const auto nbTables = rset->columnOptionalUint64("NB_TABLES");
+    ASSERT_TRUE((bool)nbTables);
+    ASSERT_EQ(0, nbTables.value());
+    ASSERT_FALSE(rset->next());
     ASSERT_TRUE(conn.getTableNames().empty());
   }
 
@@ -65,7 +67,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, create_table) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->executeNonQuery();
   }
 
@@ -78,12 +80,13 @@ TEST_F(cta_rdbms_SqliteStmtTest, create_table) {
       "WHERE "
         "NAME = 'TEST1' AND "
         "TYPE = 'table';";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     auto rset = stmt->executeQuery();
-    ASSERT_TRUE(rset.next());
-    const uint64_t nbTables = rset.columnUint64("NB_TABLES");
-    ASSERT_EQ(1, nbTables);
-    ASSERT_FALSE(rset.next());
+    ASSERT_TRUE(rset->next());
+    const auto nbTables = rset->columnOptionalUint64("NB_TABLES");
+    ASSERT_TRUE((bool)nbTables);
+    ASSERT_EQ(1, nbTables.value());
+    ASSERT_FALSE(rset->next());
     ASSERT_EQ(1, conn.getTableNames().size());
     ASSERT_EQ("TEST1", conn.getTableNames().front());
   }
@@ -95,7 +98,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, create_table) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->executeNonQuery();
   }
 
@@ -108,12 +111,13 @@ TEST_F(cta_rdbms_SqliteStmtTest, create_table) {
       "WHERE "
         "NAME = 'TEST2' AND "
         "TYPE = 'table';";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     auto rset = stmt->executeQuery();
-    ASSERT_TRUE(rset.next());
-    const uint64_t nbTables = rset.columnUint64("NB_TABLES");
-    ASSERT_EQ(1, nbTables);
-    ASSERT_FALSE(rset.next());
+    ASSERT_TRUE(rset->next());
+    const auto nbTables = rset->columnOptionalUint64("NB_TABLES");
+    ASSERT_TRUE((bool)nbTables);
+    ASSERT_EQ(1, nbTables.value());
+    ASSERT_FALSE(rset->next());
     const auto tableNames = conn.getTableNames();
     ASSERT_EQ(2, tableNames.size());
     auto nameItor = tableNames.begin();
@@ -125,8 +129,9 @@ TEST_F(cta_rdbms_SqliteStmtTest, create_table) {
   }
 }
 
-TEST_F(cta_rdbms_SqliteStmtTest, select_from_empty_table) {
-  using namespace cta::rdbms;
+TEST_F(cta_rdbms_wrapper_SqliteStmtTest, select_from_empty_table) {
+  using namespace cta;
+  using namespace cta::rdbms::wrapper;
   // Create a connection a memory resident database
   SqliteConn conn(":memory:");
 
@@ -139,7 +144,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, select_from_empty_table) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->executeNonQuery();
     ASSERT_EQ(1, conn.getTableNames().size());
     ASSERT_EQ("TEST", conn.getTableNames().front());
@@ -154,14 +159,15 @@ TEST_F(cta_rdbms_SqliteStmtTest, select_from_empty_table) {
         "COL3 "
       "FROM "
         "TEST;";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     auto rset = stmt->executeQuery();
-    ASSERT_FALSE(rset.next());
+    ASSERT_FALSE(rset->next());
   }
 }
 
-TEST_F(cta_rdbms_SqliteStmtTest, insert_without_bind) {
-  using namespace cta::rdbms;
+TEST_F(cta_rdbms_wrapper_SqliteStmtTest, insert_without_bind) {
+  using namespace cta;
+  using namespace cta::rdbms::wrapper;
   // Create a connection a memory resident database
   SqliteConn conn(":memory:");
 
@@ -174,7 +180,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, insert_without_bind) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->executeNonQuery();
     ASSERT_EQ(1, conn.getTableNames().size());
     ASSERT_EQ("TEST", conn.getTableNames().front());
@@ -191,7 +197,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, insert_without_bind) {
         "'one',"
         "'two',"
         "3);";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->executeNonQuery();
   }
 
@@ -204,24 +210,29 @@ TEST_F(cta_rdbms_SqliteStmtTest, insert_without_bind) {
         "COL3 AS COL3 "
       "FROM "
         "TEST;";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     auto rset = stmt->executeQuery();
-    ASSERT_TRUE(rset.next());
+    ASSERT_TRUE(rset->next());
 
-    const std::string col1 = rset.columnString("COL1");
-    const std::string col2 = rset.columnString("COL2");
-    const uint64_t col3 = rset.columnUint64("COL3");
+    const auto col1 = rset->columnOptionalString("COL1");
+    const auto col2 = rset->columnOptionalString("COL2");
+    const auto col3 = rset->columnOptionalUint64("COL3");
 
-    ASSERT_EQ("one", col1);
-    ASSERT_EQ("two", col2);
-    ASSERT_EQ((uint64_t)3, col3);
+    ASSERT_TRUE((bool)col1);
+    ASSERT_TRUE((bool)col2);
+    ASSERT_TRUE((bool)col3);
 
-    ASSERT_FALSE(rset.next());
+    ASSERT_EQ("one", col1.value());
+    ASSERT_EQ("two", col2.value());
+    ASSERT_EQ(3, col3.value());
+
+    ASSERT_FALSE(rset->next());
   }
 }
 
-TEST_F(cta_rdbms_SqliteStmtTest, insert_with_bind) {
-  using namespace cta::rdbms;
+TEST_F(cta_rdbms_wrapper_SqliteStmtTest, insert_with_bind) {
+  using namespace cta;
+  using namespace cta::rdbms::wrapper;
 
   // Create a connection a memory resident database
   SqliteConn conn(":memory:");
@@ -235,7 +246,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, insert_with_bind) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->executeNonQuery();
     ASSERT_EQ(1, conn.getTableNames().size());
     ASSERT_EQ("TEST", conn.getTableNames().front());
@@ -252,7 +263,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, insert_with_bind) {
         ":COL1,"
         ":COL2,"
         ":COL3);";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->bindString(":COL1", "one");
     stmt->bindString(":COL2", "two");
     stmt->bindUint64(":COL3", 3);
@@ -268,24 +279,29 @@ TEST_F(cta_rdbms_SqliteStmtTest, insert_with_bind) {
         "COL3 AS COL3 "
       "FROM "
         "TEST;";
-    auto stmt = conn.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
     auto rset = stmt->executeQuery();
-    ASSERT_TRUE(rset.next());
+    ASSERT_TRUE(rset->next());
+
+    const auto col1 = rset->columnOptionalString("COL1");
+    const auto col2 = rset->columnOptionalString("COL2");
+    const auto col3 = rset->columnOptionalUint64("COL3");
 
-    const std::string col1 = rset.columnString("COL1");
-    const std::string col2 = rset.columnString("COL2");
-    const uint64_t col3 = rset.columnUint64("COL3");
+    ASSERT_TRUE((bool)col1);
+    ASSERT_TRUE((bool)col2);
+    ASSERT_TRUE((bool)col3);
 
-    ASSERT_EQ("one", col1);
-    ASSERT_EQ("two", col2);
-    ASSERT_EQ((uint64_t)3, col3);
+    ASSERT_EQ("one", col1.value());
+    ASSERT_EQ("two", col2.value());
+    ASSERT_EQ(3, col3.value());
 
-    ASSERT_FALSE(rset.next());
+    ASSERT_FALSE(rset->next());
   }
 }
 
-TEST_F(cta_rdbms_SqliteStmtTest, isolated_transaction) {
-  using namespace cta::rdbms;
+TEST_F(cta_rdbms_wrapper_SqliteStmtTest, isolated_transaction) {
+  using namespace cta;
+  using namespace cta::rdbms::wrapper;
 
   const std::string dbFilename = "file::memory:?cache=shared";
 
@@ -298,7 +314,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, isolated_transaction) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-    auto stmt = connForCreate.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = connForCreate.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->executeNonQuery();
     ASSERT_EQ(1, connForCreate.getTableNames().size());
     ASSERT_EQ("TEST", connForCreate.getTableNames().front());
@@ -316,7 +332,7 @@ TEST_F(cta_rdbms_SqliteStmtTest, isolated_transaction) {
         "'one',"
         "'two',"
         "3);";
-    auto stmt = connForInsert.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = connForInsert.createStmt(sql, rdbms::AutocommitMode::ON);
     stmt->executeNonQuery();
   }
 
@@ -330,15 +346,15 @@ TEST_F(cta_rdbms_SqliteStmtTest, isolated_transaction) {
         "COUNT(*) AS NB_ROWS "
       "FROM "
         "TEST;";
-    auto stmt = connForSelect.createStmt(sql, Stmt::AutocommitMode::ON);
+    auto stmt = connForSelect.createStmt(sql, rdbms::AutocommitMode::ON);
     auto rset = stmt->executeQuery();
-    ASSERT_TRUE(rset.next());
-
-    const uint64_t nbRows = rset.columnUint64("NB_ROWS");
+    ASSERT_TRUE(rset->next());
 
-    ASSERT_EQ((uint64_t)1, nbRows);
+    const auto nbRows = rset->columnOptionalUint64("NB_ROWS");
+    ASSERT_TRUE((bool)nbRows);
+    ASSERT_EQ((uint64_t)1, nbRows.value());
 
-    ASSERT_FALSE(rset.next());
+    ASSERT_FALSE(rset->next());
   }
 }
 
diff --git a/rdbms/wrapper/Stmt.cpp b/rdbms/wrapper/Stmt.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..be47b1bf5dd63d7b0a47cae8b2a3f15661020270
--- /dev/null
+++ b/rdbms/wrapper/Stmt.cpp
@@ -0,0 +1,96 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "rdbms/wrapper/Stmt.hpp"
+
+namespace cta {
+namespace rdbms {
+namespace wrapper {
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+Stmt::Stmt(const std::string &sql, const AutocommitMode autocommitMode):
+  m_sql(sql),
+  m_autocommitMode(autocommitMode),
+  m_paramNameToIdx(sql) {
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+Stmt::~Stmt() throw() {
+}
+
+//------------------------------------------------------------------------------
+// getSql
+//------------------------------------------------------------------------------
+const std::string &Stmt::getSql() const {
+  return m_sql;
+}
+
+//------------------------------------------------------------------------------
+// getAutocommitMode
+//------------------------------------------------------------------------------
+AutocommitMode Stmt::getAutocommitMode() const noexcept {
+  return m_autocommitMode;
+}
+
+//------------------------------------------------------------------------------
+// getParamIdx
+//------------------------------------------------------------------------------
+uint32_t Stmt::getParamIdx(const std::string &paramName) const {
+  return m_paramNameToIdx.getIdx(paramName);
+}
+
+//------------------------------------------------------------------------------
+// getSqlForException
+//------------------------------------------------------------------------------
+std::string Stmt::getSqlForException() const {
+  if(m_sql.length() <= c_maxSqlLenInExceptions) {
+    return m_sql;
+  } else {
+    if(c_maxSqlLenInExceptions >= 3) {
+      return m_sql.substr(0, c_maxSqlLenInExceptions - 3) + "...";
+    } else {
+      return std::string("..."). substr(0, c_maxSqlLenInExceptions);
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+// bindBool
+//------------------------------------------------------------------------------
+void Stmt::bindBool(const std::string &paramName, const bool paramValue) {
+  bindOptionalBool(paramName, paramValue);
+}
+
+//------------------------------------------------------------------------------
+// bindOptionalBool
+//------------------------------------------------------------------------------
+void Stmt::bindOptionalBool(const std::string &paramName, const optional<bool> &paramValue) {
+  if(paramValue) {
+    bindOptionalUint64(paramName, paramValue.value() ? 1 : 0);
+  } else {
+    bindOptionalUint64(paramName, nullopt);
+  }
+}
+
+} // namespace wrapper
+} // namespace rdbms
+} // namespace cta
diff --git a/rdbms/wrapper/Stmt.hpp b/rdbms/wrapper/Stmt.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ee0a3a6dcafe8de91a61baef0ded6a97953c39f
--- /dev/null
+++ b/rdbms/wrapper/Stmt.hpp
@@ -0,0 +1,221 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "common/optional.hpp"
+#include "rdbms/AutocommitMode.hpp"
+#include "rdbms/wrapper/ParamNameToIdx.hpp"
+#include "rdbms/wrapper/Rset.hpp"
+
+#include <memory>
+#include <stdint.h>
+#include <string>
+
+namespace cta {
+namespace rdbms {
+namespace wrapper {
+
+/**
+ * Abstract class specifying the interface to a database statement.
+ */
+class Stmt {
+public:
+
+  /**
+   * Constructor.
+   *
+   * @param sql The SQL statement.
+   * @param autocommitMode The autocommit mode of the statement.
+   */
+  Stmt(const std::string &sql, const AutocommitMode autocommitMode);
+
+  /**
+   * Returns the autocommit mode of teh statement.
+   *
+   * @return The autocommit mode of teh statement.
+   */
+  AutocommitMode getAutocommitMode() const noexcept;
+
+  /**
+   * Destructor.
+   */
+  virtual ~Stmt() throw() = 0;
+
+  /**
+   * Deletion of the copy constructor.
+   */
+  Stmt(Stmt &) = delete;
+
+  /**
+   * Deletion of the move constructor.
+   */
+  Stmt(Stmt &&) = delete;
+
+  /**
+   * Deletion of the copy assignment operator.
+   */
+  Stmt &operator=(const Stmt &) = delete;
+
+  /**
+   * Deletion of the move assignment operator.
+   */
+  Stmt &operator=(Stmt &&) = delete;
+
+  /**
+   * Clears the prepared statement so that it is ready to be reused.
+   */
+  virtual void clear() = 0;
+
+  /**
+   * Idempotent close() method.  The destructor calls this method.
+   */
+  virtual void close() = 0;
+
+  /**
+   * Returns the SQL statement.
+   *
+   * @return The SQL statement.
+   */
+  const std::string &getSql() const;
+
+  /**
+   * Returns the index of the specified SQL parameter.
+   *
+   * @param paramName The name of the SQL parameter.
+   * @return The index of the SQL parameter.
+   */
+  uint32_t getParamIdx(const std::string &paramName) const;
+
+  /**
+   * Binds an SQL parameter.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */
+  virtual void bindUint64(const std::string &paramName, const uint64_t paramValue) = 0;
+
+  /**
+   * Binds an SQL parameter.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */
+  virtual void bindOptionalUint64(const std::string &paramName, const optional<uint64_t> &paramValue) = 0;
+
+  /**
+   * Binds an SQL parameter.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */
+  void bindBool(const std::string &paramName, const bool paramValue);
+
+  /**
+   * Binds an SQL parameter.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */
+  void bindOptionalBool(const std::string &paramName, const optional<bool> &paramValue);
+
+  /** 
+   * Binds an SQL parameter of type string.
+   *
+   * Please note that this method will throw an exception if the string
+   * parameter is empty.  If a null value is to be bound then the
+   * bindOptionalString() method should be used.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */ 
+  virtual void bindString(const std::string &paramName, const std::string &paramValue) = 0;
+
+  /** 
+   * Binds an SQL parameter of type optional-string.
+   *
+   * Please note that this method will throw an exception if the optional string
+   * parameter has the empty string as its value.  An optional string parameter
+   * should either have a non-empty string value or no value at all.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */ 
+  virtual void bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue) = 0;
+
+  /**
+   *  Executes the statement and returns the result set.
+   *
+   *  @return The result set.
+   */
+  virtual std::unique_ptr<Rset> executeQuery() = 0;
+
+  /**
+   * Executes the statement.
+   */
+  virtual void executeNonQuery() = 0;
+
+  /**
+   * Returns the number of rows affected by the last execution of this
+   * statement.
+   *
+   * @return The number of affected rows.
+   */
+  virtual uint64_t getNbAffectedRows() const = 0;
+
+  /**
+   * Returns the SQL string to be used in an exception message.  The string
+   * will be clipped at a maxmum of c_maxSqlLenInExceptions characters.  If the
+   * string is actually clipped then the three last characters will be an
+   * replaced by an ellipsis of three dots, in other word "...".  These 3
+   * characters will indicate to the reader of the exception message that the
+   * SQL statement has been clipped.
+   *
+   * @return The SQL string to be used in an exception message.
+   */
+  std::string getSqlForException() const;
+
+protected:
+
+  /**
+   * The maximum length an SQL statement can have in exception error message.
+   */
+  const uint32_t c_maxSqlLenInExceptions = 80;
+
+private:
+
+  /**
+   * The SQL statement.
+   */
+  std::string m_sql;
+
+  /**
+   * The autocommit mode of the statement.
+   */
+  AutocommitMode m_autocommitMode;
+
+  /**
+   * Map from SQL parameter name to parameter index.
+   */
+  ParamNameToIdx m_paramNameToIdx;
+
+}; // class Stmt
+
+} // namespace wrapper
+} // namespace rdbms
+} // namespace cta