From 909d4325fd72185c3dbab76da956b4fd6e667d77 Mon Sep 17 00:00:00 2001
From: Steven Murray <Steven.Murray@cern.ch>
Date: Wed, 16 Mar 2016 11:32:56 +0100
Subject: [PATCH] Added SqliteCatalogue::createTape

---
 catalogue/SqliteCatalogue.cpp     | 549 ++++++++++++++++++++++--------
 catalogue/SqliteCatalogue.hpp     |   2 +-
 catalogue/SqliteCatalogueTest.cpp | 183 +++++++---
 catalogue/SqliteConn.cpp          |  25 ++
 catalogue/SqliteConn.hpp          |  21 ++
 catalogue/SqliteStmt.cpp          |  27 +-
 catalogue/SqliteStmt.hpp          |  20 +-
 catalogue/SqliteStmtTest.cpp      |  62 ++--
 doxygen/.gitignore                |   3 +-
 9 files changed, 641 insertions(+), 251 deletions(-)

diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp
index 1063ecfe26..cd8734ff5c 100644
--- a/catalogue/SqliteCatalogue.cpp
+++ b/catalogue/SqliteCatalogue.cpp
@@ -20,6 +20,7 @@
 #include "catalogue/SqliteStmt.hpp"
 #include "common/exception/Exception.hpp"
 
+#include <memory>
 #include <sqlite3.h>
 #include <time.h>
 
