From 0054ca7c03510ccce1714d884ec6e92ffc6feab7 Mon Sep 17 00:00:00 2001
From: Steven Murray <Steven.Murray@cern.ch>
Date: Fri, 27 Sep 2019 18:10:10 +0200
Subject: [PATCH] Added Catalogue::modifyTapePoolName() which works towards
 cta/CTA#630

---
 catalogue/Catalogue.hpp                       |   9 +
 catalogue/CatalogueRetryWrapper.hpp           |   4 +
 catalogue/CatalogueTest.cpp                   | 115 ++++++++++
 catalogue/DropSchemaCmd.cpp                   |   6 +-
 catalogue/DummyCatalogue.hpp                  |   1 +
 catalogue/MysqlCatalogue.cpp                  | 124 ++++-------
 catalogue/MysqlCatalogue.hpp                  |  19 +-
 catalogue/OracleCatalogue.cpp                 | 105 +++------
 catalogue/OracleCatalogue.hpp                 |  19 +-
 catalogue/PostgresCatalogue.cpp               | 102 +++------
 catalogue/PostgresCatalogue.hpp               |  18 +-
 catalogue/RdbmsCatalogue.cpp                  | 210 ++++++++++++------
 catalogue/RdbmsCatalogue.hpp                  |  23 ++
 ...sCatalogueGetArchiveFilesForRepackItor.cpp |   4 +-
 .../RdbmsCatalogueGetArchiveFilesItor.cpp     |   8 +-
 catalogue/SqliteCatalogue.cpp                 | 113 +++-------
 catalogue/SqliteCatalogue.hpp                 |  19 +-
 catalogue/common_catalogue_schema.sql         |  16 +-
 catalogue/mysql_catalogue_schema_header.sql   |   6 +
 catalogue/oracle_catalogue_schema_header.sql  |   8 +
 .../postgres_catalogue_schema_header.sql      |   7 +
 catalogue/sqlite_catalogue_schema_header.sql  |   3 +
 22 files changed, 544 insertions(+), 395 deletions(-)

diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp
index bbbfca2fd0..79638dd08e 100644
--- a/catalogue/Catalogue.hpp
+++ b/catalogue/Catalogue.hpp
@@ -265,6 +265,15 @@ public:
   virtual void setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool encryptionValue) = 0;
   virtual void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &supply) = 0;
 
+  /**
+   * Modifies the name of the specified tape pool.
+   *
+   * @param admin The administrator.
+   * @param currentName The current name of the tape pool.
+   * @param newName The new name of the tape pool.
+   */
+  virtual void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &currentName, const std::string &newName) = 0;
+
   virtual void createArchiveRoute(
     const common::dataStructures::SecurityIdentity &admin,
     const std::string &diskInstanceName,
diff --git a/catalogue/CatalogueRetryWrapper.hpp b/catalogue/CatalogueRetryWrapper.hpp
index 725718a179..a9ab40f0a9 100644
--- a/catalogue/CatalogueRetryWrapper.hpp
+++ b/catalogue/CatalogueRetryWrapper.hpp
@@ -173,6 +173,10 @@ public:
     return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyTapePoolSupply(admin, name, supply);}, m_maxTriesToConnect);
   }
 
+  void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &currentName, const std::string &newName) override {
+    return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyTapePoolName(admin, currentName, newName);}, m_maxTriesToConnect);
+  }
+
   void createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, const std::string &diskInstanceName, const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName, const std::string &comment) override {
     return retryOnLostConnection(m_log, [&]{return m_catalogue->createArchiveRoute(admin, diskInstanceName, storageClassName, copyNb, tapePoolName, comment);}, m_maxTriesToConnect);
   }
diff --git a/catalogue/CatalogueTest.cpp b/catalogue/CatalogueTest.cpp
index fb3af14b41..86bb802108 100644
--- a/catalogue/CatalogueTest.cpp
+++ b/catalogue/CatalogueTest.cpp
@@ -1757,6 +1757,121 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute) {
   ASSERT_EQ(creationLog, lastModificationLog);
 }
 
+TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolName) {
+  using namespace cta;
+
+  ASSERT_TRUE(m_catalogue->getTapePools().empty());
+
+  const std::string tapePoolName = "tape_pool";
+  const std::string vo = "vo";
+  const uint64_t nbPartialTapes = 2;
+  const bool isEncrypted = true;
+  const cta::optional<std::string> supply("value for the supply pool mechanism");
+  const std::string comment = "Create tape pool";
+  m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment);
+
+  {
+    const auto pools = m_catalogue->getTapePools();
+
+    ASSERT_EQ(1, pools.size());
+
+    const auto &pool = pools.front();
+    ASSERT_EQ(tapePoolName, pool.name);
+    ASSERT_EQ(vo, pool.vo);
+    ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes);
+    ASSERT_EQ(isEncrypted, pool.encryption);
+    ASSERT_EQ(0, pool.nbTapes);
+    ASSERT_EQ(0, pool.capacityBytes);
+    ASSERT_EQ(0, pool.dataBytes);
+    ASSERT_EQ(0, pool.nbPhysicalFiles);
+    ASSERT_EQ(comment, pool.comment);
+
+    const common::dataStructures::EntryLog creationLog = pool.creationLog;
+    ASSERT_EQ(m_admin.username, creationLog.username);
+    ASSERT_EQ(m_admin.host, creationLog.host);
+
+    const common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog;
+    ASSERT_EQ(creationLog, lastModificationLog);
+  }
+
+  const std::string newTapePoolName = "new_tape_pool";
+  m_catalogue->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName);
+
+  {
+    const auto pools = m_catalogue->getTapePools();
+
+    ASSERT_EQ(1, pools.size());
+
+    const auto &pool = pools.front();
+    ASSERT_EQ(newTapePoolName, pool.name);
+    ASSERT_EQ(vo, pool.vo);
+    ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes);
+    ASSERT_EQ(isEncrypted, pool.encryption);
+    ASSERT_EQ(0, pool.nbTapes);
+    ASSERT_EQ(0, pool.capacityBytes);
+    ASSERT_EQ(0, pool.dataBytes);
+    ASSERT_EQ(0, pool.nbPhysicalFiles);
+    ASSERT_EQ(comment, pool.comment);
+
+    const common::dataStructures::EntryLog creationLog = pool.creationLog;
+    ASSERT_EQ(m_admin.username, creationLog.username);
+    ASSERT_EQ(m_admin.host, creationLog.host);
+  }
+}
+
+TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolName_emptyStringCurrentTapePoolName) {
+  using namespace cta;
+
+  ASSERT_TRUE(m_catalogue->getTapePools().empty());
+
+  const std::string tapePoolName = "";
+  const std::string newTapePoolName = "new_tape_pool";
+  ASSERT_THROW(m_catalogue->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName),
+    catalogue::UserSpecifiedAnEmptyStringTapePoolName);
+}
+
+TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolName_emptyStringNewTapePoolName) {
+  using namespace cta;
+
+  ASSERT_TRUE(m_catalogue->getTapePools().empty());
+
+  const std::string tapePoolName = "tape_pool";
+  const std::string vo = "vo";
+  const uint64_t nbPartialTapes = 2;
+  const bool isEncrypted = true;
+  const cta::optional<std::string> supply("value for the supply pool mechanism");
+  const std::string comment = "Create tape pool";
+  m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment);
+
+  {
+    const auto pools = m_catalogue->getTapePools();
+
+    ASSERT_EQ(1, pools.size());
+
+    const auto &pool = pools.front();
+    ASSERT_EQ(tapePoolName, pool.name);
+    ASSERT_EQ(vo, pool.vo);
+    ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes);
+    ASSERT_EQ(isEncrypted, pool.encryption);
+    ASSERT_EQ(0, pool.nbTapes);
+    ASSERT_EQ(0, pool.capacityBytes);
+    ASSERT_EQ(0, pool.dataBytes);
+    ASSERT_EQ(0, pool.nbPhysicalFiles);
+    ASSERT_EQ(comment, pool.comment);
+
+    const common::dataStructures::EntryLog creationLog = pool.creationLog;
+    ASSERT_EQ(m_admin.username, creationLog.username);
+    ASSERT_EQ(m_admin.host, creationLog.host);
+
+    const common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog;
+    ASSERT_EQ(creationLog, lastModificationLog);
+  }
+
+  const std::string newTapePoolName = "";
+  ASSERT_THROW(m_catalogue->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName),
+    catalogue::UserSpecifiedAnEmptyStringTapePoolName);
+}
+
 TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_emptyStringDiskInstanceName) {
   using namespace cta;
       
diff --git a/catalogue/DropSchemaCmd.cpp b/catalogue/DropSchemaCmd.cpp
index 40bf7fa116..bb691b6584 100644
--- a/catalogue/DropSchemaCmd.cpp
+++ b/catalogue/DropSchemaCmd.cpp
@@ -145,6 +145,7 @@ void DropSchemaCmd::dropSqliteCatalogueSchema(rdbms::Conn &conn) {
       "STORAGE_CLASS",
       "STORAGE_CLASS_ID",
       "TAPE_POOL",
+      "TAPE_POOL_ID",
       "LOGICAL_LIBRARY",
       "MOUNT_POLICY",
       "ACTIVITIES_WEIGHTS",
@@ -177,6 +178,7 @@ void DropSchemaCmd::dropMysqlCatalogueSchema(rdbms::Conn &conn) {
       "STORAGE_CLASS",
       "STORAGE_CLASS_ID",
       "TAPE_POOL",
+      "TAPE_POOL_ID",
       "LOGICAL_LIBRARY",
       "MOUNT_POLICY",
       "ACTIVITIES_WEIGHTS",
@@ -256,7 +258,7 @@ void DropSchemaCmd::dropOracleCatalogueSchema(rdbms::Conn &conn) {
 
     dropDatabaseTables(conn, tablesToDrop);
 
-    std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ", "STORAGE_CLASS_ID_SEQ"};
+    std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ", "STORAGE_CLASS_ID_SEQ", "TAPE_POOL_ID_SEQ"};
     dropDatabaseSequences(conn, sequencesToDrop);
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
@@ -291,7 +293,7 @@ void DropSchemaCmd::dropPostgresCatalogueSchema(rdbms::Conn &conn) {
 
     dropDatabaseTables(conn, tablesToDrop);
 
-    std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ", "STORAGE_CLASS_ID_SEQ"};
+    std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ", "STORAGE_CLASS_ID_SEQ", "TAPE_POOL_ID_SEQ"};
     dropDatabaseSequences(conn, sequencesToDrop);
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
diff --git a/catalogue/DummyCatalogue.hpp b/catalogue/DummyCatalogue.hpp
index e311234a5b..e9ed953732 100644
--- a/catalogue/DummyCatalogue.hpp
+++ b/catalogue/DummyCatalogue.hpp
@@ -113,6 +113,7 @@ public:
   void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t nbPartialTapes) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& supply) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
+  void modifyTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& currentName, const std::string& newName) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& tapePoolName) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void noSpaceLeftOnTape(const std::string& vid) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void ping() override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
diff --git a/catalogue/MysqlCatalogue.cpp b/catalogue/MysqlCatalogue.cpp
index 47de31109f..d888963fe0 100644
--- a/catalogue/MysqlCatalogue.cpp
+++ b/catalogue/MysqlCatalogue.cpp
@@ -138,46 +138,58 @@ uint64_t MysqlCatalogue::getNextStorageClassId(rdbms::Conn &conn) {
 }
 
 //------------------------------------------------------------------------------
-// selectTapeForUpdate
+// getNextTapePoolId
 //------------------------------------------------------------------------------
-common::dataStructures::Tape MysqlCatalogue::selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) {
+uint64_t MysqlCatalogue::getNextTapePoolId(rdbms::Conn &conn) {
+  try {
+    rdbms::AutoRollback autoRollback(conn);
+
+    conn.executeNonQuery("START TRANSACTION");
+
+    {
+      const char *const sql =
+        "UPDATE TAPE_POOL_ID SET ID = LAST_INSERT_ID(ID + 1)";
+      auto stmt = conn.createStmt(sql);
+      stmt.executeNonQuery();
+    }
+
+    uint64_t tapePoolId = 0;
+    {
+      const char *const sql =
+        "SELECT LAST_INSERT_ID() AS ID ";
+      auto stmt = conn.createStmt(sql);
+      auto rset = stmt.executeQuery();
+      if(!rset.next()) {
+        throw exception::Exception("TAPE_POOL_ID table is empty");
+      }
+      tapePoolId = rset.columnUint64("ID");
+      if(rset.next()) {
+        throw exception::Exception("Found more than one ID counter in the TAPE_POOL_ID table");
+      }
+    }
+    conn.commit();
+
+    return tapePoolId;
+  } catch(exception::UserError &) {
+    throw;
+  } catch(exception::Exception &ex) {
+    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
+    throw;
+  }
+}
+
+//------------------------------------------------------------------------------
+// selectTapeForUpdateAndGetLastFSeq
+//------------------------------------------------------------------------------
+uint64_t MysqlCatalogue::selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) {
   try {
     const char *const sql =
       "SELECT "
-      "VID AS VID,"
-      "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME,"
-      "TAPE_POOL_NAME AS TAPE_POOL_NAME,"
-      "ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME,"
-      "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
-      "DATA_IN_BYTES AS DATA_IN_BYTES,"
-      "LAST_FSEQ AS LAST_FSEQ,"
-      "IS_DISABLED AS IS_DISABLED,"
-      "IS_FULL AS IS_FULL,"
-      "IS_READ_ONLY AS IS_READ_ONLY,"
-      "IS_FROM_CASTOR AS IS_FROM_CASTOR,"
-
-      "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,"
-
-      "USER_COMMENT AS USER_COMMENT,"
-
-      "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME,"
-      "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME,"
-      "CREATION_LOG_TIME AS CREATION_LOG_TIME,"
-
-      "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME,"
-      "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME,"
-      "LAST_UPDATE_TIME AS LAST_UPDATE_TIME "
+        "LAST_FSEQ AS LAST_FSEQ "
       "FROM "
-      "TAPE "
+        "TAPE "
       "WHERE "
-      "VID = :VID "
+        "VID = :VID "
       "FOR UPDATE";
     auto stmt = conn.createStmt(sql);
     stmt.bindString(":VID", vid);
@@ -186,45 +198,7 @@ common::dataStructures::Tape MysqlCatalogue::selectTapeForUpdate(rdbms::Conn &co
       throw exception::Exception(std::string("The tape with VID " + vid + " does not exist"));
     }
 
-    common::dataStructures::Tape tape;
-
-    tape.vid = rset.columnString("VID");
-    tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME");
-    tape.tapePoolName = rset.columnString("TAPE_POOL_NAME");
-    tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME");
-    tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES");
-    tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES");
-    tape.lastFSeq = rset.columnUint64("LAST_FSEQ");
-    tape.disabled = rset.columnBool("IS_DISABLED");
-    tape.full = rset.columnBool("IS_FULL");
-    tape.readOnly = rset.columnBool("IS_READ_ONLY");
-    tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR");
-
-    tape.labelLog = getTapeLogFromRset(rset, "LABEL_DRIVE", "LABEL_TIME");
-    tape.lastReadLog = getTapeLogFromRset(rset, "LAST_READ_DRIVE", "LAST_READ_TIME");
-    tape.lastWriteLog = getTapeLogFromRset(rset, "LAST_WRITE_DRIVE", "LAST_WRITE_TIME");
-
-    tape.comment = rset.columnString("USER_COMMENT");
-
-    // std::string creatorUIname = rset.columnString("CREATION_LOG_USER_NAME");
-
-    common::dataStructures::EntryLog creationLog;
-    creationLog.username = rset.columnString("CREATION_LOG_USER_NAME");
-    creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME");
-    creationLog.time = rset.columnUint64("CREATION_LOG_TIME");
-
-    tape.creationLog = creationLog;
-
-    // std::string updaterUIname = rset.columnString("LAST_UPDATE_USER_NAME");
-
-    common::dataStructures::EntryLog updateLog;
-    updateLog.username = rset.columnString("LAST_UPDATE_USER_NAME");
-    updateLog.host = rset.columnString("LAST_UPDATE_HOST_NAME");
-    updateLog.time = rset.columnUint64("LAST_UPDATE_TIME");
-
-    tape.lastModificationLog = updateLog;
-
-    return tape;
+    return rset.columnUint64("LAST_FSEQ");
   } catch(exception::UserError &) {
     throw;
   } catch(exception::Exception &ex) {
@@ -251,8 +225,8 @@ void MysqlCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &
 
     conn.executeNonQuery("START TRANSACTION");
 
-    const auto tape = selectTapeForUpdate(conn, firstEvent.vid);
-    uint64_t expectedFSeq = tape.lastFSeq + 1;
+    const uint64_t lastFSeq = selectTapeForUpdateAndGetLastFSeq(conn, firstEvent.vid);
+    uint64_t expectedFSeq = lastFSeq + 1;
     uint64_t totalLogicalBytesWritten = 0;
 
     for(const auto &eventP: events) {
diff --git a/catalogue/MysqlCatalogue.hpp b/catalogue/MysqlCatalogue.hpp
index fc743a5242..1724195fa3 100644
--- a/catalogue/MysqlCatalogue.hpp
+++ b/catalogue/MysqlCatalogue.hpp
@@ -85,6 +85,20 @@ protected:
    */
   uint64_t getNextStorageClassId(rdbms::Conn &conn) override;
 
+  /**
+   * Returns a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   *
+   * This method must be implemented by the sub-classes of RdbmsCatalogue
+   * because different database technologies propose different solution to the
+   * problem of generating ever increasing numeric identifiers.
+   *
+   * @param conn The database connection.
+   * @return a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   */
+  uint64_t getNextTapePoolId(rdbms::Conn &conn) override;
+
   /**
    * Notifies the catalogue that the specified files have been written to tape.
    *
@@ -124,12 +138,13 @@ private:
   void fileWrittenToTape(rdbms::Conn &conn, const TapeFileWritten &event);
 
   /**
-   * Selects the specified tape within the Tape table for update.
+   * Selects the specified tape for update and returns its last FSeq.
    *
    * @param conn The database connection.
    * @param vid The volume identifier of the tape.
+   * @return The last FSeq of the tape.
    */
-  common::dataStructures::Tape selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid);
+  uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid);
 }; // class MysqlCatalogue
 
 } // namespace catalogue
