From adac05943db1c904a8a65913be95ec5d0135b647 Mon Sep 17 00:00:00 2001
From: Steven Murray <steven.murray@cern.ch>
Date: Mon, 27 Jun 2016 16:16:37 +0200
Subject: [PATCH] catalogue::TapeFileWritten now covers tape drive name and
 checksums

---
 catalogue/InMemoryCatalogueTest.cpp | 78 +++++++++++++++++++++++++++++
 catalogue/OcciRset.cpp              |  8 ++-
 catalogue/OcciStmt.cpp              |  2 +-
 catalogue/OracleCatalogue.cpp       |  2 +-
 catalogue/RdbmsCatalogue.cpp        | 61 +++++++++++++++-------
 catalogue/RdbmsCatalogue.hpp        |  7 ++-
 catalogue/SqliteCatalogue.cpp       |  2 +-
 catalogue/TapeFileWritten.cpp       | 34 +++++++------
 catalogue/TapeFileWritten.hpp       |  5 ++
 scheduler/ArchiveJob.cpp            |  1 +
 10 files changed, 158 insertions(+), 42 deletions(-)

diff --git a/catalogue/InMemoryCatalogueTest.cpp b/catalogue/InMemoryCatalogueTest.cpp
index 1c1c744bb4..778b34295b 100644
--- a/catalogue/InMemoryCatalogueTest.cpp
+++ b/catalogue/InMemoryCatalogueTest.cpp
@@ -2028,6 +2028,9 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, prepareToRetrieveFile) {
   m_catalogue->createStorageClass(m_cliSI, storageClassName, nbCopies, "create storage class");
 
   const uint64_t archiveFileSize = 1;
+  const std::string tapeDrive = "tape_drive";
+  const std::string checksumType = "checksum_type";
+  const std::string checksumValue = "checksum_value";
 
   catalogue::TapeFileWritten file1Written;
   file1Written.archiveFileId        = archiveFileId;
@@ -2038,12 +2041,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, prepareToRetrieveFile) {
   file1Written.diskFileGroup        = "public_disk_group";
   file1Written.diskFileRecoveryBlob = "opaque_disk_file_recovery_contents";
   file1Written.size                 = archiveFileSize;
+  file1Written.checksumType         = checksumType;
+  file1Written.checksumValue        = checksumValue;
   file1Written.storageClassName     = storageClassName;
   file1Written.vid                  = vid1;
   file1Written.fSeq                 = 1;
   file1Written.blockId              = 4321;
   file1Written.compressedSize       = 1;
   file1Written.copyNb               = 1;
+  file1Written.tapeDrive            = tapeDrive;
   m_catalogue->fileWrittenToTape(file1Written);
 
   {
@@ -2052,6 +2058,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, prepareToRetrieveFile) {
     ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file1Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file1Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file1Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance);
@@ -2080,12 +2088,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, prepareToRetrieveFile) {
   file2Written.diskFileGroup        = file1Written.diskFileGroup;
   file2Written.diskFileRecoveryBlob = file1Written.diskFileRecoveryBlob;
   file2Written.size                 = archiveFileSize;
+  file2Written.checksumType         = checksumType;
+  file2Written.checksumValue        = checksumValue;
   file2Written.storageClassName     = storageClassName;
   file2Written.vid                  = vid2;
   file2Written.fSeq                 = 1;
   file2Written.blockId              = 4331;
   file2Written.compressedSize       = 1;
   file2Written.copyNb               = 2;
+  file2Written.tapeDrive            = tapeDrive;
   m_catalogue->fileWrittenToTape(file2Written);
 
   {
@@ -2094,6 +2105,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, prepareToRetrieveFile) {
     ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file2Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file2Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file2Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance);
@@ -2219,6 +2232,10 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_many_archive_files
   const uint64_t nbCopies = 1;
   m_catalogue->createStorageClass(m_cliSI, storageClassName, nbCopies, "create storage class");
 
+  const std::string checksumType = "checksum_type";
+  const std::string checksumValue = "checksum_value";
+  const std::string tapeDrive = "tape_drive";
+
   ASSERT_FALSE(m_catalogue->getArchiveFileItor()->hasMore());
   const uint64_t nbArchiveFiles = 10;
   for(uint64_t i = 1; i <= nbArchiveFiles; i++) {
@@ -2237,12 +2254,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_many_archive_files
     fileWritten.diskFileGroup = "public_disk_group";
     fileWritten.diskFileRecoveryBlob = "opaque_disk_file_recovery_contents";
     fileWritten.size = archiveFileSize;
+    fileWritten.checksumType = checksumType;
+    fileWritten.checksumValue = checksumValue;
     fileWritten.storageClassName = storageClassName;
     fileWritten.vid = vid;
     fileWritten.fSeq = i;
     fileWritten.blockId = i * 100;
     fileWritten.compressedSize = 1;
     fileWritten.copyNb = 1;
+    fileWritten.tapeDrive = tapeDrive;
     m_catalogue->fileWrittenToTape(fileWritten);
 
     const std::list<common::dataStructures::Tape> tapes = m_catalogue->getTapes();
@@ -2275,6 +2295,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_many_archive_files
       fileWritten.diskFileGroup = "public_disk_group";
       fileWritten.diskFileRecoveryBlob = "opaque_disk_file_recovery_contents";
       fileWritten.size = archiveFileSize;
+      fileWritten.checksumType = checksumType;
+      fileWritten.checksumValue = checksumValue;
       fileWritten.storageClassName = storageClassName;
       fileWritten.vid = vid;
       fileWritten.fSeq = i;
@@ -2293,6 +2315,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_many_archive_files
       ASSERT_EQ(fileWritten.diskFileGroup, archiveFile.diskFileInfo.group);
       ASSERT_EQ(fileWritten.diskFileRecoveryBlob, archiveFile.diskFileInfo.recoveryBlob);
       ASSERT_EQ(fileWritten.size, archiveFile.fileSize);
+      ASSERT_EQ(fileWritten.checksumType, archiveFile.checksumType);
+      ASSERT_EQ(fileWritten.checksumValue, archiveFile.checksumValue);
       ASSERT_EQ(fileWritten.storageClassName, archiveFile.storageClass);
       ASSERT_EQ(1, archiveFile.tapeFiles.size());
       ASSERT_EQ(fileWritten.vid, archiveFile.tapeFiles.begin()->second.vid);
@@ -2479,6 +2503,9 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_diffe
   m_catalogue->createStorageClass(m_cliSI, storageClassName, nbCopies, "create storage class");
 
   const uint64_t archiveFileSize = 1;
+  const std::string checksumType = "checksum_type";
+  const std::string checksumValue = "checksum_value";
+  const std::string tapeDrive = "tape_drive";
 
   catalogue::TapeFileWritten file1Written;
   file1Written.archiveFileId        = archiveFileId;
@@ -2489,12 +2516,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_diffe
   file1Written.diskFileGroup        = "public_disk_group";
   file1Written.diskFileRecoveryBlob = "opaque_disk_file_recovery_contents";
   file1Written.size                 = archiveFileSize;
+  file1Written.checksumType         = checksumType;
+  file1Written.checksumValue        = checksumValue;
   file1Written.storageClassName     = storageClassName;
   file1Written.vid                  = vid1;
   file1Written.fSeq                 = 1;
   file1Written.blockId              = 4321;
   file1Written.compressedSize       = 1;
   file1Written.copyNb               = 1;
+  file1Written.tapeDrive            = tapeDrive;
   m_catalogue->fileWrittenToTape(file1Written);
 
   {
@@ -2512,6 +2542,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_diffe
     ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file1Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file1Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file1Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance);
@@ -2540,12 +2572,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_diffe
   file2Written.diskFileGroup        = file1Written.diskFileGroup;
   file2Written.diskFileRecoveryBlob = file1Written.diskFileRecoveryBlob;
   file2Written.size                 = archiveFileSize;
+  file2Written.checksumType         = checksumType;
+  file2Written.checksumValue        = checksumValue;
   file2Written.storageClassName     = storageClassName;
   file2Written.vid                  = vid2;
   file2Written.fSeq                 = 1;
   file2Written.blockId              = 4331;
   file2Written.compressedSize       = 1;
   file2Written.copyNb               = 2;
+  file2Written.tapeDrive            = tapeDrive;
   m_catalogue->fileWrittenToTape(file2Written);
 
   {
@@ -2564,6 +2599,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_diffe
     ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file2Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file2Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file2Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance);
@@ -2641,6 +2678,9 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_same_
   }
 
   const uint64_t archiveFileId = 1234;
+  const std::string checksumType = "checksum_type";
+  const std::string checksumValue = "checksum_value";
+  const std::string tapeDrive = "tape_drive";
 
   ASSERT_FALSE(m_catalogue->getArchiveFileItor()->hasMore());
   ASSERT_THROW(m_catalogue->getArchiveFileById(archiveFileId), exception::Exception);
@@ -2660,12 +2700,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_same_
   file1Written.diskFileGroup        = "public_disk_group";
   file1Written.diskFileRecoveryBlob = "opaque_disk_file_recovery_contents";
   file1Written.size                 = archiveFileSize;
+  file1Written.checksumType         = checksumType;
+  file1Written.checksumValue        = checksumValue;
   file1Written.storageClassName     = storageClassName;
   file1Written.vid                  = vid;
   file1Written.fSeq                 = 1;
   file1Written.blockId              = 4321;
   file1Written.compressedSize       = 1;
   file1Written.copyNb               = 1;
+  file1Written.tapeDrive            = tapeDrive;
   m_catalogue->fileWrittenToTape(file1Written);
 
   {
@@ -2683,6 +2726,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_same_
     ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file1Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file1Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file1Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance);
@@ -2711,12 +2756,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_same_
   file2Written.diskFileGroup        = file1Written.diskFileGroup;
   file2Written.diskFileRecoveryBlob = file1Written.diskFileRecoveryBlob;
   file2Written.size                 = archiveFileSize;
+  file2Written.checksumType         = checksumType;
+  file2Written.checksumValue        = checksumValue;
   file2Written.storageClassName     = storageClassName;
   file2Written.vid                  = vid;
   file2Written.fSeq                 = 2;
   file2Written.blockId              = 4331;
   file2Written.compressedSize       = 1;
   file2Written.copyNb               = 2;
+  file2Written.tapeDrive            = tapeDrive;
   ASSERT_THROW(m_catalogue->fileWrittenToTape(file2Written), exception::Exception);
 }
 