@@ -152,6 +153,48 @@ void cta::catalogue::SqliteCatalogue::createDbSchema() {
       "LAST_MOD_TIME       INTEGER,"
 
       "PRIMARY KEY(LOGICAL_LIBRARY_NAME)"
+    ");"
+
+    "CREATE TABLE TAPE("
+      "VID                  TEXT,"
+      "LOGICAL_LIBRARY_NAME TEXT,"
+      "TAPE_POOL_NAME       TEXT,"
+      "ENCRYPTION_KEY       TEXT,"
+      "CAPACITY_IN_BYTES    INTEGER,"
+      "DATA_IN_BYTES        INTEGER,"
+      "LAST_FSEQ            INTEGER,"
+      "IS_BUSY              INTEGER,"
+      "IS_DISABLED          INTEGER,"
+      "IS_FULL              INTEGER,"
+      "LBP_IS_ON            INTEGER,"
+
+      "LABEL_DRIVE TEXT,"
+      "LABEL_TIME  INTEGER,"
+
+      "LAST_READ_DRIVE TEXT,"
+      "LAST_READ_TIME  INTEGER,"
+
+      "LAST_WRITE_DRIVE TEXT,"
+      "LAST_WRITE_TIME  INTEGER,"
+
+      "COMMENT TEXT,"
+
+      "CREATION_LOG_USER_NAME  TEXT,"
+      "CREATION_LOG_GROUP_NAME TEXT,"
+      "CREATION_LOG_HOST_NAME  TEXT,"
+      "CREATION_LOG_TIME       INTEGER,"
+
+      "LAST_MOD_USER_NAME  TEXT,"
+      "LAST_MOD_GROUP_NAME TEXT,"
+      "LAST_MOD_HOST_NAME  TEXT,"
+      "LAST_MOD_TIME       INTEGER,"
+
+      "PRIMARY KEY(VID),"
+
+      "FOREIGN KEY(LOGICAL_LIBRARY_NAME) REFERENCES "
+        "LOGICAL_LIBRARY(LOGICAL_LIBRARY_NAME),"
+      "FOREIGN KEY(TAPE_POOL_NAME) REFERENCES "
+        "TAPE_POOL(TAPE_POOL_NAME)"
     ");";
   m_conn.enableForeignKeys();
   m_conn.execNonQuery(sql);
@@ -213,18 +256,18 @@ void cta::catalogue::SqliteCatalogue::createAdminUser(
       ":CREATION_LOG_GROUP_NAME,"
       ":CREATION_LOG_HOST_NAME,"
       ":CREATION_LOG_TIME);";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
 
-  stmt.bind(":USER_NAME", user.name);
-  stmt.bind(":GROUP_NAME", user.group);
-  stmt.bind(":COMMENT", comment);
+  stmt->bind(":USER_NAME", user.name);
+  stmt->bind(":GROUP_NAME", user.group);
+  stmt->bind(":COMMENT", comment);
 
-  stmt.bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
-  stmt.bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
-  stmt.bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
-  stmt.bind(":CREATION_LOG_TIME", now);
+  stmt->bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
+  stmt->bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
+  stmt->bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
+  stmt->bind(":CREATION_LOG_TIME", now);
 
-  stmt.step();
+  stmt->step();
 }
 
 //------------------------------------------------------------------------------
@@ -255,41 +298,41 @@ std::list<cta::common::dataStructures::AdminUser>
       "LAST_MOD_HOST_NAME  AS LAST_MOD_HOST_NAME,"
       "LAST_MOD_TIME       AS LAST_MOD_TIME "
     "FROM ADMIN_USER";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
   ColumnNameToIdx  nameToIdx;
-  while(SQLITE_ROW == stmt.step()) {
+  while(SQLITE_ROW == stmt->step()) {
     if(nameToIdx.empty()) {
-      nameToIdx = stmt.getColumnNameToIdx();
+      nameToIdx = stmt->getColumnNameToIdx();
     }
     common::dataStructures::AdminUser admin;
 
     common::dataStructures::UserIdentity adminUI;
-    adminUI.name = stmt.columnText(nameToIdx["USER_NAME"]);
-    adminUI.group = stmt.columnText(nameToIdx["GROUP_NAME"]);
+    adminUI.name = stmt->columnText(nameToIdx["USER_NAME"]);
+    adminUI.group = stmt->columnText(nameToIdx["GROUP_NAME"]);
 
     admin.user = adminUI;
 
-    admin.comment = stmt.columnText(nameToIdx["COMMENT"]);
+    admin.comment = stmt->columnText(nameToIdx["COMMENT"]);
 
     common::dataStructures::UserIdentity creatorUI;
-    creatorUI.name = stmt.columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
-    creatorUI.group = stmt.columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
+    creatorUI.name = stmt->columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
+    creatorUI.group = stmt->columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
 
     common::dataStructures::EntryLog creationLog;
     creationLog.user = creatorUI;
-    creationLog.host = stmt.columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
-    creationLog.time = stmt.columnUint64(nameToIdx["CREATION_LOG_TIME"]);
+    creationLog.host = stmt->columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
+    creationLog.time = stmt->columnUint64(nameToIdx["CREATION_LOG_TIME"]);
 
     admin.creationLog = creationLog;
 
     common::dataStructures::UserIdentity updaterUI;
-    updaterUI.name = stmt.columnText(nameToIdx["LAST_MOD_USER_NAME"]);
-    updaterUI.group = stmt.columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
+    updaterUI.name = stmt->columnText(nameToIdx["LAST_MOD_USER_NAME"]);
+    updaterUI.group = stmt->columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
 
     common::dataStructures::EntryLog updateLog;
     updateLog.user = updaterUI;
-    updateLog.host = stmt.columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
-    updateLog.time = stmt.columnUint64(nameToIdx["LAST_MOD_TIME"]);
+    updateLog.host = stmt->columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
+    updateLog.time = stmt->columnUint64(nameToIdx["LAST_MOD_TIME"]);
 
     admin.lastModificationLog = updateLog;
 
@@ -341,17 +384,17 @@ void cta::catalogue::SqliteCatalogue::createAdminHost(
       ":CREATION_LOG_GROUP_NAME,"
       ":CREATION_LOG_HOST_NAME,"
       ":CREATION_LOG_TIME);";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
 
-  stmt.bind(":HOST_NAME", hostName);
-  stmt.bind(":COMMENT", comment);
+  stmt->bind(":HOST_NAME", hostName);
+  stmt->bind(":COMMENT", comment);
 
-  stmt.bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
-  stmt.bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
-  stmt.bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
-  stmt.bind(":CREATION_LOG_TIME", now);
+  stmt->bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
+  stmt->bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
+  stmt->bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
+  stmt->bind(":CREATION_LOG_TIME", now);
 
-  stmt.step();
+  stmt->step();
 }
 
 //------------------------------------------------------------------------------
@@ -380,36 +423,36 @@ std::list<cta::common::dataStructures::AdminHost> cta::catalogue::SqliteCatalogu
       "LAST_MOD_HOST_NAME  AS LAST_MOD_HOST_NAME,"
       "LAST_MOD_TIME       AS LAST_MOD_TIME "
     "FROM ADMIN_HOST";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
   ColumnNameToIdx  nameToIdx;
-  while(SQLITE_ROW == stmt.step()) {
+  while(SQLITE_ROW == stmt->step()) {
     if(nameToIdx.empty()) {
-      nameToIdx = stmt.getColumnNameToIdx();
+      nameToIdx = stmt->getColumnNameToIdx();
     }
     common::dataStructures::AdminHost host;
 
-    host.name = stmt.columnText(nameToIdx["HOST_NAME"]);
-    host.comment = stmt.columnText(nameToIdx["COMMENT"]);
+    host.name = stmt->columnText(nameToIdx["HOST_NAME"]);
+    host.comment = stmt->columnText(nameToIdx["COMMENT"]);
 
     common::dataStructures::UserIdentity creatorUI;
-    creatorUI.name = stmt.columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
-    creatorUI.group = stmt.columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
+    creatorUI.name = stmt->columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
+    creatorUI.group = stmt->columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
 
     common::dataStructures::EntryLog creationLog;
     creationLog.user = creatorUI;
-    creationLog.host = stmt.columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
-    creationLog.time = stmt.columnUint64(nameToIdx["CREATION_LOG_TIME"]);
+    creationLog.host = stmt->columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
+    creationLog.time = stmt->columnUint64(nameToIdx["CREATION_LOG_TIME"]);
 
     host.creationLog = creationLog;
 
     common::dataStructures::UserIdentity updaterUI;
-    updaterUI.name = stmt.columnText(nameToIdx["LAST_MOD_USER_NAME"]);
-    updaterUI.group = stmt.columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
+    updaterUI.name = stmt->columnText(nameToIdx["LAST_MOD_USER_NAME"]);
+    updaterUI.group = stmt->columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
 
     common::dataStructures::EntryLog updateLog;
     updateLog.user = updaterUI;
-    updateLog.host = stmt.columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
-    updateLog.time = stmt.columnUint64(nameToIdx["LAST_MOD_TIME"]);
+    updateLog.host = stmt->columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
+    updateLog.time = stmt->columnUint64(nameToIdx["LAST_MOD_TIME"]);
 
     host.lastModificationLog = updateLog;
 
@@ -464,19 +507,19 @@ void cta::catalogue::SqliteCatalogue::createStorageClass(
       ":CREATION_LOG_GROUP_NAME,"
       ":CREATION_LOG_HOST_NAME,"
       ":CREATION_LOG_TIME);";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
 
-  stmt.bind(":STORAGE_CLASS_NAME", name);
-  stmt.bind(":NB_COPIES", nbCopies);
+  stmt->bind(":STORAGE_CLASS_NAME", name);
+  stmt->bind(":NB_COPIES", nbCopies);
 
-  stmt.bind(":COMMENT", comment);
+  stmt->bind(":COMMENT", comment);
 
-  stmt.bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
-  stmt.bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
-  stmt.bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
-  stmt.bind(":CREATION_LOG_TIME", now);
+  stmt->bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
+  stmt->bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
+  stmt->bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
+  stmt->bind(":CREATION_LOG_TIME", now);
 
-  stmt.step();
+  stmt->step();
 }
 
 //------------------------------------------------------------------------------
@@ -507,37 +550,37 @@ std::list<cta::common::dataStructures::StorageClass>
       "LAST_MOD_HOST_NAME  AS LAST_MOD_HOST_NAME,"
       "LAST_MOD_TIME       AS LAST_MOD_TIME "
     "FROM STORAGE_CLASS";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
   ColumnNameToIdx  nameToIdx;
-  while(SQLITE_ROW == stmt.step()) {
+  while(SQLITE_ROW == stmt->step()) {
     if(nameToIdx.empty()) {
-      nameToIdx = stmt.getColumnNameToIdx();
+      nameToIdx = stmt->getColumnNameToIdx();
     }
     common::dataStructures::StorageClass storageClass;
 
-    storageClass.name = stmt.columnText(nameToIdx["STORAGE_CLASS_NAME"]);
-    storageClass.nbCopies = stmt.columnUint64(nameToIdx["NB_COPIES"]);
-    storageClass.comment = stmt.columnText(nameToIdx["COMMENT"]);
+    storageClass.name = stmt->columnText(nameToIdx["STORAGE_CLASS_NAME"]);
+    storageClass.nbCopies = stmt->columnUint64(nameToIdx["NB_COPIES"]);
+    storageClass.comment = stmt->columnText(nameToIdx["COMMENT"]);
 
     common::dataStructures::UserIdentity creatorUI;
-    creatorUI.name = stmt.columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
-    creatorUI.group = stmt.columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
+    creatorUI.name = stmt->columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
+    creatorUI.group = stmt->columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
 
     common::dataStructures::EntryLog creationLog;
     creationLog.user = creatorUI;
-    creationLog.host = stmt.columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
-    creationLog.time = stmt.columnUint64(nameToIdx["CREATION_LOG_TIME"]);
+    creationLog.host = stmt->columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
+    creationLog.time = stmt->columnUint64(nameToIdx["CREATION_LOG_TIME"]);
 
     storageClass.creationLog = creationLog;
 
     common::dataStructures::UserIdentity updaterUI;
-    updaterUI.name = stmt.columnText(nameToIdx["LAST_MOD_USER_NAME"]);
-    updaterUI.group = stmt.columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
+    updaterUI.name = stmt->columnText(nameToIdx["LAST_MOD_USER_NAME"]);
+    updaterUI.group = stmt->columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
 
     common::dataStructures::EntryLog updateLog;
     updateLog.user = updaterUI;
-    updateLog.host = stmt.columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
-    updateLog.time = stmt.columnUint64(nameToIdx["LAST_MOD_TIME"]);
+    updateLog.host = stmt->columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
+    updateLog.time = stmt->columnUint64(nameToIdx["LAST_MOD_TIME"]);
 
     storageClass.lastModificationLog = updateLog;
 
@@ -600,20 +643,20 @@ void cta::catalogue::SqliteCatalogue::createTapePool(
       ":CREATION_LOG_GROUP_NAME,"
       ":CREATION_LOG_HOST_NAME,"
       ":CREATION_LOG_TIME);";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
 
-  stmt.bind(":TAPE_POOL_NAME", name);
-  stmt.bind(":NB_PARTIAL_TAPES", nbPartialTapes);
-  stmt.bind(":IS_ENCRYPTED", encryptionValue);
+  stmt->bind(":TAPE_POOL_NAME", name);
+  stmt->bind(":NB_PARTIAL_TAPES", nbPartialTapes);
+  stmt->bind(":IS_ENCRYPTED", encryptionValue);
 
-  stmt.bind(":COMMENT", comment);
+  stmt->bind(":COMMENT", comment);
 
-  stmt.bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
-  stmt.bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
-  stmt.bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
-  stmt.bind(":CREATION_LOG_TIME", now);
+  stmt->bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
+  stmt->bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
+  stmt->bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
+  stmt->bind(":CREATION_LOG_TIME", now);
 
-  stmt.step();
+  stmt->step();
 }
 
 //------------------------------------------------------------------------------
@@ -645,39 +688,39 @@ std::list<cta::common::dataStructures::TapePool>
       "LAST_MOD_HOST_NAME  AS LAST_MOD_HOST_NAME,"
       "LAST_MOD_TIME       AS LAST_MOD_TIME "
     "FROM TAPE_POOL";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
   ColumnNameToIdx  nameToIdx;
-  while(SQLITE_ROW == stmt.step()) {
+  while(SQLITE_ROW == stmt->step()) {
     if(nameToIdx.empty()) {
-      nameToIdx = stmt.getColumnNameToIdx();
+      nameToIdx = stmt->getColumnNameToIdx();
     }
     common::dataStructures::TapePool pool;
 
-    pool.name = stmt.columnText(nameToIdx["TAPE_POOL_NAME"]);
-    pool.nbPartialTapes = stmt.columnUint64(nameToIdx["NB_PARTIAL_TAPES"]);
-    pool.encryption = stmt.columnUint64(nameToIdx["IS_ENCRYPTED"]);
+    pool.name = stmt->columnText(nameToIdx["TAPE_POOL_NAME"]);
+    pool.nbPartialTapes = stmt->columnUint64(nameToIdx["NB_PARTIAL_TAPES"]);
+    pool.encryption = stmt->columnUint64(nameToIdx["IS_ENCRYPTED"]);
 
-    pool.comment = stmt.columnText(nameToIdx["COMMENT"]);
+    pool.comment = stmt->columnText(nameToIdx["COMMENT"]);
 
     common::dataStructures::UserIdentity creatorUI;
-    creatorUI.name = stmt.columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
-    creatorUI.group = stmt.columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
+    creatorUI.name = stmt->columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
+    creatorUI.group = stmt->columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
 
     common::dataStructures::EntryLog creationLog;
     creationLog.user = creatorUI;
-    creationLog.host = stmt.columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
-    creationLog.time = stmt.columnUint64(nameToIdx["CREATION_LOG_TIME"]);
+    creationLog.host = stmt->columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
+    creationLog.time = stmt->columnUint64(nameToIdx["CREATION_LOG_TIME"]);
 
     pool.creationLog = creationLog;
 
     common::dataStructures::UserIdentity updaterUI;
-    updaterUI.name = stmt.columnText(nameToIdx["LAST_MOD_USER_NAME"]);
-    updaterUI.group = stmt.columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
+    updaterUI.name = stmt->columnText(nameToIdx["LAST_MOD_USER_NAME"]);
+    updaterUI.group = stmt->columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
 
     common::dataStructures::EntryLog updateLog;
     updateLog.user = updaterUI;
-    updateLog.host = stmt.columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
-    updateLog.time = stmt.columnUint64(nameToIdx["LAST_MOD_TIME"]);
+    updateLog.host = stmt->columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
+    updateLog.time = stmt->columnUint64(nameToIdx["LAST_MOD_TIME"]);
 
     pool.lastModificationLog = updateLog;
 
@@ -745,20 +788,20 @@ void cta::catalogue::SqliteCatalogue::createArchiveRoute(
       ":CREATION_LOG_GROUP_NAME,"
       ":CREATION_LOG_HOST_NAME,"
       ":CREATION_LOG_TIME);";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
 
-  stmt.bind(":STORAGE_CLASS_NAME", storageClassName);
-  stmt.bind(":COPY_NB", copyNb);
-  stmt.bind(":TAPE_POOL_NAME", tapePoolName);
+  stmt->bind(":STORAGE_CLASS_NAME", storageClassName);
+  stmt->bind(":COPY_NB", copyNb);
+  stmt->bind(":TAPE_POOL_NAME", tapePoolName);
 
-  stmt.bind(":COMMENT", comment);
+  stmt->bind(":COMMENT", comment);
 
-  stmt.bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
-  stmt.bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
-  stmt.bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
-  stmt.bind(":CREATION_LOG_TIME", now);
+  stmt->bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
+  stmt->bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
+  stmt->bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
+  stmt->bind(":CREATION_LOG_TIME", now);
 
-  stmt.step();
+  stmt->step();
 }
 
 //------------------------------------------------------------------------------
@@ -790,39 +833,39 @@ std::list<cta::common::dataStructures::ArchiveRoute>
       "LAST_MOD_HOST_NAME  AS LAST_MOD_HOST_NAME,"
       "LAST_MOD_TIME       AS LAST_MOD_TIME "
     "FROM ARCHIVE_ROUTE";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
   ColumnNameToIdx  nameToIdx;
-  while(SQLITE_ROW == stmt.step()) {
+  while(SQLITE_ROW == stmt->step()) {
     if(nameToIdx.empty()) {
-      nameToIdx = stmt.getColumnNameToIdx();
+      nameToIdx = stmt->getColumnNameToIdx();
     }
     common::dataStructures::ArchiveRoute route;
 
-    route.storageClassName = stmt.columnText(nameToIdx["STORAGE_CLASS_NAME"]);
-    route.copyNb = stmt.columnUint64(nameToIdx["COPY_NB"]);
-    route.tapePoolName = stmt.columnText(nameToIdx["TAPE_POOL_NAME"]);
+    route.storageClassName = stmt->columnText(nameToIdx["STORAGE_CLASS_NAME"]);
+    route.copyNb = stmt->columnUint64(nameToIdx["COPY_NB"]);
+    route.tapePoolName = stmt->columnText(nameToIdx["TAPE_POOL_NAME"]);
 
-    route.comment = stmt.columnText(nameToIdx["COMMENT"]);
+    route.comment = stmt->columnText(nameToIdx["COMMENT"]);
 
     common::dataStructures::UserIdentity creatorUI;
-    creatorUI.name = stmt.columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
-    creatorUI.group = stmt.columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
+    creatorUI.name = stmt->columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
+    creatorUI.group = stmt->columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
 
     common::dataStructures::EntryLog creationLog;
     creationLog.user = creatorUI;
-    creationLog.host = stmt.columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
-    creationLog.time = stmt.columnUint64(nameToIdx["CREATION_LOG_TIME"]);
+    creationLog.host = stmt->columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
+    creationLog.time = stmt->columnUint64(nameToIdx["CREATION_LOG_TIME"]);
 
     route.creationLog = creationLog;
 
     common::dataStructures::UserIdentity updaterUI;
-    updaterUI.name = stmt.columnText(nameToIdx["LAST_MOD_USER_NAME"]);
-    updaterUI.group = stmt.columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
+    updaterUI.name = stmt->columnText(nameToIdx["LAST_MOD_USER_NAME"]);
+    updaterUI.group = stmt->columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
 
     common::dataStructures::EntryLog updateLog;
     updateLog.user = updaterUI;
-    updateLog.host = stmt.columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
-    updateLog.time = stmt.columnUint64(nameToIdx["LAST_MOD_TIME"]);
+    updateLog.host = stmt->columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
+    updateLog.time = stmt->columnUint64(nameToIdx["LAST_MOD_TIME"]);
 
     route.lastModificationLog = updateLog;
 
@@ -879,18 +922,18 @@ void cta::catalogue::SqliteCatalogue::createLogicalLibrary(
       ":CREATION_LOG_GROUP_NAME,"
       ":CREATION_LOG_HOST_NAME,"
       ":CREATION_LOG_TIME);";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
 
-  stmt.bind(":LOGICAL_LIBRARY_NAME", name);
+  stmt->bind(":LOGICAL_LIBRARY_NAME", name);
 
-  stmt.bind(":COMMENT", comment);
+  stmt->bind(":COMMENT", comment);
 
-  stmt.bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
-  stmt.bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
-  stmt.bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
-  stmt.bind(":CREATION_LOG_TIME", now);
+  stmt->bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
+  stmt->bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
+  stmt->bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
+  stmt->bind(":CREATION_LOG_TIME", now);
 
-  stmt.step();
+  stmt->step();
 }
 
 //------------------------------------------------------------------------------
@@ -920,37 +963,37 @@ std::list<cta::common::dataStructures::LogicalLibrary>
       "LAST_MOD_HOST_NAME  AS LAST_MOD_HOST_NAME,"
       "LAST_MOD_TIME       AS LAST_MOD_TIME "
     "FROM LOGICAL_LIBRARY";
-  SqliteStmt stmt(m_conn, sql);
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
   ColumnNameToIdx  nameToIdx;
-  while(SQLITE_ROW == stmt.step()) {
+  while(SQLITE_ROW == stmt->step()) {
     if(nameToIdx.empty()) {
-      nameToIdx = stmt.getColumnNameToIdx();
+      nameToIdx = stmt->getColumnNameToIdx();
     }
     common::dataStructures::LogicalLibrary lib;
 
-    lib.name = stmt.columnText(nameToIdx["LOGICAL_LIBRARY_NAME"]);
+    lib.name = stmt->columnText(nameToIdx["LOGICAL_LIBRARY_NAME"]);
 
-    lib.comment = stmt.columnText(nameToIdx["COMMENT"]);
+    lib.comment = stmt->columnText(nameToIdx["COMMENT"]);
 
     common::dataStructures::UserIdentity creatorUI;
-    creatorUI.name = stmt.columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
-    creatorUI.group = stmt.columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
+    creatorUI.name = stmt->columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
+    creatorUI.group = stmt->columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
 
     common::dataStructures::EntryLog creationLog;
     creationLog.user = creatorUI;
-    creationLog.host = stmt.columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
-    creationLog.time = stmt.columnUint64(nameToIdx["CREATION_LOG_TIME"]);
+    creationLog.host = stmt->columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
+    creationLog.time = stmt->columnUint64(nameToIdx["CREATION_LOG_TIME"]);
 
     lib.creationLog = creationLog;
 
     common::dataStructures::UserIdentity updaterUI;
-    updaterUI.name = stmt.columnText(nameToIdx["LAST_MOD_USER_NAME"]);
-    updaterUI.group = stmt.columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
+    updaterUI.name = stmt->columnText(nameToIdx["LAST_MOD_USER_NAME"]);
+    updaterUI.group = stmt->columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
 
     common::dataStructures::EntryLog updateLog;
     updateLog.user = updaterUI;
-    updateLog.host = stmt.columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
-    updateLog.time = stmt.columnUint64(nameToIdx["LAST_MOD_TIME"]);
+    updateLog.host = stmt->columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
+    updateLog.time = stmt->columnUint64(nameToIdx["LAST_MOD_TIME"]);
 
     lib.lastModificationLog = updateLog;
 
@@ -968,8 +1011,116 @@ void cta::catalogue::SqliteCatalogue::modifyLogicalLibraryComment(const common::
 //------------------------------------------------------------------------------
 // createTape
 //------------------------------------------------------------------------------
-void cta::catalogue::SqliteCatalogue::createTape(const cta::common::dataStructures::SecurityIdentity &cliIdentity, const std::string &vid, const std::string &logicalLibraryName, const std::string &tapePoolName,
-                          const std::string &encryptionKey, const uint64_t capacityInBytes, const bool disabledValue, const bool fullValue, const std::string &comment) {}
+void cta::catalogue::SqliteCatalogue::createTape(
+  const cta::common::dataStructures::SecurityIdentity &cliIdentity,
+  const std::string &vid,
+  const std::string &logicalLibraryName,
+  const std::string &tapePoolName,
+  const std::string &encryptionKey,
+  const uint64_t capacityInBytes,
+  const bool disabledValue,
+  const bool fullValue,
+  const std::string &comment) {
+  const time_t now = time(NULL);
+  const char *const sql =
+    "INSERT INTO TAPE("
+      "VID,"
+      "LOGICAL_LIBRARY_NAME,"
+      "TAPE_POOL_NAME,"
+      "ENCRYPTION_KEY,"
+      "CAPACITY_IN_BYTES,"
+      "DATA_IN_BYTES,"
+      "LAST_FSEQ,"
+      "IS_BUSY,"
+      "IS_DISABLED,"
+      "IS_FULL,"
+      "LBP_IS_ON,"
+
+      "LABEL_DRIVE,"
+      "LABEL_TIME,"
+
+      "LAST_READ_DRIVE,"
+      "LAST_READ_TIME,"
+
+      "LAST_WRITE_DRIVE,"
+      "LAST_WRITE_TIME,"
+
+      "COMMENT,"
+
+      "CREATION_LOG_USER_NAME,"
+      "CREATION_LOG_GROUP_NAME,"
+      "CREATION_LOG_HOST_NAME,"
+      "CREATION_LOG_TIME,"
+
+      "LAST_MOD_USER_NAME,"
+      "LAST_MOD_GROUP_NAME,"
+      "LAST_MOD_HOST_NAME,"
+      "LAST_MOD_TIME)"
+    "VALUES("
+      ":VID,"
+      ":LOGICAL_LIBRARY_NAME,"
+      ":TAPE_POOL_NAME,"
+      ":ENCRYPTION_KEY,"
+      ":CAPACITY_IN_BYTES,"
+      ":DATA_IN_BYTES,"
+      ":LAST_FSEQ,"
+      ":IS_BUSY,"
+      ":IS_DISABLED,"
+      ":IS_FULL,"
+      ":LBP_IS_ON,"
+
+      ":LABEL_DRIVE,"
+      ":LABEL_TIME,"
+
+      ":LAST_READ_DRIVE,"
+      ":LAST_READ_TIME,"
+
+      ":LAST_WRITE_DRIVE,"
+      ":LAST_WRITE_TIME,"
+
+      ":COMMENT,"
+
+      ":CREATION_LOG_USER_NAME,"
+      ":CREATION_LOG_GROUP_NAME,"
+      ":CREATION_LOG_HOST_NAME,"
+      ":CREATION_LOG_TIME,"
+
+      ":CREATION_LOG_USER_NAME,"
+      ":CREATION_LOG_GROUP_NAME,"
+      ":CREATION_LOG_HOST_NAME,"
+      ":CREATION_LOG_TIME);";
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
+
+  stmt->bind(":VID", vid);
+  stmt->bind(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
+  stmt->bind(":TAPE_POOL_NAME", tapePoolName);
+  stmt->bind(":ENCRYPTION_KEY", encryptionKey);
+  stmt->bind(":CAPACITY_IN_BYTES", capacityInBytes);
+  stmt->bind(":DATA_IN_BYTES", 0);
+  stmt->bind(":LAST_FSEQ", 0);
+  stmt->bind(":IS_BUSY", 0);
+  stmt->bind(":IS_DISABLED", disabledValue);
+  stmt->bind(":IS_FULL", fullValue);
+  stmt->bind(":LBP_IS_ON", 1);
+
+  stmt->bind(":LABEL_DRIVE", "");
+  stmt->bind(":LABEL_TIME", 0);
+
+  stmt->bind(":LAST_READ_DRIVE", "");
+  stmt->bind(":LAST_READ_TIME", 0);
+
+  stmt->bind(":LAST_WRITE_DRIVE", "");
+  stmt->bind(":LAST_WRITE_TIME", 0);
+
+  stmt->bind(":COMMENT", comment);
+
+  stmt->bind(":CREATION_LOG_USER_NAME", cliIdentity.user.name);
+  stmt->bind(":CREATION_LOG_GROUP_NAME", cliIdentity.user.group);
+  stmt->bind(":CREATION_LOG_HOST_NAME", cliIdentity.host);
+  stmt->bind(":CREATION_LOG_TIME", now);
+
+  stmt->step();
+}
 
 //------------------------------------------------------------------------------
 // deleteTape
@@ -979,8 +1130,110 @@ void cta::catalogue::SqliteCatalogue::deleteTape(const std::string &vid) {}
 //------------------------------------------------------------------------------
 // getTapes
 //------------------------------------------------------------------------------
-std::list<cta::common::dataStructures::Tape> cta::catalogue::SqliteCatalogue::getTapes(const std::string &vid, const std::string &logicalLibraryName, const std::string &tapePoolName,
-        const std::string &capacityInBytes, const std::string &disabledValue, const std::string &fullValue, const std::string &busyValue, const std::string &lbpValue) { return std::list<cta::common::dataStructures::Tape>();}
+std::list<cta::common::dataStructures::Tape>
+  cta::catalogue::SqliteCatalogue::getTapes(
+  const std::string &vid,
+  const std::string &logicalLibraryName,
+  const std::string &tapePoolName,
+  const std::string &capacityInBytes,
+  const std::string &disabledValue,
+  const std::string &fullValue,
+  const std::string &busyValue,
+  const std::string &lbpValue) {
+  std::list<cta::common::dataStructures::Tape> tapes;
+  const char *const sql =
+    "SELECT "
+      "VID                  AS VID,"
+      "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME,"
+      "TAPE_POOL_NAME       AS TAPE_POOL_NAME,"
+      "ENCRYPTION_KEY       AS ENCRYPTION_KEY,"
+      "CAPACITY_IN_BYTES    AS CAPACITY_IN_BYTES,"
+      "DATA_IN_BYTES        AS DATA_IN_BYTES,"
+      "LAST_FSEQ            AS LAST_FSEQ,"
+      "IS_BUSY              AS IS_BUSY,"
+      "IS_DISABLED          AS IS_DISABLED,"
+      "IS_FULL              AS IS_FULL,"
+      "LBP_IS_ON            AS LBP_IS_ON,"
+
+      "LABEL_DRIVE AS LABEL_DRIVE,"
+      "LABEL_TIME  AS LABEL_TIME,"
+
+      "LAST_READ_DRIVE AS LAST_READ_DRIVE,"
+      "LAST_READ_TIME  AS LAST_READ_TIME,"
+
+      "LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE,"
+      "LAST_WRITE_TIME  AS LAST_WRITE_TIME,"
+
+      "COMMENT AS COMMENT,"
+
+      "CREATION_LOG_USER_NAME  AS CREATION_LOG_USER_NAME,"
+      "CREATION_LOG_GROUP_NAME AS CREATION_LOG_GROUP_NAME,"
+      "CREATION_LOG_HOST_NAME  AS CREATION_LOG_HOST_NAME,"
+      "CREATION_LOG_TIME       AS CREATION_LOG_TIME,"
+
+      "LAST_MOD_USER_NAME  AS LAST_MOD_USER_NAME,"
+      "LAST_MOD_GROUP_NAME AS LAST_MOD_GROUP_NAME,"
+      "LAST_MOD_HOST_NAME  AS LAST_MOD_HOST_NAME,"
+      "LAST_MOD_TIME       AS LAST_MOD_TIME "
+    "FROM TAPE";
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
+  ColumnNameToIdx  nameToIdx;
+  while(SQLITE_ROW == stmt->step()) {
+    if(nameToIdx.empty()) {
+      nameToIdx = stmt->getColumnNameToIdx();
+    }
+    common::dataStructures::Tape tape;
+
+    tape.vid = stmt->columnText(nameToIdx["VID"]);
+    tape.logicalLibraryName = stmt->columnText(nameToIdx["LOGICAL_LIBRARY_NAME"]);
+    tape.tapePoolName = stmt->columnText(nameToIdx["TAPE_POOL_NAME"]);
+    tape.encryptionKey = stmt->columnText(nameToIdx["ENCRYPTION_KEY"]);
+    tape.capacityInBytes = stmt->columnUint64(nameToIdx["CAPACITY_IN_BYTES"]);
+    tape.dataOnTapeInBytes = stmt->columnUint64(nameToIdx["DATA_IN_BYTES"]);
+    tape.lastFSeq = stmt->columnUint64(nameToIdx["LAST_FSEQ"]);
+    tape.busy = stmt->columnUint64(nameToIdx["IS_BUSY"]);
+    tape.disabled = stmt->columnUint64(nameToIdx["IS_DISABLED"]);
+    tape.full = stmt->columnUint64(nameToIdx["IS_FULL"]);
+    tape.lbp = stmt->columnUint64(nameToIdx["LBP_IS_ON"]);
+
+    tape.labelLog.drive = stmt->columnText(nameToIdx["LABEL_DRIVE"]);
+    tape.labelLog.time = stmt->columnUint64(nameToIdx["LABEL_TIME"]);
+
+    tape.lastReadLog.drive = stmt->columnText(nameToIdx["LAST_READ_DRIVE"]);
+    tape.lastReadLog.time = stmt->columnUint64(nameToIdx["LAST_READ_TIME"]);
+
+    tape.lastWriteLog.drive = stmt->columnText(nameToIdx["LAST_WRITE_DRIVE"]);
+    tape.lastWriteLog.time = stmt->columnUint64(nameToIdx["LAST_WRITE_TIME"]);
+
+    tape.comment = stmt->columnText(nameToIdx["COMMENT"]);
+
+    common::dataStructures::UserIdentity creatorUI;
+    creatorUI.name = stmt->columnText(nameToIdx["CREATION_LOG_USER_NAME"]);
+    creatorUI.group = stmt->columnText(nameToIdx["CREATION_LOG_GROUP_NAME"]);
+
+    common::dataStructures::EntryLog creationLog;
+    creationLog.user = creatorUI;
+    creationLog.host = stmt->columnText(nameToIdx["CREATION_LOG_HOST_NAME"]);
+    creationLog.time = stmt->columnUint64(nameToIdx["CREATION_LOG_TIME"]);
+
+    tape.creationLog = creationLog;
+
+    common::dataStructures::UserIdentity updaterUI;
+    updaterUI.name = stmt->columnText(nameToIdx["LAST_MOD_USER_NAME"]);
+    updaterUI.group = stmt->columnText(nameToIdx["LAST_MOD_GROUP_NAME"]);
+
+    common::dataStructures::EntryLog updateLog;
+    updateLog.user = updaterUI;
+    updateLog.host = stmt->columnText(nameToIdx["LAST_MOD_HOST_NAME"]);
+    updateLog.time = stmt->columnUint64(nameToIdx["LAST_MOD_TIME"]);
+
+    tape.lastModificationLog = updateLog;
+
+    tapes.push_back(tape);
+  }
+
+  return tapes;
+}
 
 //------------------------------------------------------------------------------
 // reclaimTape
@@ -1277,9 +1530,9 @@ bool cta::catalogue::SqliteCatalogue::userIsAdmin(const std::string &userName)
       "USER_NAME AS USER_NAME "
     "FROM ADMIN_USER WHERE "
       "USER_NAME = :USER_NAME;";
-  SqliteStmt stmt(m_conn, sql);
-  stmt.bind(":USER_NAME", userName);
-  if(SQLITE_ROW == stmt.step()) {
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
+  stmt->bind(":USER_NAME", userName);
+  if(SQLITE_ROW == stmt->step()) {
     return true;
   } else {
     return false;
@@ -1296,9 +1549,9 @@ bool cta::catalogue::SqliteCatalogue::hostIsAdmin(const std::string &hostName)
       "HOST_NAME AS HOST_NAME "
     "FROM ADMIN_HOST WHERE "
       "HOST_NAME = :HOST_NAME;";
-  SqliteStmt stmt(m_conn, sql);
-  stmt.bind(":HOST_NAME", hostName);
-  if(SQLITE_ROW == stmt.step()) {
+  std::unique_ptr<SqliteStmt> stmt(m_conn.createStmt(sql));
+  stmt->bind(":HOST_NAME", hostName);
+  if(SQLITE_ROW == stmt->step()) {
     return true;
   } else {
     return false;
diff --git a/catalogue/SqliteCatalogue.hpp b/catalogue/SqliteCatalogue.hpp
index bd158729d4..e2eca83f09 100644
--- a/catalogue/SqliteCatalogue.hpp
+++ b/catalogue/SqliteCatalogue.hpp
@@ -164,7 +164,7 @@ private:
   /**
    * The connection to the underlying relational database.
    */
-  SqliteConn m_conn;
+  mutable SqliteConn m_conn;
 
   /**
    * Creates the database schema.
diff --git a/catalogue/SqliteCatalogueTest.cpp b/catalogue/SqliteCatalogueTest.cpp
index 55d2e47412..914b7db20e 100644
--- a/catalogue/SqliteCatalogueTest.cpp
+++ b/catalogue/SqliteCatalogueTest.cpp
@@ -68,12 +68,15 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createBootstrapAdminAndHostNoAuth) {
 
   catalogue::SqliteCatalogue catalogue;
 
+  ASSERT_TRUE(catalogue.getAdminUsers().empty());
+  ASSERT_TRUE(catalogue.getAdminHosts().empty());
+
   catalogue.createBootstrapAdminAndHostNoAuth(
     m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment);
 
   {
     std::list<common::dataStructures::AdminUser> admins;
-    ASSERT_NO_THROW(admins = catalogue.getAdminUsers());
+    admins = catalogue.getAdminUsers();
     ASSERT_EQ(1, admins.size());
 
     const common::dataStructures::AdminUser admin = admins.front();
@@ -91,7 +94,7 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createBootstrapAdminAndHostNoAuth) {
 
   {
     std::list<common::dataStructures::AdminHost> hosts;
-    ASSERT_NO_THROW(hosts = catalogue.getAdminHosts());
+    hosts = catalogue.getAdminHosts();
     ASSERT_EQ(1, hosts.size());
 
     const common::dataStructures::AdminHost host = hosts.front();
@@ -113,12 +116,14 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminUser) {
 
   catalogue::SqliteCatalogue catalogue;
 
-  ASSERT_NO_THROW(catalogue.createBootstrapAdminAndHostNoAuth(
-    m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment));
+  ASSERT_TRUE(catalogue.getAdminUsers().empty());
+
+  catalogue.createBootstrapAdminAndHostNoAuth(
+    m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment);
 
   {
     std::list<common::dataStructures::AdminUser> admins;
-    ASSERT_NO_THROW(admins = catalogue.getAdminUsers());
+    admins = catalogue.getAdminUsers();
     ASSERT_EQ(1, admins.size());
 
     const common::dataStructures::AdminUser admin = admins.front();
@@ -135,8 +140,8 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminUser) {
   }
 
   const std::string createAdminUserComment = "create admin user";
-  ASSERT_NO_THROW(catalogue.createAdminUser(m_bootstrapAdminSI, m_adminUI,
-    createAdminUserComment));
+  catalogue.createAdminUser(m_bootstrapAdminSI, m_adminUI,
+    createAdminUserComment);
 
   {
     std::list<common::dataStructures::AdminUser> admins;
@@ -183,17 +188,17 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminUser) {
   }
 }
 
-TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminUser_same_admin_twice) {
+TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminUser_same_twice) {
   using namespace cta;
 
   catalogue::SqliteCatalogue catalogue;
 
-  ASSERT_NO_THROW(catalogue.createBootstrapAdminAndHostNoAuth(
-    m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment));
+  catalogue.createBootstrapAdminAndHostNoAuth(
+    m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment);
 
   {
     std::list<common::dataStructures::AdminUser> admins;
-    ASSERT_NO_THROW(admins = catalogue.getAdminUsers());
+    admins = catalogue.getAdminUsers();
     ASSERT_EQ(1, admins.size());
 
     const common::dataStructures::AdminUser admin = admins.front();
@@ -209,8 +214,7 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminUser_same_admin_twice) {
     ASSERT_EQ(creationLog, lastModificationLog);
   }
 
-  ASSERT_NO_THROW(catalogue.createAdminUser(m_bootstrapAdminSI, m_adminUI,
-    "comment 1"));
+  catalogue.createAdminUser(m_bootstrapAdminSI, m_adminUI, "comment 1");
 
   ASSERT_THROW(catalogue.createAdminUser(m_bootstrapAdminSI, m_adminUI,
     "comment 2"), exception::Exception);
@@ -221,12 +225,14 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminHost) {
 
   catalogue::SqliteCatalogue catalogue;
 
-  ASSERT_NO_THROW(catalogue.createBootstrapAdminAndHostNoAuth(
-    m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment));
+  ASSERT_TRUE(catalogue.getAdminHosts().empty());
+
+  catalogue.createBootstrapAdminAndHostNoAuth(
+    m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment);
 
   {
     std::list<common::dataStructures::AdminUser> admins;
-    ASSERT_NO_THROW(admins = catalogue.getAdminUsers());
+    admins = catalogue.getAdminUsers();
     ASSERT_EQ(1, admins.size());
 
     const common::dataStructures::AdminUser admin = admins.front();
@@ -244,8 +250,8 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminHost) {
 
   const std::string createAdminHostComment = "create host user";
   const std::string anotherAdminHost = "another_admin_host";
-  ASSERT_NO_THROW(catalogue.createAdminHost(m_bootstrapAdminSI,
-    anotherAdminHost, createAdminHostComment));
+  catalogue.createAdminHost(m_bootstrapAdminSI,
+    anotherAdminHost, createAdminHostComment);
 
   {
     std::list<common::dataStructures::AdminHost> hosts;
@@ -295,17 +301,17 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminHost) {
   }
 }
 
-TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminHost_same_host_twice) {
+TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminHost_same_twice) {
   using namespace cta;
 
   catalogue::SqliteCatalogue catalogue;
 
-  ASSERT_NO_THROW(catalogue.createBootstrapAdminAndHostNoAuth(
-    m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment));
+  catalogue.createBootstrapAdminAndHostNoAuth(
+    m_cliSI, m_bootstrapAdminUI, m_bootstrapAdminSI.host, m_bootstrapComment);
 
   {
     std::list<common::dataStructures::AdminUser> admins;
-    ASSERT_NO_THROW(admins = catalogue.getAdminUsers());
+    admins = catalogue.getAdminUsers();
     ASSERT_EQ(1, admins.size());
 
     const common::dataStructures::AdminUser admin = admins.front();
@@ -323,8 +329,7 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createAdminHost_same_host_twice) {
 
   const std::string anotherAdminHost = "another_admin_host";
 
-  ASSERT_NO_THROW(catalogue.createAdminHost(m_bootstrapAdminSI,
-    anotherAdminHost, "comment 1"));
+  catalogue.createAdminHost(m_bootstrapAdminSI, anotherAdminHost, "comment 1");
 
   ASSERT_THROW(catalogue.createAdminHost(m_bootstrapAdminSI,
     anotherAdminHost, "coment 2"), exception::Exception);
@@ -354,11 +359,12 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createStorageClass) {
 
   catalogue::SqliteCatalogue catalogue;
 
+  ASSERT_TRUE(catalogue.getStorageClasses().empty());
+
   const std::string storageClassName = "storage_class";
   const uint64_t nbCopies = 2;
   const std::string comment = "create storage class";
-  ASSERT_NO_THROW(catalogue.createStorageClass(m_cliSI,
-    storageClassName, nbCopies, comment));
+  catalogue.createStorageClass(m_cliSI, storageClassName, nbCopies, comment);
 
   const std::list<common::dataStructures::StorageClass> storageClasses =
     catalogue.getStorageClasses();
@@ -381,7 +387,7 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createStorageClass) {
   ASSERT_EQ(creationLog, lastModificationLog);
 }
 
-TEST_F(cta_catalogue_SqliteCatalogueTest, createStorageClass_same_name_twice) {
+TEST_F(cta_catalogue_SqliteCatalogueTest, createStorageClass_same_twice) {
   using namespace cta;
 
   catalogue::SqliteCatalogue catalogue;
@@ -389,8 +395,7 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createStorageClass_same_name_twice) {
   const std::string storageClassName = "storage_class";
   const uint64_t nbCopies = 2;
   const std::string comment = "create storage class";
-  ASSERT_NO_THROW(catalogue.createStorageClass(m_cliSI,
-    storageClassName, nbCopies, comment));
+  catalogue.createStorageClass(m_cliSI, storageClassName, nbCopies, comment);
   ASSERT_THROW(catalogue.createStorageClass(m_cliSI,
     storageClassName, nbCopies, comment), exception::Exception);
 }
@@ -399,13 +404,15 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createTapePool) {
   using namespace cta;
       
   catalogue::SqliteCatalogue catalogue;
+
+  ASSERT_TRUE(catalogue.getTapePools().empty());
       
   const std::string tapePoolName = "tape_pool";
   const uint64_t nbPartialTapes = 2;
   const bool is_encrypted = true;
   const std::string comment = "create tape pool";
-  ASSERT_NO_THROW(catalogue.createTapePool(m_cliSI,
-    tapePoolName, nbPartialTapes, is_encrypted, comment));
+  catalogue.createTapePool(m_cliSI, tapePoolName, nbPartialTapes, is_encrypted,
+    comment);
       
   const std::list<common::dataStructures::TapePool> pools =
     catalogue.getTapePools();
@@ -428,7 +435,7 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createTapePool) {
   ASSERT_EQ(creationLog, lastModificationLog);
 }
   
-TEST_F(cta_catalogue_SqliteCatalogueTest, createTapePool_same_name_twice) {
+TEST_F(cta_catalogue_SqliteCatalogueTest, createTapePool_same_twice) {
   using namespace cta;
   
   catalogue::SqliteCatalogue catalogue;
@@ -437,8 +444,8 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createTapePool_same_name_twice) {
   const uint64_t nbPartialTapes = 2;
   const bool is_encrypted = true;
   const std::string comment = "create tape pool";
-  ASSERT_NO_THROW(catalogue.createTapePool(m_cliSI,
-    tapePoolName, nbPartialTapes, is_encrypted, comment));
+  catalogue.createTapePool(m_cliSI, tapePoolName, nbPartialTapes, is_encrypted,
+    comment);
   ASSERT_THROW(catalogue.createTapePool(m_cliSI,
     tapePoolName, nbPartialTapes, is_encrypted, comment),
     exception::Exception);
@@ -449,21 +456,23 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createArchiveRoute) {
       
   catalogue::SqliteCatalogue catalogue;
 
+  ASSERT_TRUE(catalogue.getArchiveRoutes().empty());
+
   const std::string storageClassName = "storage_class";
   const uint64_t nbCopies = 2;
-  ASSERT_NO_THROW(catalogue.createStorageClass(m_cliSI,
-    storageClassName, nbCopies, "create storage class"));
+  catalogue.createStorageClass(m_cliSI, storageClassName, nbCopies,
+    "create storage class");
       
   const std::string tapePoolName = "tape_pool";
   const uint64_t nbPartialTapes = 2;
   const bool is_encrypted = true;
-  ASSERT_NO_THROW(catalogue.createTapePool(m_cliSI,
-    tapePoolName, nbPartialTapes, is_encrypted, "create tape pool"));
+  catalogue.createTapePool(m_cliSI, tapePoolName, nbPartialTapes, is_encrypted,
+    "create tape pool");
 
   const uint64_t copyNb = 1;
   const std::string comment = "create archive route";
-  ASSERT_NO_THROW(catalogue.createArchiveRoute(m_cliSI,
-    storageClassName, copyNb, tapePoolName, comment));
+  catalogue.createArchiveRoute(m_cliSI, storageClassName, copyNb, tapePoolName,
+    comment);
       
   const std::list<common::dataStructures::ArchiveRoute> routes =
     catalogue.getArchiveRoutes();
@@ -493,19 +502,19 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createArchiveRouteTapePool_same_twice)
 
   const std::string storageClassName = "storage_class";
   const uint64_t nbCopies = 2;
-  ASSERT_NO_THROW(catalogue.createStorageClass(m_cliSI,
-    storageClassName, nbCopies, "create storage class"));
+  catalogue.createStorageClass(m_cliSI, storageClassName, nbCopies,
+    "create storage class");
       
   const std::string tapePoolName = "tape_pool";
   const uint64_t nbPartialTapes = 2;
   const bool is_encrypted = true;
-  ASSERT_NO_THROW(catalogue.createTapePool(m_cliSI,
-    tapePoolName, nbPartialTapes, is_encrypted, "create tape pool"));
+  catalogue.createTapePool(m_cliSI, tapePoolName, nbPartialTapes, is_encrypted,
+    "create tape pool");
 
   const uint64_t copyNb = 1;
   const std::string comment = "create archive route";
-  ASSERT_NO_THROW(catalogue.createArchiveRoute(m_cliSI,
-    storageClassName, copyNb, tapePoolName, comment));
+  catalogue.createArchiveRoute(m_cliSI, storageClassName, copyNb, tapePoolName,
+    comment);
   ASSERT_THROW(catalogue.createArchiveRoute(m_cliSI,
     storageClassName, copyNb, tapePoolName, comment),
     exception::Exception);
@@ -515,11 +524,12 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createLogicalLibrary) {
   using namespace cta;
       
   catalogue::SqliteCatalogue catalogue;
+
+  ASSERT_TRUE(catalogue.getLogicalLibraries().empty());
       
   const std::string logicalLibraryName = "logical_library";
   const std::string comment = "create logical library";
-  ASSERT_NO_THROW(catalogue.createLogicalLibrary(m_cliSI,
-    logicalLibraryName, comment));
+  catalogue.createLogicalLibrary(m_cliSI, logicalLibraryName, comment);
       
   const std::list<common::dataStructures::LogicalLibrary> libs =
     catalogue.getLogicalLibraries();
@@ -540,18 +550,89 @@ TEST_F(cta_catalogue_SqliteCatalogueTest, createLogicalLibrary) {
   ASSERT_EQ(creationLog, lastModificationLog);
 }
   
-TEST_F(cta_catalogue_SqliteCatalogueTest, createLogicalLibrary_same_name_twice) {
+TEST_F(cta_catalogue_SqliteCatalogueTest, createLogicalLibrary_same_twice) {
   using namespace cta;
   
   catalogue::SqliteCatalogue catalogue;
 
   const std::string logicalLibraryName = "logical_library";
   const std::string comment = "create logical library";
-  ASSERT_NO_THROW(catalogue.createLogicalLibrary(m_cliSI,
-    logicalLibraryName, comment));
+  catalogue.createLogicalLibrary(m_cliSI, logicalLibraryName, comment);
   ASSERT_THROW(catalogue.createLogicalLibrary(m_cliSI,
     logicalLibraryName, comment),
     exception::Exception);
 }
 
+TEST_F(cta_catalogue_SqliteCatalogueTest, createTape) {
+  using namespace cta;
+
+  catalogue::SqliteCatalogue catalogue;
+
+  ASSERT_TRUE(catalogue.getTapes("", "", "", "", "", "", "", "").empty());
+
+  const std::string vid = "vid";
+  const std::string logicalLibraryName = "logical_library_name";
+  const std::string tapePoolName = "tape_pool_name";
+  const std::string encryptionKey = "encryption_key";
+  const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000;
+  const bool disabledValue = true;
+  const bool fullValue = false;
+  const std::string comment = "create tape";
+
+  catalogue.createLogicalLibrary(m_cliSI, logicalLibraryName,
+    "create logical library");
+  catalogue.createTapePool(m_cliSI, tapePoolName, 2, true, "create tape pool");
+  catalogue.createTape(m_cliSI, vid, logicalLibraryName, tapePoolName,
+    encryptionKey, capacityInBytes, disabledValue, fullValue,
+    comment);
+
+  const std::list<common::dataStructures::Tape> tapes =
+    catalogue.getTapes("", "", "", "", "", "", "", "");
+
+  ASSERT_EQ(1, tapes.size());
+
+  const common::dataStructures::Tape tape = tapes.front();
+  ASSERT_EQ(vid, tape.vid);
+  ASSERT_EQ(logicalLibraryName, tape.logicalLibraryName);
+  ASSERT_EQ(tapePoolName, tape.tapePoolName);
+  ASSERT_EQ(encryptionKey, tape.encryptionKey);
+  ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
+  ASSERT_TRUE(disabledValue == tape.disabled);
+  ASSERT_TRUE(fullValue == tape.full);
+  ASSERT_EQ(comment, tape.comment);
+
+  const common::dataStructures::EntryLog creationLog = tape.creationLog;
+  ASSERT_EQ(m_cliSI.user.name, creationLog.user.name);
+  ASSERT_EQ(m_cliSI.user.group, creationLog.user.group);
+  ASSERT_EQ(m_cliSI.host, creationLog.host);
+
+  const common::dataStructures::EntryLog lastModificationLog =
+    tape.lastModificationLog;
+  ASSERT_EQ(creationLog, lastModificationLog);
+}
+
+TEST_F(cta_catalogue_SqliteCatalogueTest, createTape_same_twice) {
+  using namespace cta;
+
+  catalogue::SqliteCatalogue catalogue;
+
+  const std::string vid = "vid";
+  const std::string logicalLibraryName = "logical_library_name";
+  const std::string tapePoolName = "tape_pool_name";
+  const std::string encryptionKey = "encryption_key";
+  const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000;
+  const bool disabledValue = true;
+  const bool fullValue = false;
+  const std::string comment = "create tape";
+
+  catalogue.createLogicalLibrary(m_cliSI, logicalLibraryName,
+    "create logical library");
+  catalogue.createTapePool(m_cliSI, tapePoolName, 2, true, "create tape pool");
+  catalogue.createTape(m_cliSI, vid, logicalLibraryName, tapePoolName,
+    encryptionKey, capacityInBytes, disabledValue, fullValue, comment);
+  ASSERT_THROW(catalogue.createTape(m_cliSI, vid, logicalLibraryName,
+    tapePoolName, encryptionKey, capacityInBytes, disabledValue, fullValue,
+    comment), exception::Exception);
+}
+
 } // namespace unitTests
diff --git a/catalogue/SqliteConn.cpp b/catalogue/SqliteConn.cpp
index 073d4bd76c..73704a03e2 100644
--- a/catalogue/SqliteConn.cpp
+++ b/catalogue/SqliteConn.cpp
@@ -16,7 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "catalogue/Sqlite.hpp"
 #include "catalogue/SqliteConn.hpp"
+#include "catalogue/SqliteStmt.hpp"
 #include "common/exception/Exception.hpp"
 
 //------------------------------------------------------------------------------
@@ -80,3 +82,26 @@ void cta::catalogue::SqliteConn::execNonQuery(const std::string &sql) {
     throw ex;
   }
 }
+
+//------------------------------------------------------------------------------
+// createStmt
+//------------------------------------------------------------------------------
+cta::catalogue::SqliteStmt *cta::catalogue::SqliteConn::createStmt(
+  const std::string &sql) {
+  std::lock_guard<std::mutex> lock(m_mutex);
+
+  sqlite3_stmt *stmt = NULL;
+  const int nByte = -1; // Read SQL up to first null terminator
+  const int prepareRc = sqlite3_prepare_v2(m_conn, sql.c_str(), nByte, &stmt,
+    NULL);
+  if(SQLITE_OK != prepareRc) {
+    sqlite3_finalize(stmt);
+    exception::Exception ex;
+    ex.getMessage() << __FUNCTION__ << " failed"
+      ": Failed to prepare SQL statement " << sql << ": " <<
+      sqlite3_errmsg(m_conn);
+    throw ex;
+  }
+
+  return new SqliteStmt(sql, stmt);
+}
diff --git a/catalogue/SqliteConn.hpp b/catalogue/SqliteConn.hpp
index 147c357e37..66dfbd91b4 100644
--- a/catalogue/SqliteConn.hpp
+++ b/catalogue/SqliteConn.hpp
@@ -18,12 +18,19 @@
 
 #pragma once
 
+#include <mutex>
 #include <sqlite3.h>
 #include <string>
 
 namespace cta {
 namespace catalogue {
 
+/**
+ * Forward declaraion to avoid a circular dependency beween SqliteConn and
+ * SqliteStmt.
+ */
+class SqliteStmt;
+
 /**
  * A C++ wrapper around a connectioin an SQLite database.
  */
@@ -61,8 +68,22 @@ public:
    */
   void execNonQuery(const std::string &sql);
 
+  /**
+   * Creates a prepared statement.
+   *
+   * @sql The SQL statement.
+   * @return The prepared statement.
+   */
+  SqliteStmt *createStmt(const std::string &sql);
+
 private:
 
+  /**
+   * Mutex to be used to create a critical section around the database
+   * connection.
+   */
+  std::mutex m_mutex;
+
   /**
    * The database connection.
    */
diff --git a/catalogue/SqliteStmt.cpp b/catalogue/SqliteStmt.cpp
index 25b3317ac8..662e6eca72 100644
--- a/catalogue/SqliteStmt.cpp
+++ b/catalogue/SqliteStmt.cpp
@@ -17,26 +17,18 @@
  */
 
 #include "catalogue/Sqlite.hpp"
+#include "catalogue/SqliteConn.hpp"
 #include "catalogue/SqliteStmt.hpp"
 #include "common/exception/Exception.hpp"
 
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-cta::catalogue::SqliteStmt::SqliteStmt(const SqliteConn &conn,
-  const std::string &sql): m_sql(sql) {
-  m_stmt = NULL;
-  const int nByte = -1; // Read SQL up to first null terminator
-  const int prepareRc = sqlite3_prepare_v2(conn.get(), sql.c_str(), nByte,
-    &m_stmt, NULL);
-  if(SQLITE_OK != prepareRc) {
-    sqlite3_finalize(m_stmt);
-    exception::Exception ex;
-    ex.getMessage() << __FUNCTION__ << " failed"
-      ": Failed to prepare SQL statement " << sql;
-    throw ex;
-  }
-} 
+cta::catalogue::SqliteStmt::SqliteStmt(const std::string &sql,
+  sqlite3_stmt *const stmt):
+  m_sql(sql),
+  m_stmt(stmt) {
+}
 
 //------------------------------------------------------------------------------
 // destructor
@@ -45,6 +37,13 @@ cta::catalogue::SqliteStmt::~SqliteStmt() throw() {
   sqlite3_finalize(m_stmt);
 }
 
+//------------------------------------------------------------------------------
+// getSql
+//------------------------------------------------------------------------------
+const std::string &cta::catalogue::SqliteStmt::getSql() const {
+  return m_sql;
+}
+
 //------------------------------------------------------------------------------
 // get
 //------------------------------------------------------------------------------
diff --git a/catalogue/SqliteStmt.hpp b/catalogue/SqliteStmt.hpp
index 550ae49399..edaa78ce25 100644
--- a/catalogue/SqliteStmt.hpp
+++ b/catalogue/SqliteStmt.hpp
@@ -18,7 +18,6 @@
 
 #pragma once
 
-#include "catalogue/SqliteConn.hpp"
 #include "catalogue/ColumnNameToIdx.hpp"
 
 #include <map>
@@ -29,6 +28,12 @@
 namespace cta {
 namespace catalogue {
 
+/**
+ * Forward decalaration to avoid a circular depedency between SqliteConn and
+ * SqliteStmt.
+ */
+class SqliteConn;
+
 /**
  * A C++ wrapper around an SQLite prepared statement.
  */
@@ -38,16 +43,23 @@ public:
   /**
    * Constructor.
    *  
-   * @param conn The SQLite database connection.
    * @param sql The SQL statement.
+   * @param stmt The SQLite prepared statement.
    */
-  SqliteStmt(const SqliteConn &conn, const std::string &sql);
+  SqliteStmt(const std::string &sql, sqlite3_stmt *const stmt);
 
   /**
    * Destructor.
    */
   ~SqliteStmt() throw();
 
+  /**
+   * Returns the SQL statement.
+   *
+   * @return The SQL statement.
+   */
+  const std::string &getSql() const;
+
   /**
    * Returns the underlying prepared statement.
    *
@@ -76,7 +88,7 @@ public:
    *
    * This method throws a exception if sqlite3_step() returns an error.
    *
-   * @return See sqlite3_step() documenetation.
+   * @return See sqlite3_step() documentation.
    */
   int step();
 
diff --git a/catalogue/SqliteStmtTest.cpp b/catalogue/SqliteStmtTest.cpp
index ae7a83f179..1810aa9823 100644
--- a/catalogue/SqliteStmtTest.cpp
+++ b/catalogue/SqliteStmtTest.cpp
@@ -46,8 +46,8 @@ TEST_F(cta_catalogue_SqliteStmtTest, create_table) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-    SqliteStmt stmt(conn, sql);
-    ASSERT_EQ(SQLITE_DONE, stmt.step());
+    std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+    ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 }
 
@@ -63,8 +63,8 @@ TEST_F(cta_catalogue_SqliteStmtTest, select_from_empty_table) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-    SqliteStmt stmt(conn, sql);
-    ASSERT_EQ(SQLITE_DONE, stmt.step());
+    std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+    ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 
   // Select from the empty table
@@ -75,8 +75,8 @@ TEST_F(cta_catalogue_SqliteStmtTest, select_from_empty_table) {
         "COL2,"
         "COL3 "
       "FROM TEST;";
-    SqliteStmt stmt(conn, sql);
-    ASSERT_EQ(SQLITE_DONE, stmt.step());
+    std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+    ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 }
 
@@ -92,8 +92,8 @@ TEST_F(cta_catalogue_SqliteStmtTest, insert_without_bind) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-     SqliteStmt stmt(conn, sql);
-     ASSERT_EQ(SQLITE_DONE, stmt.step());
+     std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+     ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 
   // Insert a row into the test table
@@ -107,8 +107,8 @@ TEST_F(cta_catalogue_SqliteStmtTest, insert_without_bind) {
         "'one',"
         "'two',"
         "3);";
-    SqliteStmt stmt(conn, sql);
-    ASSERT_EQ(SQLITE_DONE, stmt.step());
+    std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+    ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 
   // Select the row back from the table
@@ -119,25 +119,25 @@ TEST_F(cta_catalogue_SqliteStmtTest, insert_without_bind) {
         "COL2 AS COL2,"
         "COL3 AS COL3 "
       "FROM TEST;";
-    SqliteStmt stmt(conn, sql);
-    ASSERT_EQ(SQLITE_ROW, stmt.step());
+    std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+    ASSERT_EQ(SQLITE_ROW, stmt->step());
 
     ColumnNameToIdx nameToIdx;
-    ASSERT_NO_THROW(nameToIdx = stmt.getColumnNameToIdx());
+    ASSERT_NO_THROW(nameToIdx = stmt->getColumnNameToIdx());
 
     std::string col1;
     std::string col2;
     uint64_t col3 = 0;
 
-    ASSERT_NO_THROW(col1 = stmt.columnText(nameToIdx["COL1"]));
-    ASSERT_NO_THROW(col2 = stmt.columnText(nameToIdx["COL2"]));
-    ASSERT_NO_THROW(col3 = stmt.columnUint64(nameToIdx["COL3"]));
+    ASSERT_NO_THROW(col1 = stmt->columnText(nameToIdx["COL1"]));
+    ASSERT_NO_THROW(col2 = stmt->columnText(nameToIdx["COL2"]));
+    ASSERT_NO_THROW(col3 = stmt->columnUint64(nameToIdx["COL3"]));
 
     ASSERT_EQ("one", col1);
     ASSERT_EQ("two", col2);
     ASSERT_EQ((uint64_t)3, col3);
 
-    ASSERT_EQ(SQLITE_DONE, stmt.step());
+    ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 }
 
@@ -153,8 +153,8 @@ TEST_F(cta_catalogue_SqliteStmtTest, insert_with_bind) {
         "COL1 TEXT,"
         "COL2 TEXT,"
         "COL3 INTEGER);";
-     SqliteStmt stmt(conn, sql);
-     ASSERT_EQ(SQLITE_DONE, stmt.step());
+     std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+     ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 
   // Insert a row into the test table
@@ -168,11 +168,11 @@ TEST_F(cta_catalogue_SqliteStmtTest, insert_with_bind) {
         ":COL1,"
         ":COL2,"
         ":COL3);";
-    SqliteStmt stmt(conn, sql);
-    ASSERT_NO_THROW(stmt.bind(":COL1", "one"));
-    ASSERT_NO_THROW(stmt.bind(":COL2", "two"));
-    ASSERT_NO_THROW(stmt.bind(":COL3", 3));
-    ASSERT_EQ(SQLITE_DONE, stmt.step());
+    std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+    ASSERT_NO_THROW(stmt->bind(":COL1", "one"));
+    ASSERT_NO_THROW(stmt->bind(":COL2", "two"));
+    ASSERT_NO_THROW(stmt->bind(":COL3", 3));
+    ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 
   // Select the row back from the table
@@ -183,25 +183,25 @@ TEST_F(cta_catalogue_SqliteStmtTest, insert_with_bind) {
         "COL2 AS COL2,"
         "COL3 AS COL3 "
       "FROM TEST;";
-    SqliteStmt stmt(conn, sql);
-    ASSERT_EQ(SQLITE_ROW, stmt.step());
+    std::unique_ptr<SqliteStmt> stmt(conn.createStmt(sql));
+    ASSERT_EQ(SQLITE_ROW, stmt->step());
 
     ColumnNameToIdx nameToIdx;
-    ASSERT_NO_THROW(nameToIdx = stmt.getColumnNameToIdx());
+    ASSERT_NO_THROW(nameToIdx = stmt->getColumnNameToIdx());
 
     std::string col1;
     std::string col2;
     uint64_t col3 = 0;
 
-    ASSERT_NO_THROW(col1 = stmt.columnText(nameToIdx["COL1"]));
-    ASSERT_NO_THROW(col2 = stmt.columnText(nameToIdx["COL2"]));
-    ASSERT_NO_THROW(col3 = stmt.columnUint64(nameToIdx["COL3"]));
+    ASSERT_NO_THROW(col1 = stmt->columnText(nameToIdx["COL1"]));
+    ASSERT_NO_THROW(col2 = stmt->columnText(nameToIdx["COL2"]));
+    ASSERT_NO_THROW(col3 = stmt->columnUint64(nameToIdx["COL3"]));
 
     ASSERT_EQ("one", col1);
     ASSERT_EQ("two", col2);
     ASSERT_EQ((uint64_t)3, col3);
 
-    ASSERT_EQ(SQLITE_DONE, stmt.step());
+    ASSERT_EQ(SQLITE_DONE, stmt->step());
   }
 }
 
diff --git a/doxygen/.gitignore b/doxygen/.gitignore
index d092772385..1936cc1d44 100644
--- a/doxygen/.gitignore
+++ b/doxygen/.gitignore
@@ -1,2 +1 @@
-# Ignore everything in this directory except this file
-!.gitignore
+html
-- 
GitLab