diff --git a/catalogue/OracleCatalogue.cpp b/catalogue/OracleCatalogue.cpp
index 4ee1c1fc28..00faf9c15e 100644
--- a/catalogue/OracleCatalogue.cpp
+++ b/catalogue/OracleCatalogue.cpp
@@ -203,42 +203,39 @@ uint64_t OracleCatalogue::getNextStorageClassId(rdbms::Conn &conn) {
 }
 
 //------------------------------------------------------------------------------
-// selectTapeForUpdate
+// getNextTapePoolId
 //------------------------------------------------------------------------------
-common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) {
+uint64_t OracleCatalogue::getNextTapePoolId(rdbms::Conn &conn) {
   try {
     const char *const sql =
       "SELECT "
-        "VID AS VID,"
-        "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME,"
-        "TAPE_POOL_NAME AS TAPE_POOL_NAME,"
-        "ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME,"
-        "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
-        "DATA_IN_BYTES AS DATA_IN_BYTES,"
-        "LAST_FSEQ AS LAST_FSEQ,"
-        "IS_DISABLED AS IS_DISABLED,"
-        "IS_FULL AS IS_FULL,"
-        "IS_READ_ONLY AS IS_READ_ONLY,"
-        "IS_FROM_CASTOR AS IS_FROM_CASTOR,"
-
-        "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,"
-
-        "USER_COMMENT AS USER_COMMENT,"
-
-        "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME,"
-        "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME,"
-        "CREATION_LOG_TIME AS CREATION_LOG_TIME,"
-
-        "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME,"
-        "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME,"
-        "LAST_UPDATE_TIME AS LAST_UPDATE_TIME "
+        "TAPE_POOL_ID_SEQ.NEXTVAL AS TAPE_POOL_ID "
+      "FROM "
+        "DUAL";
+    auto stmt = conn.createStmt(sql);
+    auto rset = stmt.executeQuery();
+    if (!rset.next()) {
+      throw exception::Exception(std::string("Result set is unexpectedly empty"));
+    }
+
+    return rset.columnUint64("TAPE_POOL_ID");
+  } catch(exception::UserError &) {
+    throw;
+  } catch(exception::Exception &ex) {
+    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
+    throw;
+  }
+}
+
+//------------------------------------------------------------------------------
+// selectTapeForUpdateAndGetLastFSeq
+//------------------------------------------------------------------------------
+uint64_t OracleCatalogue::selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn,
+  const std::string &vid) {
+  try {
+    const char *const sql =
+      "SELECT "
+        "LAST_FSEQ AS LAST_FSEQ "
       "FROM "
         "TAPE "
       "WHERE "
@@ -251,45 +248,7 @@ common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(rdbms::Conn &c
       throw exception::Exception(std::string("The tape with VID " + vid + " does not exist"));
     }
 
-    common::dataStructures::Tape tape;
-
-    tape.vid = rset.columnString("VID");
-    tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME");
-    tape.tapePoolName = rset.columnString("TAPE_POOL_NAME");
-    tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME");
-    tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES");
-    tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES");
-    tape.lastFSeq = rset.columnUint64("LAST_FSEQ");
-    tape.disabled = rset.columnBool("IS_DISABLED");
-    tape.full = rset.columnBool("IS_FULL");
-    tape.readOnly = rset.columnBool("IS_READ_ONLY");
-    tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR");
-
-    tape.labelLog = getTapeLogFromRset(rset, "LABEL_DRIVE", "LABEL_TIME");
-    tape.lastReadLog = getTapeLogFromRset(rset, "LAST_READ_DRIVE", "LAST_READ_TIME");
-    tape.lastWriteLog = getTapeLogFromRset(rset, "LAST_WRITE_DRIVE", "LAST_WRITE_TIME");
-
-    tape.comment = rset.columnString("USER_COMMENT");
-
-    //std::string creatorUIname = rset.columnString("CREATION_LOG_USER_NAME");
-
-    common::dataStructures::EntryLog creationLog;
-    creationLog.username = rset.columnString("CREATION_LOG_USER_NAME");
-    creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME");
-    creationLog.time = rset.columnUint64("CREATION_LOG_TIME");
-
-    tape.creationLog = creationLog;
-
-    //std::string updaterUIname = rset.columnString("LAST_UPDATE_USER_NAME");
-
-    common::dataStructures::EntryLog updateLog;
-    updateLog.username = rset.columnString("LAST_UPDATE_USER_NAME");
-    updateLog.host = rset.columnString("LAST_UPDATE_HOST_NAME");
-    updateLog.time = rset.columnUint64("LAST_UPDATE_TIME");
-
-    tape.lastModificationLog = updateLog;
-
-    return tape;
+    return rset.columnUint64("LAST_FSEQ");
   } catch(exception::UserError &) {
     throw;
   } catch(exception::Exception &ex) {
@@ -317,8 +276,8 @@ void OracleCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer>
 
     conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF);
 
-    const auto tape = selectTapeForUpdate(conn, firstEvent.vid);
-    uint64_t expectedFSeq = tape.lastFSeq + 1;
+    const uint64_t lastFSeq = selectTapeForUpdateAndGetLastFSeq(conn, firstEvent.vid);
+    uint64_t expectedFSeq = lastFSeq + 1;
     uint64_t totalLogicalBytesWritten = 0;
 
     uint32_t i = 0;
diff --git a/catalogue/OracleCatalogue.hpp b/catalogue/OracleCatalogue.hpp
index 0542c7a188..b6017617ae 100644
--- a/catalogue/OracleCatalogue.hpp
+++ b/catalogue/OracleCatalogue.hpp
@@ -85,6 +85,20 @@ public:
    */
   uint64_t getNextStorageClassId(rdbms::Conn &conn) override;
 
+  /**
+   * Returns a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   *
+   * This method must be implemented by the sub-classes of RdbmsCatalogue
+   * because different database technologies propose different solution to the
+   * problem of generating ever increasing numeric identifiers.
+   *
+   * @param conn The database connection.
+   * @return a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   */
+  uint64_t getNextTapePoolId(rdbms::Conn &conn) override;
+
   /**
    * Notifies the catalogue that the specified files have been written to tape.
    *
@@ -116,12 +130,13 @@ public:
 private:
 
   /**
-   * Selects the specified tape within the Tape table for update.
+   * Selects the specified tape for update and returns its last FSeq.
    *
    * @param conn The database connection.
    * @param vid The volume identifier of the tape.
+   * @return The last FSeq of the tape.
    */
-  common::dataStructures::Tape selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid);
+  uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid);
 
   /**
    * Batch inserts rows into the ARCHIVE_FILE table that correspond to the
diff --git a/catalogue/PostgresCatalogue.cpp b/catalogue/PostgresCatalogue.cpp
index 8feba18264..921b2d265a 100644
--- a/catalogue/PostgresCatalogue.cpp
+++ b/catalogue/PostgresCatalogue.cpp
@@ -193,42 +193,34 @@ uint64_t PostgresCatalogue::getNextStorageClassId(rdbms::Conn &conn) {
 }
 
 //------------------------------------------------------------------------------
-// selectTapeForUpdate
+// getNextTapePoolId
 //------------------------------------------------------------------------------
-common::dataStructures::Tape PostgresCatalogue::selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) const {
+uint64_t PostgresCatalogue::getNextTapePoolId(rdbms::Conn &conn) {
+  try {
+    const char *const sql =
+      "select NEXTVAL('TAPE_POOL_ID_SEQ') AS TAPE_POOL_ID";
+    auto stmt = conn.createStmt(sql);
+    auto rset = stmt.executeQuery();
+    if(!rset.next()) {
+      throw exception::Exception("Result set is unexpectedly empty");
+    }
+    return rset.columnUint64("TAPE_POOL_ID");
+  } catch(exception::UserError &) {
+    throw;
+  } catch(exception::Exception &ex) {
+    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
+    throw;
+  }
+}
+
+//------------------------------------------------------------------------------
+// selectTapeForUpdateAndGetNextFSeq
+//------------------------------------------------------------------------------
+uint64_t PostgresCatalogue::selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) const {
   try {
     const char *const sql =
       "SELECT "
-        "VID AS VID,"
-        "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME,"
-        "TAPE_POOL_NAME AS TAPE_POOL_NAME,"
-        "ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME,"
-        "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
-        "DATA_IN_BYTES AS DATA_IN_BYTES,"
-        "LAST_FSEQ AS LAST_FSEQ,"
-        "IS_DISABLED AS IS_DISABLED,"
-        "IS_FULL AS IS_FULL,"
-        "IS_READ_ONLY AS IS_READ_ONLY,"
-        "IS_FROM_CASTOR AS IS_FROM_CASTOR,"
-
-        "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,"
-
-        "USER_COMMENT AS USER_COMMENT,"
-
-        "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME,"
-        "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME,"
-        "CREATION_LOG_TIME AS CREATION_LOG_TIME,"
-
-        "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME,"
-        "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME,"
-        "LAST_UPDATE_TIME AS LAST_UPDATE_TIME "
+        "LAST_FSEQ AS LAST_FSEQ "
       "FROM "
         "TAPE "
       "WHERE "
@@ -241,47 +233,7 @@ common::dataStructures::Tape PostgresCatalogue::selectTapeForUpdate(rdbms::Conn
       throw exception::Exception(std::string("The tape with VID " + vid + " does not exist"));
     }
 
-    common::dataStructures::Tape tape;
-
-    tape.vid = rset.columnString("VID");
-    tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME");
-    tape.tapePoolName = rset.columnString("TAPE_POOL_NAME");
-    tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME");
-    tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES");
-    tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES");
-    tape.lastFSeq = rset.columnUint64("LAST_FSEQ");
-    tape.disabled = rset.columnBool("IS_DISABLED");
-    tape.full = rset.columnBool("IS_FULL");
-    tape.readOnly = rset.columnBool("IS_READ_ONLY");
-    tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR");
-
-    tape.labelLog = getTapeLogFromRset(rset, "LABEL_DRIVE", "LABEL_TIME");
-    tape.lastReadLog = getTapeLogFromRset(rset, "LAST_READ_DRIVE", "LAST_READ_TIME");
-    tape.lastWriteLog = getTapeLogFromRset(rset, "LAST_WRITE_DRIVE", "LAST_WRITE_TIME");
-
-    tape.comment = rset.columnString("USER_COMMENT");
-
-    //std::string creatorUIname = rset.columnString("CREATION_LOG_USER_NAME");
-
-    common::dataStructures::EntryLog creationLog;
-    creationLog.username = rset.columnString("CREATION_LOG_USER_NAME");
-    creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME");
-    creationLog.time = rset.columnUint64("CREATION_LOG_TIME");
-
-    tape.creationLog = creationLog;
-
-    //std::string updaterUIname = rset.columnString("LAST_UPDATE_USER_NAME");
-
-    common::dataStructures::EntryLog updateLog;
-    updateLog.username = rset.columnString("LAST_UPDATE_USER_NAME");
-    updateLog.host = rset.columnString("LAST_UPDATE_HOST_NAME");
-    updateLog.time = rset.columnUint64("LAST_UPDATE_TIME");
-
-    tape.lastModificationLog = updateLog;
-
-    return tape;
-  } catch(exception::UserError &) {
-    throw;
+    return rset.columnUint64("LAST_FSEQ");
   } catch(exception::Exception &ex) {
     ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
     throw;
@@ -310,8 +262,8 @@ void PostgresCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer
     // to avoid violation in the case of concurrent inserts of a previously not existing archive file.
     beginCreateTemporarySetDeferred(conn);
 
-    const auto tape = selectTapeForUpdate(conn, firstEvent.vid);
-    uint64_t expectedFSeq = tape.lastFSeq + 1;
+    const uint64_t lastFSeq = selectTapeForUpdateAndGetLastFSeq(conn, firstEvent.vid);
+    uint64_t expectedFSeq = lastFSeq + 1;
     uint64_t totalLogicalBytesWritten = 0;
 
     // We have a mix of files and items. Only files will be recorded, but items
diff --git a/catalogue/PostgresCatalogue.hpp b/catalogue/PostgresCatalogue.hpp
index 9fa3be5876..b7320784d8 100644
--- a/catalogue/PostgresCatalogue.hpp
+++ b/catalogue/PostgresCatalogue.hpp
@@ -111,6 +111,19 @@ public:
    */
   uint64_t getNextStorageClassId(rdbms::Conn &conn) override;
 
