From 4338d2dafbfceb99d0588f970572899c0ea1eb26 Mon Sep 17 00:00:00 2001
From: Steven Murray <steven.murray@cern.ch>
Date: Wed, 7 Dec 2016 14:54:43 +0100
Subject: [PATCH] Database connections in a pool now reconnect if an Oracle
 connection is lost

---
 catalogue/OracleCatalogue.cpp               |   8 +-
 catalogue/PollDatabaseCmd.cpp               |   4 +-
 catalogue/RdbmsCatalogue.cpp                | 214 ++++++++++----------
 catalogue/SchemaCreatingSqliteCatalogue.cpp |   2 +-
 catalogue/SqliteCatalogue.cpp               |  12 +-
 rdbms/AutoRollback.cpp                      |  10 +-
 rdbms/AutoRollback.hpp                      |  12 +-
 rdbms/Conn.cpp                              |  14 --
 rdbms/Conn.hpp                              |  22 +-
 rdbms/ConnPool.cpp                          |  24 ++-
 rdbms/ConnPool.hpp                          |  13 +-
 rdbms/OcciConn.cpp                          |  36 +---
 rdbms/OcciConn.hpp                          |  13 +-
 rdbms/OcciStmt.cpp                          |  58 +++++-
 rdbms/OcciStmt.hpp                          |   9 +
 rdbms/PooledConn.cpp                        | 103 +++++++---
 rdbms/PooledConn.hpp                        |  70 +++++--
 rdbms/SqliteConn.cpp                        |   7 +
 rdbms/SqliteConn.hpp                        |  15 +-
 19 files changed, 378 insertions(+), 268 deletions(-)