@@ -2773,6 +2821,9 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_corru
     "create storage class");
 
   const uint64_t archiveFileSize = 1;
+  const std::string checksumType = "checksum_type";
+  const std::string checksumValue = "checksum_value";
+  const std::string tapeDrive = "tape_drive";
 
   catalogue::TapeFileWritten file1Written;
   file1Written.archiveFileId        = archiveFileId;
@@ -2783,12 +2834,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_corru
   file1Written.diskFileGroup        = "public_disk_group";
   file1Written.diskFileRecoveryBlob = "opaque_disk_file_recovery_contents";
   file1Written.size                 = archiveFileSize;
+  file1Written.checksumType         = checksumType;
+  file1Written.checksumValue        = checksumValue;
   file1Written.storageClassName     = storageClassName;
   file1Written.vid                  = vid;
   file1Written.fSeq                 = 1;
   file1Written.blockId              = 4321;
   file1Written.compressedSize       = 1;
   file1Written.copyNb               = 1;
+  file1Written.tapeDrive            = tapeDrive;
   m_catalogue->fileWrittenToTape(file1Written);
 
   {
@@ -2797,6 +2851,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_corru
     ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file1Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file1Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file1Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance);
@@ -2825,12 +2881,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, fileWrittenToTape_2_tape_files_corru
   file2Written.diskFileGroup        = file1Written.diskFileGroup;
   file2Written.diskFileRecoveryBlob = file1Written.diskFileRecoveryBlob;
   file2Written.size                 = archiveFileSize;