+  /**
+   * Returns a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   *
+   * This method must be implemented by the sub-classes of RdbmsCatalogue
+   * because different database technologies propose different solution to the
+   * problem of generating ever increasing numeric identifiers.
+   *
+   * @param conn The database connection.
+   * @return a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   */
+  uint64_t getNextTapePoolId(rdbms::Conn &conn) override;
 
 private:
 
@@ -125,12 +138,13 @@ private:
   void beginCreateTemporarySetDeferred(rdbms::Conn &conn) const;
 
   /**
-   * Selects the specified tape within the Tape table for update.
+   * Selects the specified tape for update and returns its last FSeq.
    *
    * @param conn The database connection.
    * @param vid The volume identifier of the tape.
+   * @param The last FSeq of the tape.
    */
-  common::dataStructures::Tape selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) const;
+  uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) const;
 
   /**
    * Batch inserts rows into the ARCHIVE_FILE table that correspond to the
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index bddf5bd720..6e26769b09 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -707,9 +707,11 @@ void RdbmsCatalogue::createTapePool(
       throw exception::UserError(std::string("Cannot create tape pool ") + name +
         " because a tape pool with the same name already exists");
     }
+    const uint64_t tapePoolId = getNextTapePoolId(conn);
     const time_t now = time(nullptr);
     const char *const sql =
       "INSERT INTO TAPE_POOL("
+        "TAPE_POOL_ID,"
         "TAPE_POOL_NAME,"
         "VO,"
         "NB_PARTIAL_TAPES,"
@@ -726,6 +728,7 @@ void RdbmsCatalogue::createTapePool(
         "LAST_UPDATE_HOST_NAME,"
         "LAST_UPDATE_TIME)"
       "VALUES("
+        ":TAPE_POOL_ID,"
         ":TAPE_POOL_NAME,"
         ":VO,"
         ":NB_PARTIAL_TAPES,"
@@ -743,6 +746,7 @@ void RdbmsCatalogue::createTapePool(
         ":LAST_UPDATE_TIME)";
     auto stmt = conn.createStmt(sql);
 
+    stmt.bindUint64(":TAPE_POOL_ID", tapePoolId);
     stmt.bindString(":TAPE_POOL_NAME", name);
     stmt.bindString(":VO", vo);
     stmt.bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes);
@@ -1034,7 +1038,7 @@ std::list<TapePool> RdbmsCatalogue::getTapePools() const {
       "FROM "
         "TAPE_POOL "
       "LEFT OUTER JOIN TAPE ON "
-        "TAPE_POOL.TAPE_POOL_NAME = TAPE.TAPE_POOL_NAME "
+        "TAPE_POOL.TAPE_POOL_ID = TAPE.TAPE_POOL_ID "
       "GROUP BY "
         "TAPE_POOL.TAPE_POOL_NAME,"
         "TAPE_POOL.VO,"
@@ -1294,6 +1298,50 @@ void RdbmsCatalogue::modifyTapePoolSupply(const common::dataStructures::Security
   }
 }
 
+//------------------------------------------------------------------------------
+// modifyTapePoolName
+//------------------------------------------------------------------------------
+void RdbmsCatalogue::modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin,
+  const std::string &currentName, const std::string &newName) {
+  try {
+    if(currentName.empty()) {
+      throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty"
+        " string");
+    }
+
+    if(newName.empty()) {
+      throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the new name is an empty string");
+    }
+
+    const time_t now = time(nullptr);
+    const char *const sql =
+      "UPDATE TAPE_POOL SET "
+        "TAPE_POOL_NAME = :NEW_TAPE_POOL_NAME,"
+        "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
+        "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
+        "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
+      "WHERE "
+        "TAPE_POOL_NAME = :CURRENT_TAPE_POOL_NAME";
+    auto conn = m_connPool.getConn();
+    auto stmt = conn.createStmt(sql);
+    stmt.bindString(":NEW_TAPE_POOL_NAME", newName);
+    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
+    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
+    stmt.bindUint64(":LAST_UPDATE_TIME", now);
+    stmt.bindString(":CURRENT_TAPE_POOL_NAME", currentName);
+    stmt.executeNonQuery();
+
+    if(0 == stmt.getNbAffectedRows()) {
+      throw exception::UserError(std::string("Cannot modify tape pool ") + currentName + " because it does not exist");
+    }
+  } catch(exception::UserError &) {
+    throw;
+  } catch(exception::Exception &ex) {
+    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
+    throw;
+  }
+}
+
 //------------------------------------------------------------------------------
 // createArchiveRoute
 //------------------------------------------------------------------------------
@@ -1350,7 +1398,7 @@ void RdbmsCatalogue::createArchiveRoute(
       "INSERT INTO ARCHIVE_ROUTE("
         "STORAGE_CLASS_ID,"
         "COPY_NB,"
-        "TAPE_POOL_NAME,"
+        "TAPE_POOL_ID,"
 
         "USER_COMMENT,"
 
@@ -1364,7 +1412,7 @@ void RdbmsCatalogue::createArchiveRoute(
       "SELECT "
         "STORAGE_CLASS_ID,"
         ":COPY_NB,"
-        ":TAPE_POOL_NAME,"
+        "(SELECT TAPE_POOL_ID FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME) AS TAPE_POOL_ID,"
 
         ":USER_COMMENT,"
 
@@ -1457,7 +1505,7 @@ std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes
         "STORAGE_CLASS.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME,"
         "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME,"
         "ARCHIVE_ROUTE.COPY_NB AS COPY_NB,"
-        "ARCHIVE_ROUTE.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
 
         "ARCHIVE_ROUTE.USER_COMMENT AS USER_COMMENT,"
 
@@ -1472,6 +1520,8 @@ std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes
         "ARCHIVE_ROUTE "
       "INNER JOIN STORAGE_CLASS ON "
         "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID "
+      "INNER JOIN TAPE_POOL ON "
+        "ARCHIVE_ROUTE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID "
       "ORDER BY "
         "DISK_INSTANCE_NAME, STORAGE_CLASS_NAME, COPY_NB";
     auto conn = m_connPool.getConn();
@@ -1514,7 +1564,7 @@ void RdbmsCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures
     const time_t now = time(nullptr);
     const char *const sql =
       "UPDATE ARCHIVE_ROUTE SET "
-        "TAPE_POOL_NAME = :TAPE_POOL_NAME,"
+        "TAPE_POOL_ID = (SELECT TAPE_POOL_ID FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME),"
         "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
         "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
         "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
@@ -1542,7 +1592,7 @@ void RdbmsCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures
     if(0 == stmt.getNbAffectedRows()) {
       exception::UserError ue;
       ue.getMessage() << "Cannot modify archive route for storage-class " << instanceName + ":" + storageClassName +
-        " and copy number " << copyNb << " because it does not exist";
+        " and copy number " << copyNb << " because either it or tape pool " + tapePoolName + " does not exist";
       throw ue;
     }
   } catch(exception::UserError &) {
@@ -1912,59 +1962,62 @@ void RdbmsCatalogue::createTape(
     }
     const time_t now = time(nullptr);
     const char *const sql =
-      "INSERT INTO TAPE("
-        "VID,"
-        "MEDIA_TYPE,"
-        "VENDOR,"
-        "LOGICAL_LIBRARY_NAME,"
-        "TAPE_POOL_NAME,"
-        "CAPACITY_IN_BYTES,"
-        "DATA_IN_BYTES,"
-        "LAST_FSEQ,"
-        "IS_DISABLED,"
-        "IS_FULL,"
-        "IS_READ_ONLY,"
-        "IS_FROM_CASTOR,"
-
-        "USER_COMMENT,"
-
-        "CREATION_LOG_USER_NAME,"
-        "CREATION_LOG_HOST_NAME,"
-        "CREATION_LOG_TIME,"
-
-        "LAST_UPDATE_USER_NAME,"
-        "LAST_UPDATE_HOST_NAME,"
-        "LAST_UPDATE_TIME)"
-      "VALUES("
-        ":VID,"
-        ":MEDIA_TYPE,"
-        ":VENDOR,"
-        ":LOGICAL_LIBRARY_NAME,"
-        ":TAPE_POOL_NAME,"
-        ":CAPACITY_IN_BYTES,"
-        ":DATA_IN_BYTES,"
-        ":LAST_FSEQ,"
-        ":IS_DISABLED,"
-        ":IS_FULL,"
-        ":IS_READ_ONLY,"
-        ":IS_FROM_CASTOR,"
-
-        ":USER_COMMENT,"
-
-        ":CREATION_LOG_USER_NAME,"
-        ":CREATION_LOG_HOST_NAME,"
-        ":CREATION_LOG_TIME,"
-
-        ":LAST_UPDATE_USER_NAME,"
-        ":LAST_UPDATE_HOST_NAME,"
-        ":LAST_UPDATE_TIME)";
+      "INSERT INTO TAPE("                  "\n"
+        "VID,"                             "\n"
+        "MEDIA_TYPE,"                      "\n"
+        "VENDOR,"                          "\n"
+        "LOGICAL_LIBRARY_NAME,"            "\n"
+        "TAPE_POOL_ID,"                    "\n"
+        "CAPACITY_IN_BYTES,"               "\n"
+        "DATA_IN_BYTES,"                   "\n"
+        "LAST_FSEQ,"                       "\n"
+        "IS_DISABLED,"                     "\n"
+        "IS_FULL,"                         "\n"
+        "IS_READ_ONLY,"                    "\n"
+        "IS_FROM_CASTOR,"                  "\n"
+
+        "USER_COMMENT,"                    "\n"
+
+        "CREATION_LOG_USER_NAME,"          "\n"
+        "CREATION_LOG_HOST_NAME,"          "\n"
+        "CREATION_LOG_TIME,"               "\n"
+
+        "LAST_UPDATE_USER_NAME,"           "\n"
+        "LAST_UPDATE_HOST_NAME,"           "\n"
+        "LAST_UPDATE_TIME)"                "\n"
+      "SELECT"                             "\n"
+        ":VID,"                            "\n"
+        ":MEDIA_TYPE,"                     "\n"
+        ":VENDOR,"                         "\n"
+        ":LOGICAL_LIBRARY_NAME,"           "\n"
+        "TAPE_POOL_ID,"                    "\n"
+        ":CAPACITY_IN_BYTES,"              "\n"
+        ":DATA_IN_BYTES,"                  "\n"
+        ":LAST_FSEQ,"                      "\n"
+        ":IS_DISABLED,"                    "\n"
+        ":IS_FULL,"                        "\n"
+        ":IS_READ_ONLY,"                   "\n"
+        ":IS_FROM_CASTOR,"                 "\n"
+
+        ":USER_COMMENT,"                   "\n"
+
+        ":CREATION_LOG_USER_NAME,"         "\n"
+        ":CREATION_LOG_HOST_NAME,"         "\n"
+        ":CREATION_LOG_TIME,"              "\n"
+
+        ":LAST_UPDATE_USER_NAME,"          "\n"
+        ":LAST_UPDATE_HOST_NAME,"          "\n"
+        ":LAST_UPDATE_TIME"                "\n"
+      "FROM "
+        "TAPE_POOL "                       "\n"
+      "WHERE "                             "\n"
+        "TAPE_POOL_NAME = :TAPE_POOL_NAME";
     auto stmt = conn.createStmt(sql);
 
     stmt.bindString(":VID", vid);
     stmt.bindString(":MEDIA_TYPE", mediaType);
     stmt.bindString(":VENDOR", vendor);
     stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
-    stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
     stmt.bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
     stmt.bindUint64(":DATA_IN_BYTES", 0);
     stmt.bindUint64(":LAST_FSEQ", 0);
@@ -1983,6 +2036,8 @@ void RdbmsCatalogue::createTape(
     stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
     stmt.bindUint64(":LAST_UPDATE_TIME", now);
 
+    stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
+
     stmt.executeNonQuery();
 
     log::LogContext lc(m_log);
@@ -2158,7 +2213,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::Conn &co
         "TAPE.MEDIA_TYPE AS MEDIA_TYPE,"
         "TAPE.VENDOR AS VENDOR,"
         "TAPE.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME,"
-        "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
         "TAPE_POOL.VO AS VO,"
         "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME,"
         "TAPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
@@ -2193,7 +2248,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::Conn &co
       "FROM "
         "TAPE "
       "INNER JOIN TAPE_POOL ON "
-        "TAPE.TAPE_POOL_NAME = TAPE_POOL.TAPE_POOL_NAME";
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID";
 
     if(searchCriteria.vid ||
        searchCriteria.mediaType ||
@@ -2231,7 +2286,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::Conn &co
     }
     if(searchCriteria.tapePool) {
       if(addedAWhereConstraint) sql += " AND ";
-      sql += " TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME";
+      sql += " TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME";
       addedAWhereConstraint = true;
     }
     if(searchCriteria.vo) {
@@ -2333,7 +2388,7 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getTapesByVid(const std::se
         "TAPE.MEDIA_TYPE AS MEDIA_TYPE,"
         "TAPE.VENDOR AS VENDOR,"
         "TAPE.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME,"
-        "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
         "TAPE_POOL.VO AS VO,"
         "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME,"
         "TAPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
@@ -2368,7 +2423,7 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getTapesByVid(const std::se
       "FROM "
         "TAPE "
       "INNER JOIN TAPE_POOL ON "
-        "TAPE.TAPE_POOL_NAME = TAPE_POOL.TAPE_POOL_NAME";
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID";
 
     if(!vids.empty()) {
       sql += " WHERE ";
@@ -2459,7 +2514,7 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getAllTapes() const {
         "TAPE.MEDIA_TYPE AS MEDIA_TYPE,"
         "TAPE.VENDOR AS VENDOR,"
         "TAPE.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME,"
-        "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
         "TAPE_POOL.VO AS VO,"
         "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME,"
         "TAPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
@@ -2494,7 +2549,7 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getAllTapes() const {
       "FROM "
         "TAPE "
       "INNER JOIN TAPE_POOL ON "
-        "TAPE.TAPE_POOL_NAME = TAPE_POOL.TAPE_POOL_NAME";
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID";
 
     auto conn = m_connPool.getConn();
     auto stmt = conn.createStmt(sql);
@@ -2860,7 +2915,8 @@ void RdbmsCatalogue::modifyTapeLogicalLibraryName(const common::dataStructures::
     stmt.executeNonQuery();
 
     if(0 == stmt.getNbAffectedRows()) {
-      throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
+      throw exception::UserError(std::string("Cannot modify tape ") + vid + " because either it or logical library " +
+        logicalLibraryName + " does not exist");
     }
 
     log::LogContext lc(m_log);
@@ -2888,7 +2944,7 @@ void RdbmsCatalogue::modifyTapeTapePoolName(const common::dataStructures::Securi
     const time_t now = time(nullptr);
     const char *const sql =
       "UPDATE TAPE SET "
-        "TAPE_POOL_NAME = :TAPE_POOL_NAME,"
+        "TAPE_POOL_ID = (SELECT TAPE_POOL_ID FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME),"
         "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
         "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
         "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
@@ -5375,7 +5431,7 @@ std::list<common::dataStructures::ArchiveFile> RdbmsCatalogue::getFilesForRepack
         "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME,"
         "TAPE_FILE.SUPERSEDED_BY_VID AS SSBY_VID,"
         "TAPE_FILE.SUPERSEDED_BY_FSEQ AS SSBY_FSEQ,"
-        "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME "
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME "
       "FROM "
         "ARCHIVE_FILE "
       "INNER JOIN STORAGE_CLASS ON "
@@ -5384,10 +5440,12 @@ std::list<common::dataStructures::ArchiveFile> RdbmsCatalogue::getFilesForRepack
         "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID "
       "INNER JOIN TAPE ON "
         "TAPE_FILE.VID = TAPE.VID "
-       "WHERE "
-         "TAPE_FILE.VID = :VID AND "
-         "TAPE_FILE.FSEQ >= :START_FSEQ AND "
-         "TAPE_FILE.SUPERSEDED_BY_VID IS NULL "
+      "INNER JOIN TAPE_POOL ON "
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID "
+      "WHERE "
+        "TAPE_FILE.VID = :VID AND "
+        "TAPE_FILE.FSEQ >= :START_FSEQ AND "
+        "TAPE_FILE.SUPERSEDED_BY_VID IS NULL "
        "ORDER BY FSEQ";
 
     auto conn = m_connPool.getConn();
@@ -5472,7 +5530,9 @@ common::dataStructures::ArchiveFileSummary RdbmsCatalogue::getTapeFileSummary(
       "INNER JOIN TAPE_FILE ON "
         "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID "
       "INNER JOIN TAPE ON "
-        "TAPE_FILE.VID = TAPE.VID";
+        "TAPE_FILE.VID = TAPE.VID "
+      "INNER JOIN TAPE_POOL ON "
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID";
 
     if(
       searchCriteria.archiveFileId  ||
@@ -5536,7 +5596,7 @@ common::dataStructures::ArchiveFileSummary RdbmsCatalogue::getTapeFileSummary(
     }
     if(searchCriteria.tapePool) {
       if(addedAWhereConstraint) sql += " AND ";
-      sql += "TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME";
+      sql += "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME";
     }
 
     auto conn = m_connPool.getConn();
@@ -5770,11 +5830,13 @@ common::dataStructures::TapeCopyToPoolMap RdbmsCatalogue::getTapeCopyToPoolMap(r
     const char *const sql =
       "SELECT "
         "ARCHIVE_ROUTE.COPY_NB AS COPY_NB,"
-        "ARCHIVE_ROUTE.TAPE_POOL_NAME AS TAPE_POOL_NAME "
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME "
       "FROM "
         "ARCHIVE_ROUTE "
       "INNER JOIN STORAGE_CLASS ON "
         "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID "
+      "INNER JOIN TAPE_POOL ON "
+        "ARCHIVE_ROUTE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID "
       "WHERE "
         "STORAGE_CLASS.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
         "STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
@@ -6125,7 +6187,7 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string &
         "TAPE.VID AS VID,"
         "TAPE.MEDIA_TYPE AS MEDIA_TYPE,"
         "TAPE.VENDOR AS VENDOR,"
-        "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
         "TAPE_POOL.VO AS VO,"
         "TAPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
         "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES,"
@@ -6133,7 +6195,7 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string &
       "FROM "
         "TAPE "
       "INNER JOIN TAPE_POOL ON "
-        "TAPE.TAPE_POOL_NAME = TAPE_POOL.TAPE_POOL_NAME "
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID "
       "WHERE "
 //      "LABEL_DRIVE IS NOT NULL AND " // Set when the tape has been labelled
 //      "LABEL_TIME IS NOT NULL AND "  // Set when the tape has been labelled
@@ -6819,8 +6881,10 @@ uint64_t RdbmsCatalogue::getNbTapesInPool(rdbms::Conn &conn, const std::string &
         "COUNT(*) AS NB_TAPES "
       "FROM "
         "TAPE "
+      "INNER JOIN TAPE_POOL ON "
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID "
       "WHERE "
-        "TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME";
+        "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME";
     auto stmt = conn.createStmt(sql);
     stmt.bindString(":TAPE_POOL_NAME", name);
     auto rset = stmt.executeQuery();
diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp
index 7afcd87fc0..8b9e437205 100644
--- a/catalogue/RdbmsCatalogue.hpp
+++ b/catalogue/RdbmsCatalogue.hpp
@@ -255,6 +255,15 @@ public:
   void setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool encryptionValue) override;
   void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &supply) override;
 
+  /**
+   * Modifies the name of the specified tape pool.
+   *
+   * @param admin The administrator.
+   * @param currentName The current name of the tape pool.
+   * @param newName The new name of the tape pool.
+   */
+  void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &currentName, const std::string &newName) override;
+
   void createArchiveRoute(
     const common::dataStructures::SecurityIdentity &admin,
     const std::string &diskInstanceName,
@@ -1340,6 +1349,20 @@ protected:
    */
   virtual uint64_t getNextStorageClassId(rdbms::Conn &conn) = 0;
 
+  /**
+   * Returns a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   *
+   * This method must be implemented by the sub-classes of RdbmsCatalogue
+   * because different database technologies propose different solution to the
+   * problem of generating ever increasing numeric identifiers.
+   *
+   * @param conn The database connection.
+   * @return a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   */
+  virtual uint64_t getNextTapePoolId(rdbms::Conn &conn) = 0;
+
   /**
    * Returns a cached version of the mapping from tape copy to tape pool for the
    * specified storage class.
diff --git a/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp b/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp
index 5857695308..2a0d38ea12 100644
--- a/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp
+++ b/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp
@@ -113,7 +113,7 @@ RdbmsCatalogueGetArchiveFilesForRepackItor::RdbmsCatalogueGetArchiveFilesForRepa
         "TAPE_COPY.CREATION_TIME AS TAPE_FILE_CREATION_TIME, "
         "TAPE_COPY.SUPERSEDED_BY_VID AS SUPERSEDED_BY_VID, "
         "TAPE_COPY.SUPERSEDED_BY_FSEQ AS SUPERSEDED_BY_FSEQ, "
-        "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME "
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME "
       "FROM "
         "TAPE_FILE REPACK_TAPE "
       "INNER JOIN TAPE_FILE TAPE_COPY ON "
@@ -124,6 +124,8 @@ RdbmsCatalogueGetArchiveFilesForRepackItor::RdbmsCatalogueGetArchiveFilesForRepa
         "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID "
       "INNER JOIN TAPE ON "
         "TAPE_COPY.VID = TAPE.VID "
+      "INNER JOIN TAPE_POOL ON "
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID "
       "WHERE "
         "REPACK_TAPE.VID = :VID "
       "AND "
diff --git a/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp b/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp
index acaa6c8023..b988534b78 100644
--- a/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp
+++ b/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp
@@ -109,7 +109,7 @@ RdbmsCatalogueGetArchiveFilesItor::RdbmsCatalogueGetArchiveFilesItor(
         "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME, "
         "TAPE_FILE.SUPERSEDED_BY_VID AS SUPERSEDED_BY_VID, "
         "TAPE_FILE.SUPERSEDED_BY_FSEQ AS SUPERSEDED_BY_FSEQ, "
-        "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME "
+        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME "
       "FROM "
         "ARCHIVE_FILE "
       "INNER JOIN STORAGE_CLASS ON "
@@ -117,7 +117,9 @@ RdbmsCatalogueGetArchiveFilesItor::RdbmsCatalogueGetArchiveFilesItor(
       "LEFT OUTER JOIN TAPE_FILE ON "
         "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID "
       "LEFT OUTER JOIN TAPE ON "
-        "TAPE_FILE.VID = TAPE.VID";
+        "TAPE_FILE.VID = TAPE.VID "
+      "INNER JOIN TAPE_POOL ON "
+        "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID";
 
     const bool thereIsAtLeastOneSearchCriteria =
       searchCriteria.archiveFileId  ||
@@ -183,7 +185,7 @@ RdbmsCatalogueGetArchiveFilesItor::RdbmsCatalogueGetArchiveFilesItor(
     }
     if(searchCriteria.tapePool) {
       if(addedAWhereConstraint) sql += " AND ";
-      sql += "TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME";
+      sql += "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME";
     }
 
     // Order by FSEQ if we are listing the contents of a tape, else order by
diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp
index 978778d18c..ab9f955486 100644
--- a/catalogue/SqliteCatalogue.cpp
+++ b/catalogue/SqliteCatalogue.cpp
@@ -241,42 +241,43 @@ uint64_t SqliteCatalogue::getNextStorageClassId(rdbms::Conn &conn) {
 }
 
 //------------------------------------------------------------------------------
-// selectTape
+// getNextTapePoolId
 //------------------------------------------------------------------------------
-common::dataStructures::Tape SqliteCatalogue::selectTape(rdbms::Conn &conn, const std::string &vid) {
+uint64_t SqliteCatalogue::getNextTapePoolId(rdbms::Conn &conn) {
+  try {
+    conn.executeNonQuery("INSERT INTO TAPE_POOL_ID VALUES(NULL)");
+    uint64_t tapePoolId = 0;
+    {
+      const char *const sql = "SELECT LAST_INSERT_ROWID() AS ID";
+      auto stmt = conn.createStmt(sql);
+      auto rset = stmt.executeQuery();
+      if(!rset.next()) {
+        throw exception::Exception(std::string("Unexpected empty result set for '") + sql + "\'");
+      }
+      tapePoolId = rset.columnUint64("ID");
+      if(rset.next()) {
+        throw exception::Exception(std::string("Unexpectedly found more than one row in the result of '") + sql + "\'");
+      }
+    }
+    conn.executeNonQuery("DELETE FROM TAPE_POOL_ID");
+
+    return tapePoolId;
+  } catch(exception::UserError &) {
+    throw;
+  } catch(exception::Exception &ex) {
+    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
+    throw;
+  }
+}
+
+//------------------------------------------------------------------------------
+// getTapeLastFSeq
+//------------------------------------------------------------------------------
+uint64_t SqliteCatalogue::getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) {
   try {
     const char *const sql =
       "SELECT "
-        "VID AS VID,"
-        "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME,"
-        "TAPE_POOL_NAME AS TAPE_POOL_NAME,"
-        "ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME,"
-        "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
-        "DATA_IN_BYTES AS DATA_IN_BYTES,"
-        "LAST_FSEQ AS LAST_FSEQ,"
-        "IS_DISABLED AS IS_DISABLED,"
-        "IS_FULL AS IS_FULL,"
-        "IS_READ_ONLY AS IS_READ_ONLY,"
-        "IS_FROM_CASTOR AS IS_FROM_CASTOR,"
-
-        "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,"
-
-        "USER_COMMENT AS USER_COMMENT,"
-
-        "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME,"
-        "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME,"
-        "CREATION_LOG_TIME AS CREATION_LOG_TIME,"
-
-        "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME,"
-        "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME,"
-        "LAST_UPDATE_TIME AS LAST_UPDATE_TIME "
+        "LAST_FSEQ AS LAST_FSEQ "
       "FROM "
         "TAPE "
       "WHERE "
@@ -289,49 +290,7 @@ common::dataStructures::Tape SqliteCatalogue::selectTape(rdbms::Conn &conn, cons
       throw exception::Exception(std::string("The tape with VID " + vid + " does not exist"));
     }
 
-    common::dataStructures::Tape tape;
-
-    tape.vid = rset.columnString("VID");
-    tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME");
-    tape.tapePoolName = rset.columnString("TAPE_POOL_NAME");
-    tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME");
-    tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES");
-    tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES");
-    tape.lastFSeq = rset.columnUint64("LAST_FSEQ");
-    tape.disabled = rset.columnBool("IS_DISABLED");
-    tape.full = rset.columnBool("IS_FULL");
-    tape.readOnly = rset.columnBool("IS_READ_ONLY");
-    tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR");
-
-    tape.labelLog = getTapeLogFromRset(rset, "LABEL_DRIVE", "LABEL_TIME");
-    tape.lastReadLog = getTapeLogFromRset(rset, "LAST_READ_DRIVE", "LAST_READ_TIME");
-    tape.lastWriteLog = getTapeLogFromRset(rset, "LAST_WRITE_DRIVE", "LAST_WRITE_TIME");
-
-    tape.comment = rset.columnString("USER_COMMENT");
-
-    common::dataStructures::RequesterIdentity creatorUI;
-    creatorUI.name = rset.columnString("CREATION_LOG_USER_NAME");
-
-    common::dataStructures::EntryLog creationLog;
-    creationLog.username = rset.columnString("CREATION_LOG_USER_NAME");
-    creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME");
-    creationLog.time = rset.columnUint64("CREATION_LOG_TIME");
-
-    tape.creationLog = creationLog;
-
-    common::dataStructures::RequesterIdentity updaterUI;
-    updaterUI.name = rset.columnString("LAST_UPDATE_USER_NAME");
-
-    common::dataStructures::EntryLog updateLog;
-    updateLog.username = rset.columnString("LAST_UPDATE_USER_NAME");
-    updateLog.host = rset.columnString("LAST_UPDATE_HOST_NAME");
-    updateLog.time = rset.columnUint64("LAST_UPDATE_TIME");
-
-    tape.lastModificationLog = updateLog;
-
-    return tape;
-  } catch(exception::UserError &) {
-    throw;
+    return rset.columnUint64("LAST_FSEQ");
   } catch(exception::Exception &ex) {
     ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
     throw;
@@ -360,8 +319,8 @@ void SqliteCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer>
     threading::MutexLocker locker(m_mutex);
     auto conn = m_connPool.getConn();
 
-    const auto tape = selectTape(conn, firstEvent.vid);
-    uint64_t expectedFSeq = tape.lastFSeq + 1;
+    const uint64_t lastFSeq = getTapeLastFSeq(conn, firstEvent.vid);
+    uint64_t expectedFSeq = lastFSeq + 1;
     uint64_t totalLogicalBytesWritten = 0;
 
     for(const auto &eventP: events) {
diff --git a/catalogue/SqliteCatalogue.hpp b/catalogue/SqliteCatalogue.hpp
index 5446e0b8d6..65eff32c68 100644
--- a/catalogue/SqliteCatalogue.hpp
+++ b/catalogue/SqliteCatalogue.hpp
@@ -114,6 +114,20 @@ protected:
    */
   uint64_t getNextStorageClassId(rdbms::Conn &conn) override;
 
+  /**
+   * Returns a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   *
+   * This method must be implemented by the sub-classes of RdbmsCatalogue
+   * because different database technologies propose different solution to the
+   * problem of generating ever increasing numeric identifiers.
+   *
+   * @param conn The database connection.
+   * @return a unique tape pool ID that can be used by a new tape pool within
+   * the catalogue.
+   */
+  uint64_t getNextTapePoolId(rdbms::Conn &conn) override;
+
   /**
    * Notifies the catalogue that the specified files have been written to tape.
    *
@@ -132,12 +146,13 @@ private:
   void fileWrittenToTape(rdbms::Conn &conn, const TapeFileWritten &event);
 
   /**
-   * Selects the specified tape within the Tape table.
+   * Gets the last FSeq of the specified tape.
    *
    * @param conn The database connection.
    * @param vid The volume identifier of the tape.
+   * @return The last FSeq of the tape.
    */
-  common::dataStructures::Tape selectTape(rdbms::Conn &conn, const std::string &vid);
+  uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid);
 
 }; // class SqliteCatalogue
 