diff --git a/catalogue/OracleCatalogue.cpp b/catalogue/OracleCatalogue.cpp
index 06a9e94c1e..eb7561cdb0 100644
--- a/catalogue/OracleCatalogue.cpp
+++ b/catalogue/OracleCatalogue.cpp
@@ -82,7 +82,7 @@ common::dataStructures::ArchiveFile OracleCatalogue::deleteArchiveFile(
         "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID "
       "FOR UPDATE";
     auto conn = m_connPool.getConn();
-    auto selectStmt = conn->createStmt(selectSql, rdbms::Stmt::AutocommitMode::OFF);
+    auto selectStmt = conn.createStmt(selectSql, rdbms::Stmt::AutocommitMode::OFF);
     selectStmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
     std::unique_ptr<rdbms::Rset> selectRset(selectStmt->executeQuery());
     std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile;
@@ -139,19 +139,19 @@ common::dataStructures::ArchiveFile OracleCatalogue::deleteArchiveFile(
 
     {
       const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
-      auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
       stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
       stmt->executeNonQuery();
     }
 
     {
       const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
-      auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
       stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
       stmt->executeNonQuery();
     }
 
-    conn->commit();
+    conn.commit();
 
     return *archiveFile;
   } catch(exception::UserError &) {
diff --git a/catalogue/PollDatabaseCmd.cpp b/catalogue/PollDatabaseCmd.cpp
index 9a6af9f241..bd680a770c 100644
--- a/catalogue/PollDatabaseCmd.cpp
+++ b/catalogue/PollDatabaseCmd.cpp
@@ -53,7 +53,7 @@ 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 = 1;
+  const uint64_t nbConns = 2;
   rdbms::ConnPool connPool(*factory, nbConns);
 
   uint32_t elapsedSeconds = 0;
@@ -61,7 +61,7 @@ int PollDatabaseCmd::exceptionThrowingMain(const int argc, char *const *const ar
     try {
       m_out << "Querying the database" << std::endl;
       auto conn = connPool.getConn();
-      conn->getTableNames();
+      conn.getTableNames();
     } catch(exception::Exception &ex) {
       m_out << "Database error: " << ex.getMessage().str() << std::endl;
     }
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index e377288df0..4d7a8bdb05 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -75,7 +75,7 @@ void RdbmsCatalogue::createAdminUser(
   const std::string &comment) {
   try {
     auto conn = m_connPool.getConn();
-    if(adminUserExists(*conn, username)) {
+    if(adminUserExists(conn, username)) {
       throw exception::UserError(std::string("Cannot create admin user " + username +
         " because an admin user with the same name already exists"));
     }
@@ -105,7 +105,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":ADMIN_USER_NAME", username);
 
@@ -155,7 +155,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":ADMIN_USER_NAME", username);
     stmt->executeNonQuery();
 
@@ -191,7 +191,7 @@ std::list<common::dataStructures::AdminUser> RdbmsCatalogue::getAdminUsers() con
       "FROM "
         "ADMIN_USER";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while (rset->next()) {
       common::dataStructures::AdminUser admin;
@@ -230,7 +230,7 @@ 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);
+    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);
@@ -257,7 +257,7 @@ void RdbmsCatalogue::createAdminHost(
   const std::string &comment) {
   try {
     auto conn = m_connPool.getConn();
-    if(adminHostExists(*conn, hostName)) {
+    if(adminHostExists(conn, hostName)) {
       throw exception::UserError(std::string("Cannot create admin host " + hostName +
         " because an admin host with the same name already exists"));
     }
@@ -287,7 +287,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":ADMIN_HOST_NAME", hostName);
 
@@ -337,7 +337,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":ADMIN_HOST_NAME", hostName);
     stmt->executeNonQuery();
 
@@ -373,7 +373,7 @@ std::list<common::dataStructures::AdminHost> RdbmsCatalogue::getAdminHosts() con
       "FROM "
         "ADMIN_HOST";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while (rset->next()) {
       common::dataStructures::AdminHost host;
@@ -412,7 +412,7 @@ 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);
+    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);
@@ -438,7 +438,7 @@ void RdbmsCatalogue::createStorageClass(
   const common::dataStructures::StorageClass &storageClass) {
   try {
     auto conn = m_connPool.getConn();
-    if(storageClassExists(*conn, storageClass.diskInstance, storageClass.name)) {
+    if(storageClassExists(conn, storageClass.diskInstance, storageClass.name)) {
       throw exception::UserError(std::string("Cannot create storage class ") + storageClass.diskInstance + ":" +
         storageClass.name + " because it already exists");
     }
@@ -472,7 +472,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":DISK_INSTANCE_NAME", storageClass.diskInstance);
     stmt->bindString(":STORAGE_CLASS_NAME", storageClass.name);
@@ -533,7 +533,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
     stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
@@ -575,7 +575,7 @@ std::list<common::dataStructures::StorageClass>
       "FROM "
         "STORAGE_CLASS";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while (rset->next()) {
       common::dataStructures::StorageClass storageClass;
@@ -617,7 +617,7 @@ 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);
+    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);
@@ -654,7 +654,7 @@ 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);
+    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);
@@ -686,7 +686,7 @@ void RdbmsCatalogue::createTapePool(
   try {
     auto conn = m_connPool.getConn();
 
-    if(tapePoolExists(*conn, name)) {
+    if(tapePoolExists(conn, name)) {
       throw exception::UserError(std::string("Cannot create tape pool ") + name +
         " because a tape pool with the same name already exists");
     }
@@ -720,7 +720,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":TAPE_POOL_NAME", name);
     stmt->bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes);
@@ -800,7 +800,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":TAPE_POOL_NAME", name);
     stmt->executeNonQuery();
 
@@ -838,7 +838,7 @@ std::list<common::dataStructures::TapePool> RdbmsCatalogue::getTapePools() const
       "FROM "
         "TAPE_POOL";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while (rset->next()) {
       common::dataStructures::TapePool pool;
@@ -879,7 +879,7 @@ 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);
+    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);
@@ -912,7 +912,7 @@ 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);
+    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);
@@ -946,7 +946,7 @@ 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);
+    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);
@@ -977,20 +977,20 @@ void RdbmsCatalogue::createArchiveRoute(
   try {
     const time_t now = time(nullptr);
     auto conn = m_connPool.getConn();
-    if(archiveRouteExists(*conn, diskInstanceName, storageClassName, copyNb)) {
+    if(archiveRouteExists(conn, diskInstanceName, storageClassName, copyNb)) {
       exception::UserError ue;
       ue.getMessage() << "Cannot create archive route " << diskInstanceName << ":" << storageClassName << "," << copyNb
         << "->" << tapePoolName << " because it already exists";
       throw ue;
     }
-    if(!storageClassExists(*conn, diskInstanceName, storageClassName)) {
+    if(!storageClassExists(conn, diskInstanceName, storageClassName)) {
       exception::UserError ue;
       ue.getMessage() << "Cannot create archive route " << diskInstanceName << ":" << storageClassName << "," << copyNb
         << "->" << tapePoolName << " because storage class " << diskInstanceName << ":" << storageClassName <<
         " does not exist";
       throw ue;
     }
-    if(!tapePoolExists(*conn, tapePoolName)) {
+    if(!tapePoolExists(conn, tapePoolName)) {
       exception::UserError ue;
       ue.getMessage() << "Cannot create archive route " << diskInstanceName << ":" << storageClassName << "," << copyNb
         << "->" << tapePoolName << " because tape pool " << tapePoolName + " does not exist";
@@ -1028,7 +1028,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
     stmt->bindString(":STORAGE_CLASS_NAME", storageClassName);
@@ -1067,7 +1067,7 @@ 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);
+    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);
@@ -1111,7 +1111,7 @@ std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes
       "FROM "
         "ARCHIVE_ROUTE";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while (rset->next()) {
       common::dataStructures::ArchiveRoute route;
@@ -1156,7 +1156,7 @@ 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);
+    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);
@@ -1198,7 +1198,7 @@ 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);
+    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);
@@ -1230,7 +1230,7 @@ void RdbmsCatalogue::createLogicalLibrary(
   const std::string &comment) {
   try {
     auto conn = m_connPool.getConn();
-    if(logicalLibraryExists(*conn, name)) {
+    if(logicalLibraryExists(conn, name)) {
       throw exception::UserError(std::string("Cannot create logical library ") + name +
         " because a logical library with the same name already exists");
     }
@@ -1260,7 +1260,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":LOGICAL_LIBRARY_NAME", name);
 
@@ -1310,7 +1310,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":LOGICAL_LIBRARY_NAME", name);
     stmt->executeNonQuery();
 
@@ -1347,7 +1347,7 @@ std::list<common::dataStructures::LogicalLibrary>
       "FROM "
         "LOGICAL_LIBRARY";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while (rset->next()) {
       common::dataStructures::LogicalLibrary lib;
@@ -1386,7 +1386,7 @@ 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);
+    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);
@@ -1424,15 +1424,15 @@ void RdbmsCatalogue::createTape(
     }
 
     auto conn = m_connPool.getConn();
-    if(tapeExists(*conn, vid)) {
+    if(tapeExists(conn, vid)) {
       throw exception::UserError(std::string("Cannot create tape ") + vid +
         " because a tape with the same volume identifier already exists");
     }
-    if(!logicalLibraryExists(*conn, logicalLibraryName)) {
+    if(!logicalLibraryExists(conn, logicalLibraryName)) {
       throw exception::UserError(std::string("Cannot create tape ") + vid + " because logical library " +
         logicalLibraryName + " does not exist");
     }
-    if(!tapePoolExists(*conn, tapePoolName)) {
+    if(!tapePoolExists(conn, tapePoolName)) {
       throw exception::UserError(std::string("Cannot create tape ") + vid + " because tape pool " +
         tapePoolName + " does not exist");
     }
@@ -1478,7 +1478,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":VID", vid);
     stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
@@ -1536,7 +1536,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":VID", vid);
     stmt->executeNonQuery();
 
@@ -1556,7 +1556,7 @@ void RdbmsCatalogue::deleteTape(const std::string &vid) {
 std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(const TapeSearchCriteria &searchCriteria) const {
   try {
     auto conn = m_connPool.getConn();
-    return getTapes(*conn, searchCriteria);
+    return getTapes(conn, searchCriteria);
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
   }
@@ -1749,7 +1749,7 @@ 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::Stmt::AutocommitMode::OFF);
 
     {
       uint64_t vidNb = 1;
@@ -1817,7 +1817,7 @@ 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);
+    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);
@@ -1834,7 +1834,7 @@ void RdbmsCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity
       // place on the TAPE and TAPE_FILE tables
       TapeSearchCriteria searchCriteria;
       searchCriteria.vid = vid;
-      const auto tapes = getTapes(*conn, searchCriteria);
+      const auto tapes = getTapes(conn, searchCriteria);
 
       if(tapes.empty()) {
         throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it does not exist");
@@ -1848,7 +1848,7 @@ void RdbmsCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity
       }
     }
 
-    conn->commit();
+    conn.commit();
   } catch(exception::UserError &) {
     throw;
   } catch (exception::Exception &ex) {
@@ -1905,7 +1905,7 @@ void RdbmsCatalogue::modifyTapeLogicalLibraryName(const common::dataStructures::
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    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);
@@ -1939,7 +1939,7 @@ void RdbmsCatalogue::modifyTapeTapePoolName(const common::dataStructures::Securi
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    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);
@@ -1973,7 +1973,7 @@ void RdbmsCatalogue::modifyTapeCapacityInBytes(const common::dataStructures::Sec
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    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);
@@ -2007,7 +2007,7 @@ void RdbmsCatalogue::modifyTapeEncryptionKey(const common::dataStructures::Secur
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    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);
@@ -2038,7 +2038,7 @@ 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);
+    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);
@@ -2067,7 +2067,7 @@ 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);
+    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);
@@ -2099,7 +2099,7 @@ void RdbmsCatalogue::setTapeFull(const common::dataStructures::SecurityIdentity
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    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);
@@ -2128,7 +2128,7 @@ void RdbmsCatalogue::noSpaceLeftOnTape(const std::string &vid) {
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":VID", vid);
     stmt->executeNonQuery();
 