+  file2Written.checksumType         = checksumType;
+  file2Written.checksumValue        = checksumValue;
   file2Written.storageClassName     = storageClassName;
   file2Written.vid                  = "VID123";
   file2Written.fSeq                 = 2;
   file2Written.blockId              = 4331;
   file2Written.compressedSize       = 1;
   file2Written.copyNb               = 2;
+  file2Written.tapeDrive            = tapeDrive;
 
   ASSERT_THROW(m_catalogue->fileWrittenToTape(file2Written), exception::Exception);
 }
@@ -2915,6 +2974,9 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, deleteArchiveFile) {
   m_catalogue->createStorageClass(m_cliSI, storageClassName, nbCopies, "create storage class");
 
   const uint64_t archiveFileSize = 1;
+  const std::string checksumType = "checksum_type";
+  const std::string checksumValue = "checksum_value";
+  const std::string tapeDrive = "tape_drive";
 
   catalogue::TapeFileWritten file1Written;
   file1Written.archiveFileId        = archiveFileId;
@@ -2925,12 +2987,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, deleteArchiveFile) {
   file1Written.diskFileGroup        = "public_disk_group";
   file1Written.diskFileRecoveryBlob = "opaque_disk_file_recovery_contents";
   file1Written.size                 = archiveFileSize;
+  file1Written.checksumType         = checksumType;
+  file1Written.checksumValue        = checksumValue;
   file1Written.storageClassName     = storageClassName;
   file1Written.vid                  = vid1;
   file1Written.fSeq                 = 1;
   file1Written.blockId              = 4321;
   file1Written.compressedSize       = 1;
   file1Written.copyNb               = 1;
+  file1Written.tapeDrive            = tapeDrive;
   m_catalogue->fileWrittenToTape(file1Written);
 
   {
@@ -2954,6 +3019,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, deleteArchiveFile) {
     ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file1Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file1Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file1Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance);
@@ -2979,6 +3046,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, deleteArchiveFile) {
     ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file1Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file1Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file1Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance);