diff --git a/catalogue/common_catalogue_schema.sql b/catalogue/common_catalogue_schema.sql
index 37d2d22298..d5cdb26b92 100644
--- a/catalogue/common_catalogue_schema.sql
+++ b/catalogue/common_catalogue_schema.sql
@@ -45,6 +45,7 @@ CREATE TABLE STORAGE_CLASS(
   CONSTRAINT STORAGE_CLASS_DIN_SCN_UN UNIQUE(DISK_INSTANCE_NAME, STORAGE_CLASS_NAME)
 );
 CREATE TABLE TAPE_POOL(
+  TAPE_POOL_ID            UINT64TYPE      CONSTRAINT TAPE_POOL_TPI_NN  NOT NULL,
   TAPE_POOL_NAME          VARCHAR(100)    CONSTRAINT TAPE_POOL_TPN_NN  NOT NULL,
   VO                      VARCHAR(100)    CONSTRAINT TAPE_POOL_VO_NN   NOT NULL,
   NB_PARTIAL_TAPES        UINT64TYPE      CONSTRAINT TAPE_POOL_NPT_NN  NOT NULL,
@@ -57,13 +58,14 @@ CREATE TABLE TAPE_POOL(
   LAST_UPDATE_USER_NAME   VARCHAR(100)    CONSTRAINT TAPE_POOL_LUUN_NN NOT NULL,
   LAST_UPDATE_HOST_NAME   VARCHAR(100)    CONSTRAINT TAPE_POOL_LUHN_NN NOT NULL,
   LAST_UPDATE_TIME        UINT64TYPE      CONSTRAINT TAPE_POOL_LUT_NN  NOT NULL,
-  CONSTRAINT TAPE_POOL_PK PRIMARY KEY(TAPE_POOL_NAME),
+  CONSTRAINT TAPE_POOL_PK PRIMARY KEY(TAPE_POOL_ID),
+  CONSTRAINT TAPE_POOL_TPN_UN UNIQUE(TAPE_POOL_NAME),
   CONSTRAINT TAPE_POOL_IS_ENCRYPTED_BOOL_CK CHECK(IS_ENCRYPTED IN ('0', '1'))
 );
 CREATE TABLE ARCHIVE_ROUTE(
   STORAGE_CLASS_ID        UINT64TYPE      CONSTRAINT ARCHIVE_ROUTE_SCI_NN  NOT NULL,
   COPY_NB                 UINT64TYPE      CONSTRAINT ARCHIVE_ROUTE_CN_NN   NOT NULL,
-  TAPE_POOL_NAME          VARCHAR(100)    CONSTRAINT ARCHIVE_ROUTE_TPN_NN  NOT NULL,
+  TAPE_POOL_ID            UINT64TYPE      CONSTRAINT ARCHIVE_ROUTE_TPI_NN  NOT NULL,
   USER_COMMENT            VARCHAR(1000)   CONSTRAINT ARCHIVE_ROUTE_UC_NN   NOT NULL,
   CREATION_LOG_USER_NAME  VARCHAR(100)    CONSTRAINT ARCHIVE_ROUTE_CLUN_NN NOT NULL,
   CREATION_LOG_HOST_NAME  VARCHAR(100)    CONSTRAINT ARCHIVE_ROUTE_CLHN_NN NOT NULL,
@@ -73,8 +75,7 @@ CREATE TABLE ARCHIVE_ROUTE(
   LAST_UPDATE_TIME        UINT64TYPE      CONSTRAINT ARCHIVE_ROUTE_LUT_NN  NOT NULL,
   CONSTRAINT ARCHIVE_ROUTE_PK PRIMARY KEY(STORAGE_CLASS_ID, COPY_NB),
   CONSTRAINT ARCHIVE_ROUTE_STORAGE_CLASS_FK FOREIGN KEY(STORAGE_CLASS_ID) REFERENCES STORAGE_CLASS(STORAGE_CLASS_ID),
-  CONSTRAINT ARCHIVE_ROUTE_TAPE_POOL_FK FOREIGN KEY(TAPE_POOL_NAME)
-    REFERENCES TAPE_POOL(TAPE_POOL_NAME),
+  CONSTRAINT ARCHIVE_ROUTE_TAPE_POOL_FK FOREIGN KEY(TAPE_POOL_ID) REFERENCES TAPE_POOL(TAPE_POOL_ID),
   CONSTRAINT ARCHIVE_ROUTE_COPY_NB_GT_ZERO CHECK(COPY_NB > 0)
 );
 CREATE TABLE LOGICAL_LIBRARY(
@@ -95,7 +96,7 @@ CREATE TABLE TAPE(
   MEDIA_TYPE              VARCHAR(100)    CONSTRAINT TAPE_MT_NN   NOT NULL,
   VENDOR                  VARCHAR(100)    CONSTRAINT TAPE_V2_NN   NOT NULL,
   LOGICAL_LIBRARY_NAME    VARCHAR(100)    CONSTRAINT TAPE_LLN_NN  NOT NULL,
-  TAPE_POOL_NAME          VARCHAR(100)    CONSTRAINT TAPE_TPN_NN  NOT NULL,
+  TAPE_POOL_ID            UINT64TYPE      CONSTRAINT TAPE_TPI_NN  NOT NULL,
   ENCRYPTION_KEY_NAME     VARCHAR(100),
   CAPACITY_IN_BYTES       UINT64TYPE      CONSTRAINT TAPE_CIB_NN  NOT NULL,
   DATA_IN_BYTES           UINT64TYPE      CONSTRAINT TAPE_DIB_NN  NOT NULL,
@@ -122,14 +123,13 @@ CREATE TABLE TAPE(
   CONSTRAINT TAPE_PK PRIMARY KEY(VID),
   CONSTRAINT TAPE_LOGICAL_LIBRARY_FK FOREIGN KEY(LOGICAL_LIBRARY_NAME)
     REFERENCES LOGICAL_LIBRARY(LOGICAL_LIBRARY_NAME),
-  CONSTRAINT TAPE_TAPE_POOL_FK FOREIGN KEY(TAPE_POOL_NAME)
-    REFERENCES TAPE_POOL(TAPE_POOL_NAME),
+  CONSTRAINT TAPE_TAPE_POOL_FK FOREIGN KEY(TAPE_POOL_ID) REFERENCES TAPE_POOL(TAPE_POOL_ID),
   CONSTRAINT TAPE_IS_DISABLED_BOOL_CK CHECK(IS_DISABLED IN ('0', '1')),
   CONSTRAINT TAPE_IS_FULL_BOOL_CK CHECK(IS_FULL IN ('0', '1')),
   CONSTRAINT TAPE_IS_READ_ONLY_BOOL_CK CHECK(IS_READ_ONLY IN ('0', '1')),
   CONSTRAINT TAPE_IS_FROM_CASTOR_BOOL_CK CHECK(IS_FROM_CASTOR IN ('0', '1'))
 );
-CREATE INDEX TAPE_TAPE_POOL_NAME_IDX ON TAPE(TAPE_POOL_NAME);
+CREATE INDEX TAPE_TAPE_POOL_ID_IDX ON TAPE(TAPE_POOL_ID);
 CREATE TABLE MOUNT_POLICY(
   MOUNT_POLICY_NAME        VARCHAR(100)    CONSTRAINT MOUNT_POLICY_MPN_NN  NOT NULL,
   ARCHIVE_PRIORITY         UINT64TYPE      CONSTRAINT MOUNT_POLICY_AP_NN   NOT NULL,
diff --git a/catalogue/mysql_catalogue_schema_header.sql b/catalogue/mysql_catalogue_schema_header.sql
index fc069549a2..70a7cb314e 100644
--- a/catalogue/mysql_catalogue_schema_header.sql
+++ b/catalogue/mysql_catalogue_schema_header.sql
@@ -8,3 +8,9 @@ CREATE TABLE STORAGE_CLASS_ID(
   CONSTRAINT STORAGE_CLASS_ID_PK PRIMARY KEY(ID)
 );
 INSERT INTO STORAGE_CLASS_ID(ID) VALUES(1);
+CREATE TABLE TAPE_POOL_ID(
+  ID UINT64TYPE,
+  CONSTRAINT TAPE_POOL_ID_PK PRIMARY KEY(ID)
+);
+INSERT INTO TAPE_POOL_ID(ID) VALUES(1);
+
diff --git a/catalogue/oracle_catalogue_schema_header.sql b/catalogue/oracle_catalogue_schema_header.sql
index b4038762e0..f3345ec826 100644
--- a/catalogue/oracle_catalogue_schema_header.sql
+++ b/catalogue/oracle_catalogue_schema_header.sql
@@ -14,6 +14,14 @@ CREATE SEQUENCE STORAGE_CLASS_ID_SEQ
   NOCYCLE
   CACHE 20
   NOORDER;
+CREATE SEQUENCE TAPE_POOL_ID_SEQ
+  INCREMENT BY 1
+  START WITH 4294967296
+  NOMAXVALUE
+  MINVALUE 1
+  NOCYCLE
+  CACHE 20
+  NOORDER;
 CREATE GLOBAL TEMPORARY TABLE TEMP_TAPE_FILE_INSERTION_BATCH(
   VID                   VARCHAR(100),
   FSEQ                  UINT64TYPE  ,
diff --git a/catalogue/postgres_catalogue_schema_header.sql b/catalogue/postgres_catalogue_schema_header.sql
index c46162e86f..1ec5a948cf 100644
--- a/catalogue/postgres_catalogue_schema_header.sql
+++ b/catalogue/postgres_catalogue_schema_header.sql
@@ -12,3 +12,10 @@ CREATE SEQUENCE STORAGE_CLASS_ID_SEQ
   MINVALUE 1
   NO CYCLE
   CACHE 20;
+CREATE SEQUENCE TAPE_POOL_ID_SEQ
+  INCREMENT BY 1
+  START WITH 1
+  NO MAXVALUE
+  MINVALUE 1
+  NO CYCLE
+  CACHE 20;
diff --git a/catalogue/sqlite_catalogue_schema_header.sql b/catalogue/sqlite_catalogue_schema_header.sql
index 58e6973958..d813579287 100644
--- a/catalogue/sqlite_catalogue_schema_header.sql
+++ b/catalogue/sqlite_catalogue_schema_header.sql
@@ -4,3 +4,6 @@ CREATE TABLE ARCHIVE_FILE_ID(
 CREATE TABLE STORAGE_CLASS_ID(
   ID INTEGER PRIMARY KEY AUTOINCREMENT
 );
+CREATE TABLE TAPE_POOL_ID(
+  ID INTEGER PRIMARY KEY AUTOINCREMENT
+);
-- 
GitLab