@@ -2156,7 +2156,7 @@ void RdbmsCatalogue::setTapeDisabled(const common::dataStructures::SecurityIdent
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    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);
@@ -2190,7 +2190,7 @@ void RdbmsCatalogue::modifyTapeComment(const common::dataStructures::SecurityIde
       "WHERE "
         "VID = :VID";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    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);
@@ -2225,7 +2225,7 @@ 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);
+    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);
@@ -2262,7 +2262,7 @@ 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);
+    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);
@@ -2299,7 +2299,7 @@ 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);
+    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);
@@ -2336,7 +2336,7 @@ 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);
+    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);
@@ -2370,7 +2370,7 @@ void RdbmsCatalogue::createMountPolicy(
   const std::string &comment) {
   try {
     auto conn = m_connPool.getConn();
-    if(mountPolicyExists(*conn, name)) {
+    if(mountPolicyExists(conn, name)) {
       throw exception::UserError(std::string("Cannot create mount policy ") + name +
         " because a mount policy with the same name already exists");
     }
@@ -2416,7 +2416,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":MOUNT_POLICY_NAME", name);
 
@@ -2457,14 +2457,14 @@ void RdbmsCatalogue::createRequesterMountRule(
   const std::string &comment) {
   try {
     auto conn = m_connPool.getConn();
-    std::unique_ptr<common::dataStructures::MountPolicy> mountPolicy(getRequesterMountPolicy(*conn, diskInstanceName,
+    std::unique_ptr<common::dataStructures::MountPolicy> mountPolicy(getRequesterMountPolicy(conn, diskInstanceName,
       requesterName));
     if(nullptr != mountPolicy.get()) {
       throw exception::UserError(std::string("Cannot create rule to assign mount-policy ") + mountPolicyName +
         " to requester " + diskInstanceName + ":" + requesterName +
         " because the requester is already assigned to mount-policy " + mountPolicy->name);
     }
-    if(!mountPolicyExists(*conn, mountPolicyName)) {
+    if(!mountPolicyExists(conn, mountPolicyName)) {
       throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName +
         " to requester " + diskInstanceName + ":" + requesterName + " because mount-policy " + mountPolicyName +
         " does not exist");
@@ -2499,7 +2499,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
     stmt->bindString(":REQUESTER_NAME", requesterName);
@@ -2547,7 +2547,7 @@ std::list<common::dataStructures::RequesterMountRule> RdbmsCatalogue::getRequest
       "FROM "
         "REQUESTER_MOUNT_RULE";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while(rset->next()) {
       common::dataStructures::RequesterMountRule rule;
@@ -2584,7 +2584,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
     stmt->bindString(":REQUESTER_NAME", requesterName);
     stmt->executeNonQuery();
@@ -2612,13 +2612,13 @@ void RdbmsCatalogue::createRequesterGroupMountRule(
   try {
     auto conn = m_connPool.getConn();
     std::unique_ptr<common::dataStructures::MountPolicy> mountPolicy(
-      getRequesterGroupMountPolicy(*conn, diskInstanceName, requesterGroupName));
+      getRequesterGroupMountPolicy(conn, diskInstanceName, requesterGroupName));
     if(nullptr != mountPolicy.get()) {
       throw exception::UserError(std::string("Cannot create rule to assign mount-policy ") + mountPolicyName +
         " to requester-group " + diskInstanceName + ":" + requesterGroupName +
         " because a rule already exists assigning the requester-group to mount-policy " + mountPolicy->name);
     }
-    if(!mountPolicyExists(*conn, mountPolicyName)) {
+    if(!mountPolicyExists(conn, mountPolicyName)) {
       throw exception::UserError(std::string("Cannot assign mount-policy ") + mountPolicyName + " to requester-group " +
         diskInstanceName + ":" + requesterGroupName + " because mount-policy " + mountPolicyName + " does not exist");
     }
@@ -2652,7 +2652,7 @@ 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::Stmt::AutocommitMode::ON);
 
     stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
     stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
@@ -2772,7 +2772,7 @@ std::list<common::dataStructures::RequesterGroupMountRule> RdbmsCatalogue::getRe
       "FROM "
         "REQUESTER_GROUP_MOUNT_RULE";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while(rset->next()) {
       common::dataStructures::RequesterGroupMountRule rule;
@@ -2811,7 +2811,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":DISK_INSTANCE_NAME", diskInstanceName);
     stmt->bindString(":REQUESTER_GROUP_NAME", requesterGroupName);
     stmt->executeNonQuery();
@@ -2979,7 +2979,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
     stmt->bindString(":MOUNT_POLICY_NAME", name);
     stmt->executeNonQuery();
 
@@ -3023,7 +3023,7 @@ std::list<common::dataStructures::MountPolicy> RdbmsCatalogue::getMountPolicies(
       "FROM "
         "MOUNT_POLICY";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     while (rset->next()) {
       common::dataStructures::MountPolicy policy;
@@ -3073,7 +3073,7 @@ 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);
+    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);
@@ -3107,7 +3107,7 @@ 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);
+    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);
@@ -3141,7 +3141,7 @@ 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);
+    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);
@@ -3175,7 +3175,7 @@ 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);
+    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);
@@ -3209,7 +3209,7 @@ 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);
+    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);
@@ -3243,7 +3243,7 @@ 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);
+    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);
@@ -3473,7 +3473,7 @@ std::list<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveFilesFo
     sql += " ORDER BY ARCHIVE_FILE.ARCHIVE_FILE_ID, TAPE_FILE.COPY_NB";
 
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     stmt->bindUint64(":STARTING_ARCHIVE_FILE_ID", startingArchiveFileId);
     if(searchCriteria.archiveFileId) {
       stmt->bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value());