@@ -3007,12 +3076,15 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, deleteArchiveFile) {
   file2Written.diskFileGroup        = file1Written.diskFileGroup;
   file2Written.diskFileRecoveryBlob = file1Written.diskFileRecoveryBlob;
   file2Written.size                 = archiveFileSize;
+  file2Written.checksumType         = checksumType;
+  file2Written.checksumValue        = checksumValue;
   file2Written.storageClassName     = storageClassName;
   file2Written.vid                  = vid2;
   file2Written.fSeq                 = 1;
   file2Written.blockId              = 4331;
   file2Written.compressedSize       = 1;
   file2Written.copyNb               = 2;
+  file2Written.tapeDrive            = tapeDrive;
   m_catalogue->fileWrittenToTape(file2Written);
 
   {
@@ -3039,6 +3111,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, deleteArchiveFile) {
       ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID);
       ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId);
       ASSERT_EQ(file2Written.size, archiveFile.fileSize);
+      ASSERT_EQ(file2Written.checksumType, archiveFile.checksumType);
+      ASSERT_EQ(file2Written.checksumValue, archiveFile.checksumValue);
       ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass);
 
       ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance);
@@ -3075,6 +3149,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, deleteArchiveFile) {
     ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file2Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file2Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file2Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance);
@@ -3110,6 +3186,8 @@ TEST_F(cta_catalogue_InMemoryCatalogueTest, deleteArchiveFile) {
     ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID);
     ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId);
     ASSERT_EQ(file2Written.size, archiveFile.fileSize);
+    ASSERT_EQ(file2Written.checksumType, archiveFile.checksumType);
+    ASSERT_EQ(file2Written.checksumValue, archiveFile.checksumValue);
     ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass);
 
     ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance);
diff --git a/catalogue/OcciRset.cpp b/catalogue/OcciRset.cpp
index 0b68e1ff97..ceca345996 100644
--- a/catalogue/OcciRset.cpp
+++ b/catalogue/OcciRset.cpp
@@ -19,6 +19,7 @@
 #include "catalogue/OcciRset.hpp"
 #include "catalogue/OcciStmt.hpp"
 #include "common/exception/Exception.hpp"
+#include "common/utils/utils.hpp"
 
 #include <cstring>
 #include <map>
@@ -161,7 +162,12 @@ uint64_t OcciRset::columnUint64(const std::string &colName) const {
     std::lock_guard<std::mutex> lock(m_mutex);
 
     const int colIdx = m_colNameToIdx.getIdx(colName);
-    return m_rset->getUInt(colIdx);
+    const std::string stringValue = m_rset->getString(colIdx);
+    if(!utils::isValidUInt(stringValue)) {
+      throw exception::Exception(std::string("Column ") + colName + " contains the value " + stringValue +
+        " which is not a valid unsigned integer");
+    }
+    return utils::toUint64(stringValue);
   } catch(exception::Exception &ne) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() + ": " +
       ne.getMessage().str());