@@ -3653,7 +3653,7 @@ 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::Stmt::AutocommitMode::OFF);
     if(searchCriteria.archiveFileId) {
       stmt->bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value());
     }
@@ -3705,7 +3705,7 @@ common::dataStructures::ArchiveFileSummary RdbmsCatalogue::getTapeFileSummary(
 common::dataStructures::ArchiveFile RdbmsCatalogue::getArchiveFileById(const uint64_t id) {
   try {
     auto conn = m_connPool.getConn();
-    std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile(getArchiveFile(*conn, id));
+    std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile(getArchiveFile(conn, id));
 
     // Throw an exception if the archive file does not exist
     if(nullptr == archiveFile.get()) {
@@ -3734,7 +3734,7 @@ 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);
+    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);
@@ -3758,9 +3758,9 @@ common::dataStructures::ArchiveFileQueueCriteria RdbmsCatalogue::prepareForNewFi
   const std::string &storageClassName, const common::dataStructures::UserIdentity &user) {
   try {
     auto conn = m_connPool.getConn();
-    const common::dataStructures::TapeCopyToPoolMap copyToPoolMap = getTapeCopyToPoolMap(*conn, diskInstanceName,
+    const common::dataStructures::TapeCopyToPoolMap copyToPoolMap = getTapeCopyToPoolMap(conn, diskInstanceName,
       storageClassName);
-    const uint64_t expectedNbRoutes = getExpectedNbArchiveRoutes(*conn, diskInstanceName, storageClassName);
+    const uint64_t expectedNbRoutes = getExpectedNbArchiveRoutes(conn, diskInstanceName, storageClassName);
 
     // Check that the number of archive routes is correct
     if(copyToPoolMap.empty()) {
@@ -3776,7 +3776,7 @@ common::dataStructures::ArchiveFileQueueCriteria RdbmsCatalogue::prepareForNewFi
       throw ex;
     }
 
-    const RequesterAndGroupMountPolicies mountPolicies = getMountPolicies(*conn, diskInstanceName, user.name,
+    const RequesterAndGroupMountPolicies mountPolicies = getMountPolicies(conn, diskInstanceName, user.name,
       user.group);
     // Requester mount policies overrule requester group mount policies
     common::dataStructures::MountPolicy mountPolicy;
@@ -3794,7 +3794,7 @@ common::dataStructures::ArchiveFileQueueCriteria RdbmsCatalogue::prepareForNewFi
 
     // Now that we have both the archive routes and the mount policy it's safe to
     // consume an archive file identifier
-    const uint64_t archiveFileId = getNextArchiveFileId(*conn);
+    const uint64_t archiveFileId = getNextArchiveFileId(conn);
 
     return common::dataStructures::ArchiveFileQueueCriteria(archiveFileId, copyToPoolMap, mountPolicy);
   } catch(exception::UserError &) {
@@ -3884,8 +3884,8 @@ void RdbmsCatalogue::fileWrittenToTape(const TapeFileWritten &event) {
     std::lock_guard<std::mutex> m_lock(m_mutex);
 
     auto conn = m_connPool.getConn();
-    rdbms::AutoRollback autoRollback(conn.get());
-    const common::dataStructures::Tape tape = selectTapeForUpdate(*conn, event.vid);
+    rdbms::AutoRollback autoRollback(conn);
+    const common::dataStructures::Tape tape = selectTapeForUpdate(conn, event.vid);
 
     const uint64_t expectedFSeq = tape.lastFSeq + 1;
     if(expectedFSeq != event.fSeq) {
@@ -3894,9 +3894,9 @@ void RdbmsCatalogue::fileWrittenToTape(const TapeFileWritten &event) {
         event.fSeq;
       throw ex;
     }
-    updateTape(*conn, event);
+    updateTape(conn, event);
 
-    std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile = getArchiveFile(*conn, event.archiveFileId);
+    std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile = getArchiveFile(conn, event.archiveFileId);
 
     // If the archive file does not already exist
     if(nullptr == archiveFile.get()) {
@@ -3913,7 +3913,7 @@ void RdbmsCatalogue::fileWrittenToTape(const TapeFileWritten &event) {
       row.diskFileUser = event.diskFileUser;
       row.diskFileGroup = event.diskFileGroup;
       row.diskFileRecoveryBlob = event.diskFileRecoveryBlob;
-      insertArchiveFile(*conn, row);
+      insertArchiveFile(conn, row);
     } else {
       throwIfCommonEventDataMismatch(*archiveFile, event);
     }
@@ -3926,9 +3926,9 @@ void RdbmsCatalogue::fileWrittenToTape(const TapeFileWritten &event) {
     tapeFile.compressedSize = event.compressedSize;
     tapeFile.copyNb         = event.copyNb;
     tapeFile.creationTime   = now;
-    insertTapeFile(*conn, tapeFile, event.archiveFileId);
+    insertTapeFile(conn, tapeFile, event.archiveFileId);
 
-    conn->commit();
+    conn.commit();
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) +  " failed: " + ex.getMessage().str());
   }
@@ -4025,7 +4025,7 @@ common::dataStructures::RetrieveFileQueueCriteria RdbmsCatalogue::prepareToRetri
   const common::dataStructures::UserIdentity &user) {
   try {
     auto conn = m_connPool.getConn();
-    std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile = getArchiveFile(*conn, archiveFileId);
+    std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile = getArchiveFile(conn, archiveFileId);
     if(nullptr == archiveFile.get()) {
       exception::Exception ex;
       ex.getMessage() << "Archive file with ID " << archiveFileId << " does not exist";
@@ -4040,7 +4040,7 @@ common::dataStructures::RetrieveFileQueueCriteria RdbmsCatalogue::prepareToRetri
       throw ue;
     }
 
-    const RequesterAndGroupMountPolicies mountPolicies = getMountPolicies(*conn, diskInstanceName, user.name,
+    const RequesterAndGroupMountPolicies mountPolicies = getMountPolicies(conn, diskInstanceName, user.name,
       user.group);
     // Requester mount policies overrule requester group mount policies
     common::dataStructures::MountPolicy mountPolicy;
@@ -4174,7 +4174,7 @@ RequesterAndGroupMountPolicies RdbmsCatalogue::getMountPolicies(
 //------------------------------------------------------------------------------
 bool RdbmsCatalogue::isAdmin(const common::dataStructures::SecurityIdentity &admin) const {
   auto conn = m_connPool.getConn();
-  return userIsAdmin(*conn, admin.username) && hostIsAdmin(*conn, admin.host);
+  return userIsAdmin(conn, admin.username) && hostIsAdmin(conn, admin.host);
 }
 
 //------------------------------------------------------------------------------
@@ -4234,7 +4234,7 @@ 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);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
     auto rset = stmt->executeQuery();
     while (rset->next()) {
@@ -4435,7 +4435,7 @@ bool RdbmsCatalogue::schemaIsLocked() const {
   try {
     const char *const sql = "SELECT SCHEMA_STATUS FROM CTA_CATALOGUE";
     auto conn = m_connPool.getConn();
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     auto rset = stmt->executeQuery();
     if(!rset->next()) {
       throw exception::Exception("The CTA_CATALOGUE table does not contain any rows when it should contain exactly "
@@ -4459,8 +4459,8 @@ void RdbmsCatalogue::lockSchema() {
   try {
     const char *const sql = "UPDATE CTA_CATALOGUE SET SCHEMA_STATUS = 'LOCKED'";
     auto conn = m_connPool.getConn();
-    rdbms::AutoRollback autoRollback(conn.get());
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    rdbms::AutoRollback autoRollback(conn);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     stmt->executeNonQuery();
     const uint64_t nbAffectedRows = stmt->getNbAffectedRows();
     switch(nbAffectedRows) {
@@ -4478,7 +4478,7 @@ void RdbmsCatalogue::lockSchema() {
         throw ex;
       }
     }
-    conn->commit();
+    conn.commit();
 
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -4492,8 +4492,8 @@ void RdbmsCatalogue::unlockSchema() {
   try {
     const char *const sql = "UPDATE CTA_CATALOGUE SET SCHEMA_STATUS = 'UNLOCKED'";
     auto conn = m_connPool.getConn();
-    rdbms::AutoRollback autoRollback(conn.get());
-    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+    rdbms::AutoRollback autoRollback(conn);
+    auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
     stmt->executeNonQuery();
     const uint64_t nbAffectedRows = stmt->getNbAffectedRows();
     switch(nbAffectedRows) {
@@ -4511,7 +4511,7 @@ void RdbmsCatalogue::unlockSchema() {
         throw ex;
       }
     }
-    conn->commit();
+    conn.commit();
 
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -4524,7 +4524,7 @@ void RdbmsCatalogue::unlockSchema() {
 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 stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
   auto rset = stmt->executeQuery();
 }
 
diff --git a/catalogue/SchemaCreatingSqliteCatalogue.cpp b/catalogue/SchemaCreatingSqliteCatalogue.cpp
index 8127b15181..1465eb60ca 100644
--- a/catalogue/SchemaCreatingSqliteCatalogue.cpp
+++ b/catalogue/SchemaCreatingSqliteCatalogue.cpp
@@ -43,7 +43,7 @@ void SchemaCreatingSqliteCatalogue::createCatalogueSchema() {
   try {
     const SqliteCatalogueSchema schema;
     auto conn = m_connPool.getConn();
-    conn->executeNonQueries(schema.sql);
+    conn.executeNonQueries(schema.sql);
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
   }
diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp
index c89d0e0c8f..6ec627d85e 100644
--- a/catalogue/SqliteCatalogue.cpp
+++ b/catalogue/SqliteCatalogue.cpp
@@ -49,8 +49,8 @@ SqliteCatalogue::~SqliteCatalogue() {
 common::dataStructures::ArchiveFile SqliteCatalogue::deleteArchiveFile(const std::string &diskInstanceName, const uint64_t archiveFileId) {
   try {
     auto conn = m_connPool.getConn();
-    rdbms::AutoRollback autoRollback(conn.get());
-    const auto archiveFile = getArchiveFile(*conn, archiveFileId);
+    rdbms::AutoRollback autoRollback(conn);
+    const auto archiveFile = getArchiveFile(conn, archiveFileId);
 
     if(nullptr == archiveFile.get()) {
       exception::UserError ue;
@@ -69,19 +69,19 @@ common::dataStructures::ArchiveFile SqliteCatalogue::deleteArchiveFile(const std
 
     {
       const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;";
-      auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
       stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
       stmt->executeNonQuery();
     }
 
     {
       const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;";
-      auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
+      auto stmt = conn.createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
       stmt->bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
       stmt->executeNonQuery();
     }
 
-    conn->commit();
+    conn.commit();
 
     return *archiveFile;
   } catch(exception::UserError &) {
@@ -96,7 +96,7 @@ common::dataStructures::ArchiveFile SqliteCatalogue::deleteArchiveFile(const std
 //------------------------------------------------------------------------------
 uint64_t SqliteCatalogue::getNextArchiveFileId(rdbms::Conn &conn) {
   try {
-    rdbms::AutoRollback autoRollback(&conn);
+    rdbms::AutoRollback autoRollback(conn);
 
     conn.executeNonQuery("UPDATE ARCHIVE_FILE_ID SET ID = ID + 1", rdbms::Stmt::AutocommitMode::OFF);
     uint64_t archiveFileId = 0;
diff --git a/rdbms/AutoRollback.cpp b/rdbms/AutoRollback.cpp
index 0314252875..639ddf5ba5 100644
--- a/rdbms/AutoRollback.cpp
+++ b/rdbms/AutoRollback.cpp
@@ -26,7 +26,9 @@ namespace rdbms {
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-AutoRollback::AutoRollback(Conn *const conn): m_conn(conn) {
+AutoRollback::AutoRollback(Conn &conn):
+  m_cancelled(false),
+  m_conn(conn) {
 }
 
 //------------------------------------------------------------------------------
@@ -34,8 +36,8 @@ AutoRollback::AutoRollback(Conn *const conn): m_conn(conn) {
 //------------------------------------------------------------------------------
 AutoRollback::~AutoRollback() {
   try {
-    if(nullptr != m_conn) {
-      m_conn->rollback();
+    if(!m_cancelled) {
+      m_conn.rollback();
     }
   } catch(...) {
     // Prevent destructor from throwing
@@ -46,7 +48,7 @@ AutoRollback::~AutoRollback() {
 // cancel
 //------------------------------------------------------------------------------
 void AutoRollback::cancel() {
-  m_conn = nullptr;
+  m_cancelled = true;
 }
 
 } // namespace rdbms
diff --git a/rdbms/AutoRollback.hpp b/rdbms/AutoRollback.hpp
index 2d82083636..5d7af16d86 100644
--- a/rdbms/AutoRollback.hpp
+++ b/rdbms/AutoRollback.hpp
@@ -36,10 +36,9 @@ public:
   /**
    * Constructor.
    *
-   * @param conn The database connection or nullptr if the no rollback should
-   * take place.
+   * @param conn The database connection.
    */
-  AutoRollback(Conn *const conn);
+  AutoRollback(Conn &conn);
 
   /**
    * Prevent copying.
@@ -65,10 +64,15 @@ public:
 
 private:
 
+  /**
+   * True if the automatica rollback has been cancelled.
+   */
+  bool m_cancelled;
+
   /**
    * The database connection or nullptr if no rollback should take place.
    */
-  Conn *m_conn;
+  Conn &m_conn;
 
 }; // class Login
 
diff --git a/rdbms/Conn.cpp b/rdbms/Conn.cpp
index 75462ba85c..f70c14b855 100644
--- a/rdbms/Conn.cpp
+++ b/rdbms/Conn.cpp
@@ -67,19 +67,5 @@ void Conn::executeNonQuery(const std::string &sql, const Stmt::AutocommitMode au
   }
 }
 
-//------------------------------------------------------------------------------
-// setHealthy
-//------------------------------------------------------------------------------
-void Conn::setHealthy(const bool value) {
-  m_healthy = value;
-}
-
-//------------------------------------------------------------------------------
-// getHealthy
-//------------------------------------------------------------------------------
-bool Conn::getHealthy() const {
-  return m_healthy;
-}
-
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/Conn.hpp b/rdbms/Conn.hpp
index 684b97e58c..ac2740b909 100644
--- a/rdbms/Conn.hpp
+++ b/rdbms/Conn.hpp
@@ -95,27 +95,9 @@ public:
   virtual std::list<std::string> getTableNames() = 0;
 
   /**
-   * Returns true if the connection is healthy.
-   *
-   * @return True if the connection is healthy.
-   */
-  bool getHealthy() const;
-
-protected:
-
-  /**
-   * Sets the status of the connection to be either healthy or not healthy.
-   *
-   * @param value True if the connection is healthy.
-   */
-  void setHealthy(const bool value);
-
-private:
-
-  /**
-   * True if the connection's state is healthy.
+   * Returns true if this connection is open.
    */
-  std::atomic<bool> m_healthy{true};
+  virtual bool isOpen() const = 0;
 
 }; // class Conn
 
diff --git a/rdbms/ConnPool.cpp b/rdbms/ConnPool.cpp
index e9101aa26e..d6e899128b 100644
--- a/rdbms/ConnPool.cpp
+++ b/rdbms/ConnPool.cpp
@@ -60,17 +60,21 @@ PooledConn ConnPool::getConn() {
     m_connsCv.wait(lock);
   }
 
-  PooledConn pooledConn(m_conns.front().release(), this);
+  std::unique_ptr<Conn> conn = std::move(m_conns.front());
   m_conns.pop_front();
-  return pooledConn;
+  if(conn->isOpen()) {
+    return PooledConn(std::move(conn), this);
+  } else {
+    return PooledConn(m_connFactory.create(), this);
+  }
 }
 
 //------------------------------------------------------------------------------
 // returnConn
 //------------------------------------------------------------------------------
 void ConnPool::returnConn(Conn *const conn) {
-  // If the connection is healthy
-  if(conn->getHealthy()) {
+  // If the connection is open
+  if(conn->isOpen()) {
 
     // Commit the connection and put it back in the pool
     conn->commit();
@@ -78,13 +82,17 @@ void ConnPool::returnConn(Conn *const conn) {
     m_conns.emplace_back(conn);
     m_connsCv.notify_one();
 
-  // Else the connection is not healthy
+  // Else the connection is closed
   } else {
 
-    // Close the connection and put a brand new one in the pool
-    delete conn;
+    // Close all connections in the pool and put the returning connection back
+    // in the pool.  A closed connection within the pool is reopened when it is
+    // pulled from the pool.
     std::unique_lock<std::mutex> lock(m_connsMutex);
-    m_conns.push_back(m_connFactory.create());
+    for(auto &connInPool : m_conns) {
+      connInPool->close();
+    }
+    m_conns.emplace_back(conn);
     m_connsCv.notify_one();
   }
 }
diff --git a/rdbms/ConnPool.hpp b/rdbms/ConnPool.hpp
index c3fa7ce853..a2e292d7a7 100644
--- a/rdbms/ConnPool.hpp
+++ b/rdbms/ConnPool.hpp
@@ -55,16 +55,23 @@ public:
    */
   PooledConn getConn();
 
+  /**
+   * Closes all the database connections currently in the pool.
+   */
+  void closeAllConns();
+
 private:
 
   friend PooledConn;
 
   /**
-   * If the specified database connection is healthy, then this method calls
+   * If the specified database connection is open, then this method calls
    * commit on the connection and returns it to the pool.
    *
-   * If the specified database connection is no healthy, then this method
-   * closes the connection and creates a new one in the connection pool.
+   * If the specified database connection is closed, then this method closes all
+   * connections within the pool.
+   *
+   * A closed connection is reopened when it is pulled from the pool.
    *
    * @param conn The connection to be commited and returned to the pool.
    */
diff --git a/rdbms/OcciConn.cpp b/rdbms/OcciConn.cpp
index de2a324918..d58a7823f3 100644
--- a/rdbms/OcciConn.cpp
+++ b/rdbms/OcciConn.cpp
@@ -146,38 +146,10 @@ std::list<std::string> OcciConn::getTableNames() {
 }
 
 //------------------------------------------------------------------------------
-// updateHealth
-//------------------------------------------------------------------------------
-void OcciConn::updateHealth(const oracle::occi::SQLException &ex) {
-  using namespace oracle;
-
-  // Error codes that identify an unhealthy connection
-  // The majority of these error codes were learnt from CASTOR
-  switch(ex.getErrorCode()) {
-  case    28:
-  case  1003:
-  case  1008:
-  case  1012:
-  case  1033:
-  case  1089:
-  case  2392:
-  case  2399:
-  case  3113:
-  case  3114:
-  case  3135:
-  case 12170:
-  case 12541:
-  case 12571:
-  case 24338:
-  case 12537:
-  case 25401:
-  case 25409:
-  case 32102:
-    setHealthy(false);
-    break;
-  default:
-    break;
-  };
+// isOpen
+//------------------------------------------------------------------------------
+bool OcciConn::isOpen() const {
+  return nullptr != m_conn;
 }
 
 } // namespace rdbms
diff --git a/rdbms/OcciConn.hpp b/rdbms/OcciConn.hpp
index 59c01ee0fa..a76bdf849f 100644
--- a/rdbms/OcciConn.hpp
+++ b/rdbms/OcciConn.hpp
@@ -103,6 +103,11 @@ public:
    */
   virtual std::list<std::string> getTableNames() override;
 
+  /**
+   * Returns true if this connection is open.
+   */
+  bool isOpen() const override;
+
 private:
 
   friend OcciStmt;
@@ -122,14 +127,6 @@ private:
    */
   oracle::occi::Connection *m_conn;
 
-  /**
-   * Determines whether or not the specified Oracle exception affects the status
-   * of the database connection and updates it accordingly.
-   *
-   * @param ex The Oracle exception.
-   */
-  void updateHealth(const oracle::occi::SQLException &ex);
-
 }; // class OcciConn
 
 } // namespace rdbms
diff --git a/rdbms/OcciStmt.cpp b/rdbms/OcciStmt.cpp
index 2aaf5583aa..c20d66b02d 100644
--- a/rdbms/OcciStmt.cpp
+++ b/rdbms/OcciStmt.cpp
@@ -181,7 +181,18 @@ std::unique_ptr<Rset> OcciStmt::executeQuery() {
   try {
     return cta::make_unique<OcciRset>(*this, m_stmt->executeQuery());
   } catch(occi::SQLException &ex) {
-    m_conn.updateHealth(ex);
+    if(connShouldBeClosed(ex)) {
+      // Close the statement first and then the connection
+      try {
+        close();
+      } catch(...) {
+      }
+
+      try {
+        m_conn.close();
+      } catch(...) {
+      }
+    }
     throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + getSql() + ": " + ex.what());
   }
 }
@@ -195,7 +206,18 @@ void OcciStmt::executeNonQuery() {
   try {
     m_stmt->executeUpdate();
   } catch(occi::SQLException &ex) {
-    m_conn.updateHealth(ex);
+    if(connShouldBeClosed(ex)) {
+      // Close the statement first and then the connection
+      try {
+        close();
+      } catch(...) {
+      }
+
+      try {
+        m_conn.close();
+      } catch(...) {
+      }
+    }
     throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + getSql() + ": " + ex.what());
   }
 }
@@ -221,5 +243,37 @@ oracle::occi::Statement *OcciStmt::operator->() const {
   return get();
 }
 
+//------------------------------------------------------------------------------
+// connShouldBeClosed
+//------------------------------------------------------------------------------
+bool OcciStmt::connShouldBeClosed(const oracle::occi::SQLException &ex) {
+  using namespace oracle;
+
+  switch(ex.getErrorCode()) {
+  case    28:
+  case  1003:
+  case  1008:
+  case  1012:
+  case  1033:
+  case  1089:
+  case  2392:
+  case  2399:
+  case  3113:
+  case  3114:
+  case  3135:
+  case 12170:
+  case 12541:
+  case 12571:
+  case 24338:
+  case 12537:
+  case 25401:
+  case 25409:
+  case 32102:
+    return true;
+  default:
+    return false;
+  };
+}
+
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/OcciStmt.hpp b/rdbms/OcciStmt.hpp
index d3e09f0a69..31f82740cb 100644
--- a/rdbms/OcciStmt.hpp
+++ b/rdbms/OcciStmt.hpp
@@ -180,6 +180,15 @@ private:
    */
   oracle::occi::Statement *m_stmt;
 
+  /**
+   * Determines whether or not the connection should be closed based on the
+   * specified Oracle exception.
+   *
+   * @param ex The Oracle exception.
+   * @return True if the connection should be closed.
+   */
+  static bool connShouldBeClosed(const oracle::occi::SQLException &ex);
+
 }; // class OcciStmt
 
 } // namespace rdbms
diff --git a/rdbms/PooledConn.cpp b/rdbms/PooledConn.cpp
index 70f8e28028..29f5a160a2 100644
--- a/rdbms/PooledConn.cpp
+++ b/rdbms/PooledConn.cpp
@@ -26,15 +26,23 @@ namespace rdbms {
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-PooledConn::PooledConn(Conn *const conn, ConnPool *pool) noexcept:
+PooledConn::PooledConn(Conn *const conn, ConnPool *pool):
   m_conn(conn),
   m_pool(pool) {
 }
 
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+PooledConn::PooledConn(std::unique_ptr<Conn> conn, ConnPool *pool):
+  m_conn(conn.release()),
+  m_pool(pool) {
+}
+
 //------------------------------------------------------------------------------
 // move constructor
 //------------------------------------------------------------------------------
-PooledConn::PooledConn(PooledConn &&other) noexcept:
+PooledConn::PooledConn(PooledConn &&other):
   m_conn(other.m_conn),
   m_pool(other.m_pool) {
   other.m_conn = nullptr;
@@ -54,30 +62,6 @@ PooledConn::~PooledConn() noexcept {
   }
 }
 
-//------------------------------------------------------------------------------
-// get()
-//------------------------------------------------------------------------------
-Conn *PooledConn::get() const noexcept {
-  return m_conn;
-}
-
-//------------------------------------------------------------------------------
-// operator->()
-//------------------------------------------------------------------------------
-Conn *PooledConn::operator->() const noexcept {
-  return m_conn;
-}
-
-//------------------------------------------------------------------------------
-// operator*()
-//------------------------------------------------------------------------------
-Conn &PooledConn::operator*() const {
-  if(nullptr == m_conn) {
-    throw exception::Exception(std::string(__FUNCTION__) + " failed: No database connection");
-  }
-  return *m_conn;
-}
-
 //------------------------------------------------------------------------------
 // operator=
 //------------------------------------------------------------------------------
@@ -100,5 +84,72 @@ PooledConn &PooledConn::operator=(PooledConn &&rhs) {
   return *this;
 }
 
+//------------------------------------------------------------------------------
+// close
+//------------------------------------------------------------------------------
+void PooledConn::close() {
+  if(nullptr != m_conn) {
+    m_conn->close();
+  } else {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: PooledConn does not contain a connection");
+  }
+}
+
+//------------------------------------------------------------------------------
+// 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");
+  }
+}
+
+//------------------------------------------------------------------------------
+// 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
index 701c5ae2e5..d0046c04e2 100644
--- a/rdbms/PooledConn.hpp
+++ b/rdbms/PooledConn.hpp
@@ -20,6 +20,8 @@
 
 #include "rdbms/Conn.hpp"
 
+#include <memory>
+
 namespace cta {
 namespace rdbms {
 
@@ -33,7 +35,7 @@ class ConnPool;
  * A smart database connection that will automatically return itself to its
  * parent connection pool when it goes out of scope.
  */
-class PooledConn {
+class PooledConn: public Conn {
 public:
 
   /**
@@ -43,7 +45,16 @@ public:
    * @param pool The database connection pool to which the connection
    * should be returned.
    */
-  PooledConn(Conn *const conn, ConnPool *const pool) noexcept;
+  PooledConn(Conn *const conn, ConnPool *const pool);
+
+  /**
+   * 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.
@@ -55,7 +66,7 @@ public:
    *
    * @param other The other object.
    */
-  PooledConn(PooledConn &&other) noexcept;
+  PooledConn(PooledConn &&other);
 
   /**
    * Destructor.
@@ -65,40 +76,55 @@ public:
   ~PooledConn() noexcept;
 
   /**
-   * Returns the owned database connection.
-   *
-   * @return The owned database connection.
+   * Deletion of the copy assignment operator.
    */
-  Conn *get() const noexcept;
+  PooledConn &operator=(const PooledConn &) = delete;
+
   /**
-   * Returns the owned database connection.
+   * Move assignment operator.
    *
-   * @return The owned database connection.
+   * @param rhs The object on the right-hand side of the operator.
+   * @return This object.
    */
-  Conn *operator->() const noexcept;
+  PooledConn &operator=(PooledConn &&rhs);
 
   /**
-   * Returns the owned database connection.
-   *
-   * This method throws an exception if this smart database connection does not
-   * currently own a database connection.
+   * Idempotent close() method.  The destructor calls this method.
+   */
+  void close() override;
+
+  /**
+   * Creates a prepared statement.
    *
-   * @return The owned database connection.
+   * @param sql The SQL statement.
+   * @param autocommitMode The autocommit mode of the statement.
+   * @return The prepared statement.
    */
-  Conn &operator*() const;
+  std::unique_ptr<Stmt> createStmt(const std::string &sql, const Stmt::AutocommitMode autocommitMode) override;
 
   /**
-   * Deletion of the copy assignment operator.
+   * Commits the current transaction.
    */
-  PooledConn &operator=(const PooledConn &) = delete;
+  void commit() override;
 
   /**
-   * Move assignment operator.
+   * Rolls back the current transaction.
+   */
+  void rollback() override;
+
+  /**
+   * Returns the names of all the tables in the database schema in alphabetical
+   * order.
    *
-   * @param rhs The object on the right-hand side of the operator.
-   * @return This object.
+   * @return The names of all the tables in the database schema in alphabetical
+   * order.
    */
-  PooledConn &operator=(PooledConn &&rhs);
+  std::list<std::string> getTableNames() override;
+
+  /**
+   * Returns true if this connection is open.
+   */
+  bool isOpen() const override;
 
 private:
 
diff --git a/rdbms/SqliteConn.cpp b/rdbms/SqliteConn.cpp
index 7b14cc5bcd..e3b8cf9d5b 100644
--- a/rdbms/SqliteConn.cpp
+++ b/rdbms/SqliteConn.cpp
@@ -192,5 +192,12 @@ std::list<std::string> SqliteConn::getTableNames() {
   }
 }
 
+//------------------------------------------------------------------------------
+// isOpen
+//------------------------------------------------------------------------------
+bool SqliteConn::isOpen() const {
+  return nullptr != m_conn;
+}
+
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/SqliteConn.hpp b/rdbms/SqliteConn.hpp
index d22dfd85ac..7bcfac3eab 100644
--- a/rdbms/SqliteConn.hpp
+++ b/rdbms/SqliteConn.hpp
@@ -59,7 +59,7 @@ public:
   /**
    * Idempotent close() method.  The destructor calls this method.
    */
-  virtual void close();
+  void close() override;
 
   /**
    * Creates a prepared statement.
@@ -68,17 +68,17 @@ 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;
+  std::unique_ptr<Stmt> createStmt(const std::string &sql, const Stmt::AutocommitMode autocommitMode) override;
 
   /**
    * Commits the current transaction.
    */
-  virtual void commit() override;
+  void commit() override;
 
   /**
    * Rolls back the current transaction.
    */
-  virtual void rollback() override;
+  void rollback() override;
 
   /**
    * Returns the names of all the tables in the database schema in alphabetical
@@ -87,7 +87,12 @@ public:
    * @return The names of all the tables in the database schema in alphabetical
    * order.
    */
-  virtual std::list<std::string> getTableNames() override;
+  std::list<std::string> getTableNames() override;
+
+  /**
+   * Returns true if this connection is open.
+   */
+  bool isOpen() const override;
 
   /**
    * This ia an SqliteConn specific method that prints the database schema to
-- 
GitLab