diff --git a/catalogue/OcciStmt.cpp b/catalogue/OcciStmt.cpp
index e9d901e9ad..77c7e2ae43 100644
--- a/catalogue/OcciStmt.cpp
+++ b/catalogue/OcciStmt.cpp
@@ -87,7 +87,7 @@ const std::string &OcciStmt::getSql() const {
 void OcciStmt::bindUint64(const std::string &paramName, const uint64_t paramValue) {
   try {
     const unsigned paramIdx = m_paramNameToIdx.getIdx(paramName);
-    m_stmt->setUInt(paramIdx, paramValue);
+    m_stmt->setString(paramIdx, std::to_string(paramValue));
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + getSql() + ": " +
       ex.getMessage().str());
diff --git a/catalogue/OracleCatalogue.cpp b/catalogue/OracleCatalogue.cpp
index e0697ed273..d7333afa0a 100644
--- a/catalogue/OracleCatalogue.cpp
+++ b/catalogue/OracleCatalogue.cpp
@@ -110,7 +110,7 @@ common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(const std::str
     tape.logicalLibraryName = rset->columnText("LOGICAL_LIBRARY_NAME");
     tape.tapePoolName = rset->columnText("TAPE_POOL_NAME");
     tape.encryptionKey = rset->columnText("ENCRYPTION_KEY");
-    tape.capacityInBytes = utils::toUint64(rset->columnText("CAPACITY_IN_BYTES"));
+    tape.capacityInBytes = rset->columnUint64("CAPACITY_IN_BYTES");
     tape.dataOnTapeInBytes = rset->columnUint64("DATA_IN_BYTES");
     tape.lastFSeq = rset->columnUint64("LAST_FSEQ");
     tape.disabled = rset->columnUint64("IS_DISABLED");
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index 6dfb30c3dc..cca178c147 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -1128,7 +1128,7 @@ void RdbmsCatalogue::createTape(
     stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
     stmt->bindString(":TAPE_POOL_NAME", tapePoolName);
     stmt->bindString(":ENCRYPTION_KEY", encryptionKey);
-    stmt->bindString(":CAPACITY_IN_BYTES", std::to_string(capacityInBytes));
+    stmt->bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
     stmt->bindUint64(":DATA_IN_BYTES", 0);
     stmt->bindUint64(":LAST_FSEQ", 0);
     stmt->bindUint64(":IS_DISABLED", disabledValue);
@@ -1292,7 +1292,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(const TapeSearc
     if(!searchCriteria.vid.empty()) stmt->bindString(":VID", searchCriteria.vid);
     if(!searchCriteria.logicalLibrary.empty()) stmt->bindString(":LOGICAL_LIBRARY_NAME", searchCriteria.logicalLibrary);
     if(!searchCriteria.tapePool.empty()) stmt->bindString(":TAPE_POOL_NAME", searchCriteria.tapePool);
-    if(!searchCriteria.capacityInBytes.empty()) stmt->bindString(":CAPACITY_IN_BYTES", searchCriteria.capacityInBytes);
+    if(!searchCriteria.capacityInBytes.empty()) stmt->bindUint64(":CAPACITY_IN_BYTES", utils::toUint64(searchCriteria.capacityInBytes));
     if(!searchCriteria.disabled.empty()) stmt->bindUint64(":IS_DISABLED", toUpper(searchCriteria.disabled) == "TRUE");
     if(!searchCriteria.full.empty()) stmt->bindUint64(":IS_FULL", toUpper(searchCriteria.full) == "TRUE");
     if(!searchCriteria.lbp.empty()) stmt->bindUint64(":LBP_IS_ON", toUpper(searchCriteria.lbp) == "TRUE");
@@ -1305,7 +1305,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(const TapeSearc
       tape.logicalLibraryName = rset->columnText("LOGICAL_LIBRARY_NAME");
       tape.tapePoolName = rset->columnText("TAPE_POOL_NAME");
       tape.encryptionKey = rset->columnText("ENCRYPTION_KEY");
-      tape.capacityInBytes = utils::toUint64(rset->columnText("CAPACITY_IN_BYTES"));
+      tape.capacityInBytes = rset->columnUint64("CAPACITY_IN_BYTES");
       tape.dataOnTapeInBytes = rset->columnUint64("DATA_IN_BYTES");
       tape.lastFSeq = rset->columnUint64("LAST_FSEQ");
       tape.disabled = rset->columnUint64("IS_DISABLED");
@@ -2286,8 +2286,8 @@ void RdbmsCatalogue::insertArchiveFile(const ArchiveFileRow &row) {
     stmt->bindString(":DISK_FILE_GROUP", row.diskFileGroup);
     stmt->bindString(":DISK_FILE_RECOVERY_BLOB", row.diskFileRecoveryBlob);
     stmt->bindUint64(":FILE_SIZE", row.size);
-    stmt->bindString(":CHECKSUM_TYPE", "HELP");
-    stmt->bindString(":CHECKSUM_VALUE", "HELP");
+    stmt->bindString(":CHECKSUM_TYPE", row.checksumType);
+    stmt->bindString(":CHECKSUM_VALUE", row.checksumValue);
     stmt->bindString(":STORAGE_CLASS_NAME", row.storageClassName);
     stmt->bindUint64(":CREATION_TIME", now);
     stmt->bindUint64(":RECONCILIATION_TIME", now);
@@ -2672,6 +2672,18 @@ uint64_t RdbmsCatalogue::getExpectedNbArchiveRoutes(const std::string &storageCl
 //------------------------------------------------------------------------------
 void RdbmsCatalogue::fileWrittenToTape(const TapeFileWritten &event) {
   try {
+    if(event.diskInstance.empty()) throw exception::Exception("diskInstance is an empty string");
+    if(event.diskFileId.empty()) throw exception::Exception("diskFileId is an empty string");
+    if(event.diskFilePath.empty()) throw exception::Exception("diskFilePath is an empty string");
+    if(event.diskFileUser.empty()) throw exception::Exception("diskFileUser is an empty string");
+    if(event.diskFileGroup.empty()) throw exception::Exception("diskFileGroup is an empty string");
+    if(event.diskFileRecoveryBlob.empty()) throw exception::Exception("diskFileRecoveryBlob is an empty string");
+    if(event.checksumType.empty()) throw exception::Exception("checksumType is an empty string");
+    if(event.checksumValue.empty()) throw exception::Exception("checksumValue is an empty string");
+    if(event.storageClassName.empty()) throw exception::Exception("storageClassName is an empty string");
+    if(event.vid.empty()) throw exception::Exception("vid is an empty string");
+    if(event.tapeDrive.empty()) throw exception::Exception("tapeDrive is an empty string");
+
     const time_t now = time(NULL);
     std::lock_guard<std::mutex> m_lock(m_mutex);
 
@@ -2685,7 +2697,7 @@ void RdbmsCatalogue::fileWrittenToTape(const TapeFileWritten &event) {
         event.fSeq;
       throw ex;
     }
-    updateTapeLastFSeq(event.vid, event.fSeq);
+    updateTape(event);
 
     std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile = getArchiveFile(event.archiveFileId);
 
@@ -2697,6 +2709,8 @@ void RdbmsCatalogue::fileWrittenToTape(const TapeFileWritten &event) {
       row.diskFileId = event.diskFileId;
       row.diskInstance = event.diskInstance;
       row.size = event.size;
+      row.checksumType = event.checksumType;
+      row.checksumValue = event.checksumValue;
       row.storageClassName = event.storageClassName;
       row.diskFilePath = event.diskFilePath;
       row.diskFileUser = event.diskFileUser;
@@ -2725,18 +2739,29 @@ void RdbmsCatalogue::fileWrittenToTape(const TapeFileWritten &event) {
 }
 
 //------------------------------------------------------------------------------
-// updateTapeLastFSeq
+// updateTape
 //------------------------------------------------------------------------------
-void RdbmsCatalogue::updateTapeLastFSeq(const std::string &vid, const uint64_t lastFSeq) {
-  const char *const sql =
-    "UPDATE TAPE SET "
-      "LAST_FSEQ = :LAST_FSEQ "
-    "WHERE "
-      "VID=:VID";
-  std::unique_ptr<DbStmt> stmt(m_conn->createStmt(sql));
-  stmt->bindString(":VID", vid);
-  stmt->bindUint64(":LAST_FSEQ", lastFSeq);
-  stmt->executeNonQuery();
+void RdbmsCatalogue::updateTape(const TapeFileWritten &event) {
+  try {
+    const time_t now = time(NULL);
+    const char *const sql =
+      "UPDATE TAPE SET "
+        "LAST_FSEQ = :LAST_FSEQ,"
+        "DATA_IN_BYTES = DATA_IN_BYTES + :DATA_IN_BYTES,"
+        "LAST_WRITE_DRIVE = :LAST_WRITE_DRIVE,"
+        "LAST_WRITE_TIME = :LAST_WRITE_TIME "
+      "WHERE "
+        "VID=:VID";
+    std::unique_ptr<DbStmt> stmt(m_conn->createStmt(sql));
+    stmt->bindString(":VID", event.vid);
+    stmt->bindUint64(":LAST_FSEQ", event.fSeq);
+    stmt->bindUint64(":DATA_IN_BYTES", event.compressedSize);
+    stmt->bindString(":LAST_WRITE_DRIVE", event.tapeDrive);
+    stmt->bindUint64(":LAST_WRITE_TIME", now);
+    stmt->executeNonQuery();
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) +  " failed: " + ex.getMessage().str());
+  }
 }
 
 //------------------------------------------------------------------------------
@@ -3028,7 +3053,7 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string &
 
       tape.vid = rset->columnText("VID");
       tape.tapePool = rset->columnText("TAPE_POOL_NAME");
-      tape.capacityInBytes = utils::toUint64(rset->columnText("CAPACITY_IN_BYTES"));
+      tape.capacityInBytes = rset->columnUint64("CAPACITY_IN_BYTES");
       tape.dataOnTapeInBytes = rset->columnUint64("DATA_IN_BYTES");
       tape.lastFSeq = rset->columnUint64("LAST_FSEQ");
       tape.lbp = rset->columnUint64("LBP_IS_ON");
diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp
index 165f760298..e5744705b4 100644
--- a/catalogue/RdbmsCatalogue.hpp
+++ b/catalogue/RdbmsCatalogue.hpp
@@ -514,12 +514,11 @@ protected:
   uint64_t getTapeLastFSeq(const std::string &vid) const;
 
   /**
-   * Updates the lastFSeq column of the specified tape within the Tape table.
+   * Updates the appropriate tape based on the ocuurence of the specified event.
    *
-   * @param vid The volume identifier of the tape.
-   * @param lastFseq The new value of the lastFseq column.
+   * @param event
    */
-  void updateTapeLastFSeq(const std::string &vid, const uint64_t lastFSeq);
+  void updateTape(const TapeFileWritten &event);
 
   /**
    * Returns the specified archive file or a NULL pointer if it does not exist.
diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp
index ffda9251ef..40fc1b69b6 100644
--- a/catalogue/SqliteCatalogue.cpp
+++ b/catalogue/SqliteCatalogue.cpp
@@ -240,7 +240,7 @@ common::dataStructures::Tape SqliteCatalogue::selectTapeForUpdate(const std::str
     tape.logicalLibraryName = rset->columnText("LOGICAL_LIBRARY_NAME");
     tape.tapePoolName = rset->columnText("TAPE_POOL_NAME");
     tape.encryptionKey = rset->columnText("ENCRYPTION_KEY");
-    tape.capacityInBytes = utils::toUint64(rset->columnText("CAPACITY_IN_BYTES"));
+    tape.capacityInBytes = rset->columnUint64("CAPACITY_IN_BYTES");
     tape.dataOnTapeInBytes = rset->columnUint64("DATA_IN_BYTES");
     tape.lastFSeq = rset->columnUint64("LAST_FSEQ");
     tape.disabled = rset->columnUint64("IS_DISABLED");
diff --git a/catalogue/TapeFileWritten.cpp b/catalogue/TapeFileWritten.cpp
index 618043d0f9..8de49896f8 100644
--- a/catalogue/TapeFileWritten.cpp
+++ b/catalogue/TapeFileWritten.cpp
@@ -53,7 +53,8 @@ bool TapeFileWritten::operator==(const TapeFileWritten &rhs) const {
     fSeq == rhs.fSeq &&
     blockId == rhs.blockId &&
     compressedSize == rhs.compressedSize &&
-    copyNb == rhs.copyNb;
+    copyNb == rhs.copyNb &&
+    tapeDrive == rhs.tapeDrive;
 }
 
 //------------------------------------------------------------------------------
@@ -62,21 +63,22 @@ bool TapeFileWritten::operator==(const TapeFileWritten &rhs) const {
 std::ostream &operator<<(std::ostream &os, const TapeFileWritten &obj) {
   os <<
   "{"
-  "archiveFileId=" << obj.archiveFileId <<
-  "diskInstance=" << obj.diskInstance <<
-  "diskFileId=" << obj.diskFileId <<
-  "diskFilePath=" << obj.diskFilePath <<
-  "diskFileUser=" << obj.diskFileUser <<
-  "diskFileGroup=" << obj.diskFileGroup <<
-  "diskFileRecoveryBlob=" << obj.diskFileRecoveryBlob <<
-  "size=" << obj.size <<
-  "checksumType=" << obj.checksumType << "checksumValue=" << obj.checksumValue <<
-  "storageClassName=" << obj.storageClassName <<
-  "vid=" << obj.vid <<
-  "fSeq=" << obj.fSeq <<
-  "blockId=" << obj.blockId <<
-  "compressedSize=" << obj.compressedSize <<
-  "copyNb=" << obj.copyNb <<
+  "archiveFileId=" << obj.archiveFileId << ","
+  "diskInstance=" << obj.diskInstance << ","
+  "diskFileId=" << obj.diskFileId << ","
+  "diskFilePath=" << obj.diskFilePath << ","
+  "diskFileUser=" << obj.diskFileUser << ","
+  "diskFileGroup=" << obj.diskFileGroup << ","
+  "diskFileRecoveryBlob=" << obj.diskFileRecoveryBlob << ","
+  "size=" << obj.size << ","
+  "checksumType=" << obj.checksumType << "checksumValue=" << obj.checksumValue << ","
+  "storageClassName=" << obj.storageClassName << ","
+  "vid=" << obj.vid << ","
+  "fSeq=" << obj.fSeq << ","
+  "blockId=" << obj.blockId << ","
+  "compressedSize=" << obj.compressedSize << ","
+  "copyNb=" << obj.copyNb << ","
+  "tapeDrive=" << obj.tapeDrive <<
   "}";
   return os;
 }
diff --git a/catalogue/TapeFileWritten.hpp b/catalogue/TapeFileWritten.hpp
index 3329170be0..d5da0e3c6a 100644
--- a/catalogue/TapeFileWritten.hpp
+++ b/catalogue/TapeFileWritten.hpp
@@ -132,6 +132,11 @@ struct TapeFileWritten {
    */
   uint64_t copyNb;
 
+  /**
+   * The name of the tape drive that wrote the file.
+   */
+  std::string tapeDrive;
+
 }; // struct TapeFileWritten
 
 /**
diff --git a/scheduler/ArchiveJob.cpp b/scheduler/ArchiveJob.cpp
index e299a19b47..7b5f918b32 100644
--- a/scheduler/ArchiveJob.cpp
+++ b/scheduler/ArchiveJob.cpp
@@ -70,6 +70,7 @@ void cta::ArchiveJob::complete() {
   fileReport.size = archiveFile.fileSize;
   //TODO fileReport.storageClassName
   fileReport.vid = tapeFile.vid;
+  //TODO fileReport.tapeDrive
   m_catalogue.fileWrittenToTape(fileReport);
   //m_ns.addTapeFile(SecurityIdentity(UserIdentity(std::numeric_limits<uint32_t>::max(), 
   //  std::numeric_limits<uint32_t>::max()), ""), archiveFile.fileId, nameServerTapeFile);
-- 
GitLab