From 045d2acbb81312b5465141fbb076f6b11a859fa2 Mon Sep 17 00:00:00 2001
From: Steven Murray <steven.murray@cern.ch>
Date: Thu, 4 Aug 2016 12:02:50 +0200
Subject: [PATCH] Member variable Tape::lbp is now optional

---
 catalogue/Catalogue.hpp               |   4 +-
 catalogue/CatalogueTest.cpp           |  45 ++++++++++++---
 catalogue/OracleCatalogue.cpp         |   6 +-
 catalogue/RdbmsCatalogue.cpp          |  76 +++++++++++++++++---------
 catalogue/RdbmsCatalogue.hpp          |   7 +--
 catalogue/SqliteCatalogue.cpp         |   6 +-
 catalogue/TapeForWriting.cpp          |  12 ++--
 catalogue/TapeForWriting.hpp          |   7 +--
 catalogue/catalogue_common_schema.sql |   2 +-
 catalogue/catalogue_schema.pdf        | Bin 94418 -> 94410 bytes
 common/dataStructures/Tape.cpp        |   4 +-
 common/dataStructures/Tape.hpp        |   8 ++-
 rdbms/OcciRset.hpp                    |   4 +-
 rdbms/Rset.cpp                        |  32 +++++++++++
 rdbms/Rset.hpp                        |  31 ++++++++++-
 rdbms/SqliteRset.hpp                  |   4 +-
 rdbms/Stmt.cpp                        |  18 ++++++
 rdbms/Stmt.hpp                        |  16 ++++++
 18 files changed, 213 insertions(+), 69 deletions(-)

diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp
index 7c31701bbd..e647e8ebe9 100644
--- a/catalogue/Catalogue.hpp
+++ b/catalogue/Catalogue.hpp
@@ -454,8 +454,8 @@ public:
 
   /**
    * Returns the list of tapes that can be written to by a tape drive in the
-   * specified logical library, in other words tapes that are not disabled, not
-   * full and are in the specified logical library.
+   * specified logical library, in other words tapes that are labelled, not
+   * disabled, not full and are in the specified logical library.
    *
    * @param logicalLibraryName The name of the logical library.
    */
diff --git a/catalogue/CatalogueTest.cpp b/catalogue/CatalogueTest.cpp
index 2786a72703..a19739edc4 100644
--- a/catalogue/CatalogueTest.cpp
+++ b/catalogue/CatalogueTest.cpp
@@ -1786,6 +1786,7 @@ TEST_P(cta_catalogue_CatalogueTest, createTape) {
   ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
   ASSERT_TRUE(disabledValue == tape.disabled);
   ASSERT_TRUE(fullValue == tape.full);
+      ASSERT_FALSE(tape.lbp);
   ASSERT_EQ(comment, tape.comment);
   ASSERT_FALSE(tape.labelLog);
   ASSERT_FALSE(tape.lastReadLog);
@@ -1833,6 +1834,7 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_no_encryption_key) {
   ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
   ASSERT_TRUE(disabledValue == tape.disabled);
   ASSERT_TRUE(fullValue == tape.full);
+      ASSERT_FALSE(tape.lbp);
   ASSERT_EQ(comment, tape.comment);
   ASSERT_FALSE(tape.labelLog);
   ASSERT_FALSE(tape.lastReadLog);
@@ -1880,6 +1882,7 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_16_exabytes_capacity) {
   ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
   ASSERT_TRUE(disabledValue == tape.disabled);
   ASSERT_TRUE(fullValue == tape.full);
+  ASSERT_FALSE(tape.lbp);
   ASSERT_EQ(comment, tape.comment);
   ASSERT_FALSE(tape.labelLog);
   ASSERT_FALSE(tape.lastReadLog);
@@ -2142,6 +2145,7 @@ TEST_P(cta_catalogue_CatalogueTest, deleteTape) {
   ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
   ASSERT_TRUE(disabledValue == tape.disabled);
   ASSERT_TRUE(fullValue == tape.full);
+  ASSERT_FALSE(tape.lbp);
   ASSERT_EQ(comment, tape.comment);
   ASSERT_FALSE(tape.labelLog);
   ASSERT_FALSE(tape.lastReadLog);
@@ -2201,6 +2205,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLogicalLibraryName) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2229,6 +2234,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLogicalLibraryName) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2289,6 +2295,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeTapePoolName) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2317,6 +2324,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeTapePoolName) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2377,6 +2385,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeCapacityInBytes) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2406,6 +2415,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeCapacityInBytes) {
     ASSERT_EQ(modifiedCapacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2462,6 +2472,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeEncryptionKey) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2491,6 +2502,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeEncryptionKey) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2547,6 +2559,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLabelLog) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2576,6 +2589,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLabelLog) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_TRUE((bool)tape.labelLog);
     ASSERT_EQ(modifiedDrive, tape.labelLog.value().drive);
@@ -2633,6 +2647,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLastWrittenLog) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2662,6 +2677,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLastWrittenLog) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2719,6 +2735,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLastReadLog) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2748,6 +2765,7 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLastReadLog) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_TRUE((bool)tape.lastReadLog);
@@ -2805,6 +2823,7 @@ TEST_P(cta_catalogue_CatalogueTest, setTapeFull) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2888,6 +2907,7 @@ TEST_P(cta_catalogue_CatalogueTest, setTapeDisabled) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2971,7 +2991,7 @@ TEST_P(cta_catalogue_CatalogueTest, setTapeLbp) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
-    ASSERT_TRUE(tape.lbp);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -2985,7 +3005,7 @@ TEST_P(cta_catalogue_CatalogueTest, setTapeLbp) {
     ASSERT_EQ(creationLog, lastModificationLog);
   }
 
-  m_catalogue->setTapeLbp(vid, false);
+  m_catalogue->setTapeLbp(vid, true);
 
   {
     const std::list<common::dataStructures::Tape> tapes = m_catalogue->getTapes();
@@ -3000,7 +3020,8 @@ TEST_P(cta_catalogue_CatalogueTest, setTapeLbp) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_FALSE(tape.disabled);
     ASSERT_FALSE(tape.full);
-    ASSERT_FALSE(tape.lbp);
+    ASSERT_TRUE((bool)tape.lbp);
+    ASSERT_TRUE(tape.lbp.value());
     ASSERT_EQ(comment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -3036,12 +3057,10 @@ TEST_P(cta_catalogue_CatalogueTest, getTapesForWriting) {
   const bool fullValue = false;
   const std::string comment = "Create tape";
 
-  m_catalogue->createLogicalLibrary(m_cliSI, logicalLibraryName,
-    "Create logical library");
+  m_catalogue->createLogicalLibrary(m_cliSI, logicalLibraryName, "Create logical library");
   m_catalogue->createTapePool(m_cliSI, tapePoolName, 2, true, "Create tape pool");
-  m_catalogue->createTape(m_cliSI, vid, logicalLibraryName, tapePoolName,
-    encryptionKey, capacityInBytes, disabledValue, fullValue,
-    comment);
+  m_catalogue->createTape(m_cliSI, vid, logicalLibraryName, tapePoolName, encryptionKey, capacityInBytes, disabledValue,
+   fullValue, comment);
 
   const std::list<catalogue::TapeForWriting> tapes = m_catalogue->getTapesForWriting(logicalLibraryName);
 
@@ -3053,7 +3072,6 @@ TEST_P(cta_catalogue_CatalogueTest, getTapesForWriting) {
   ASSERT_EQ(0, tape.lastFSeq);
   ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
   ASSERT_EQ(0, tape.dataOnTapeInBytes);
-  ASSERT_TRUE(tape.lbp);
 }
 
 TEST_P(cta_catalogue_CatalogueTest, createMountPolicy) {
@@ -3828,6 +3846,7 @@ TEST_P(cta_catalogue_CatalogueTest, prepareToRetrieveFile) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(createTapeComment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -3851,6 +3870,7 @@ TEST_P(cta_catalogue_CatalogueTest, prepareToRetrieveFile) {
     ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
     ASSERT_TRUE(disabledValue == tape.disabled);
     ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
     ASSERT_EQ(createTapeComment, tape.comment);
     ASSERT_FALSE(tape.labelLog);
     ASSERT_FALSE(tape.lastReadLog);
@@ -4079,6 +4099,7 @@ TEST_P(cta_catalogue_CatalogueTest, fileWrittenToTape_many_archive_files) {
       ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
       ASSERT_TRUE(disabledValue == tape.disabled);
       ASSERT_TRUE(fullValue == tape.full);
+    ASSERT_FALSE(tape.lbp);
       ASSERT_EQ(comment, tape.comment);
       ASSERT_FALSE(tape.labelLog);
       ASSERT_FALSE(tape.lastReadLog);
@@ -4362,6 +4383,7 @@ TEST_P(cta_catalogue_CatalogueTest, fileWrittenToTape_2_tape_files_different_tap
       ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
       ASSERT_TRUE(disabledValue == tape.disabled);
       ASSERT_TRUE(fullValue == tape.full);
+      ASSERT_FALSE(tape.lbp);
       ASSERT_EQ(comment, tape.comment);
       ASSERT_FALSE(tape.labelLog);
       ASSERT_FALSE(tape.lastReadLog);
@@ -4385,6 +4407,7 @@ TEST_P(cta_catalogue_CatalogueTest, fileWrittenToTape_2_tape_files_different_tap
       ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
       ASSERT_TRUE(disabledValue == tape.disabled);
       ASSERT_TRUE(fullValue == tape.full);
+      ASSERT_FALSE(tape.lbp);
       ASSERT_EQ(comment, tape.comment);
       ASSERT_FALSE(tape.labelLog);
       ASSERT_FALSE(tape.lastReadLog);
@@ -4582,6 +4605,7 @@ TEST_P(cta_catalogue_CatalogueTest, fileWrittenToTape_2_tape_files_same_archive_
       ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
       ASSERT_TRUE(disabledValue == tape.disabled);
       ASSERT_TRUE(fullValue == tape.full);
+      ASSERT_FALSE(tape.lbp);
       ASSERT_EQ(comment, tape.comment);
       ASSERT_FALSE(tape.labelLog);
       ASSERT_FALSE(tape.lastReadLog);
@@ -4725,6 +4749,7 @@ TEST_P(cta_catalogue_CatalogueTest, fileWrittenToTape_2_tape_files_corrupted_dis
   ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
   ASSERT_TRUE(disabledValue == tape.disabled);
   ASSERT_TRUE(fullValue == tape.full);
+  ASSERT_FALSE(tape.lbp);
   ASSERT_EQ(comment, tape.comment);
   ASSERT_FALSE(tape.labelLog);
   ASSERT_FALSE(tape.lastReadLog);
@@ -4865,6 +4890,7 @@ TEST_P(cta_catalogue_CatalogueTest, deleteArchiveFile) {
       ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
       ASSERT_TRUE(disabledValue == tape.disabled);
       ASSERT_TRUE(fullValue == tape.full);
+      ASSERT_FALSE(tape.lbp);
       ASSERT_EQ(comment, tape.comment);
       ASSERT_FALSE(tape.labelLog);
       ASSERT_FALSE(tape.lastReadLog);
@@ -4888,6 +4914,7 @@ TEST_P(cta_catalogue_CatalogueTest, deleteArchiveFile) {
       ASSERT_EQ(capacityInBytes, tape.capacityInBytes);
       ASSERT_TRUE(disabledValue == tape.disabled);
       ASSERT_TRUE(fullValue == tape.full);
+      ASSERT_FALSE(tape.lbp);
       ASSERT_EQ(comment, tape.comment);
       ASSERT_FALSE(tape.labelLog);
       ASSERT_FALSE(tape.lastReadLog);
diff --git a/catalogue/OracleCatalogue.cpp b/catalogue/OracleCatalogue.cpp
index 33c6ba530c..1a977a2e82 100644
--- a/catalogue/OracleCatalogue.cpp
+++ b/catalogue/OracleCatalogue.cpp
@@ -230,9 +230,9 @@ common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(rdbms::Conn &c
     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");
-    tape.full = rset->columnUint64("IS_FULL");
-    tape.lbp = rset->columnUint64("LBP_IS_ON");
+    tape.disabled = rset->columnBool("IS_DISABLED");
+    tape.full = rset->columnBool("IS_FULL");
+    tape.lbp = rset->columnOptionalBool("LBP_IS_ON");
 
     tape.labelLog = getTapeLogFromRset(*rset, "LABEL_DRIVE", "LABEL_TIME");
     tape.lastReadLog = getTapeLogFromRset(*rset, "LAST_READ_DRIVE", "LAST_READ_TIME");
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index ed15c3f221..99b228a95b 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -724,7 +724,7 @@ void RdbmsCatalogue::createTapePool(
 
     stmt->bindString(":TAPE_POOL_NAME", name);
     stmt->bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes);
-    stmt->bindUint64(":IS_ENCRYPTED", encryptionValue ? 1 : 0);
+    stmt->bindBool(":IS_ENCRYPTED", encryptionValue);
 
     stmt->bindString(":USER_COMMENT", comment);
 
@@ -817,7 +817,7 @@ std::list<common::dataStructures::TapePool> RdbmsCatalogue::getTapePools() const
 
       pool.name = rset->columnString("TAPE_POOL_NAME");
       pool.nbPartialTapes = rset->columnUint64("NB_PARTIAL_TAPES");
-      pool.encryption = rset->columnUint64("IS_ENCRYPTED");
+      pool.encryption = rset->columnBool("IS_ENCRYPTED");
       pool.comment = rset->columnString("USER_COMMENT");
       pool.creationLog.username = rset->columnString("CREATION_LOG_USER_NAME");
       pool.creationLog.host = rset->columnString("CREATION_LOG_HOST_NAME");
@@ -919,7 +919,7 @@ void RdbmsCatalogue::setTapePoolEncryption(const common::dataStructures::Securit
         "TAPE_POOL_NAME = :TAPE_POOL_NAME";
     auto conn = m_connPool.getConn();
     auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":IS_ENCRYPTED", encryptionValue ? 1 : 0);
+    stmt->bindBool(":IS_ENCRYPTED", encryptionValue);
     stmt->bindString(":LAST_UPDATE_USER_NAME", cliIdentity.username);
     stmt->bindString(":LAST_UPDATE_HOST_NAME", cliIdentity.host);
     stmt->bindUint64(":LAST_UPDATE_TIME", now);
@@ -1390,7 +1390,6 @@ void RdbmsCatalogue::createTape(
         "LAST_FSEQ,"
         "IS_DISABLED,"
         "IS_FULL,"
-        "LBP_IS_ON,"
 
         "USER_COMMENT,"
 
@@ -1411,7 +1410,6 @@ void RdbmsCatalogue::createTape(
         ":LAST_FSEQ,"
         ":IS_DISABLED,"
         ":IS_FULL,"
-        ":LBP_IS_ON,"
 
         ":USER_COMMENT,"
 
@@ -1431,9 +1429,8 @@ void RdbmsCatalogue::createTape(
     stmt->bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
     stmt->bindUint64(":DATA_IN_BYTES", 0);
     stmt->bindUint64(":LAST_FSEQ", 0);
-    stmt->bindUint64(":IS_DISABLED", disabled ? 1 : 0);
-    stmt->bindUint64(":IS_FULL", full ? 1 : 0);
-    stmt->bindUint64(":LBP_IS_ON", 1);
+    stmt->bindBool(":IS_DISABLED", disabled);
+    stmt->bindBool(":IS_FULL", full);
 
     stmt->bindString(":USER_COMMENT", comment);
 
@@ -1588,9 +1585,9 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(const TapeSearc
     if(searchCriteria.logicalLibrary) stmt->bindString(":LOGICAL_LIBRARY_NAME", searchCriteria.logicalLibrary.value());
     if(searchCriteria.tapePool) stmt->bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value());
     if(searchCriteria.capacityInBytes) stmt->bindUint64(":CAPACITY_IN_BYTES", searchCriteria.capacityInBytes.value());
-    if(searchCriteria.disabled) stmt->bindUint64(":IS_DISABLED", searchCriteria.disabled.value() ? 1 : 0);
-    if(searchCriteria.full) stmt->bindUint64(":IS_FULL", searchCriteria.full.value() ? 1 : 0);
-    if(searchCriteria.lbp) stmt->bindUint64(":LBP_IS_ON", searchCriteria.lbp.value() ? 1 : 0);
+    if(searchCriteria.disabled) stmt->bindBool(":IS_DISABLED", searchCriteria.disabled.value());
+    if(searchCriteria.full) stmt->bindBool(":IS_FULL", searchCriteria.full.value());
+    if(searchCriteria.lbp) stmt->bindBool(":LBP_IS_ON", searchCriteria.lbp.value());
 
     auto rset = stmt->executeQuery();
     while (rset->next()) {
@@ -1603,9 +1600,9 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(const TapeSearc
       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");
-      tape.full = rset->columnUint64("IS_FULL");
-      tape.lbp = rset->columnUint64("LBP_IS_ON");
+      tape.disabled = rset->columnBool("IS_DISABLED");
+      tape.full = rset->columnBool("IS_FULL");
+      tape.lbp = rset->columnOptionalBool("LBP_IS_ON");
 
       tape.labelLog = getTapeLogFromRset(*rset, "LABEL_DRIVE", "LABEL_TIME");
       tape.lastReadLog = getTapeLogFromRset(*rset, "LAST_READ_DRIVE", "LAST_READ_TIME");
@@ -1703,9 +1700,9 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getTapesByVid(const std::se
       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");
-      tape.full = rset->columnUint64("IS_FULL");
-      tape.lbp = rset->columnUint64("LBP_IS_ON");
+      tape.disabled = rset->columnBool("IS_DISABLED");
+      tape.full = rset->columnBool("IS_FULL");
+      tape.lbp = rset->columnOptionalBool("LBP_IS_ON");
 
       tape.labelLog = getTapeLogFromRset(*rset, "LABEL_DRIVE", "LABEL_TIME");
       tape.lastReadLog = getTapeLogFromRset(*rset, "LAST_READ_DRIVE", "LAST_READ_TIME");
@@ -2012,7 +2009,7 @@ void RdbmsCatalogue::setTapeFull(const common::dataStructures::SecurityIdentity
         "VID = :VID";
     auto conn = m_connPool.getConn();
     auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":IS_FULL", fullValue ? 1 : 0);
+    stmt->bindBool(":IS_FULL", fullValue);
     stmt->bindString(":LAST_UPDATE_USER_NAME", cliIdentity.username);
     stmt->bindString(":LAST_UPDATE_HOST_NAME", cliIdentity.host);
     stmt->bindUint64(":LAST_UPDATE_TIME", now);
@@ -2046,7 +2043,7 @@ void RdbmsCatalogue::setTapeDisabled(const common::dataStructures::SecurityIdent
         "VID = :VID";
     auto conn = m_connPool.getConn();
     auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":IS_DISABLED", disabledValue ? 1 : 0);
+    stmt->bindBool(":IS_DISABLED", disabledValue);
     stmt->bindString(":LAST_UPDATE_USER_NAME", cliIdentity.username);
     stmt->bindString(":LAST_UPDATE_HOST_NAME", cliIdentity.host);
     stmt->bindUint64(":LAST_UPDATE_TIME", now);
@@ -2075,7 +2072,7 @@ void RdbmsCatalogue::setTapeLbp(const std::string &vid, const bool lbpValue) {
         "VID = :VID";
     auto conn = m_connPool.getConn();
     auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
-    stmt->bindUint64(":LBP_IS_ON", lbpValue ? 1 : 0);
+    stmt->bindBool(":LBP_IS_ON", lbpValue);
     stmt->bindString(":VID", vid);
     stmt->executeNonQuery();
 
@@ -2092,8 +2089,35 @@ void RdbmsCatalogue::setTapeLbp(const std::string &vid, const bool lbpValue) {
 //------------------------------------------------------------------------------
 // modifyTapeComment
 //------------------------------------------------------------------------------
-void RdbmsCatalogue::modifyTapeComment(const common::dataStructures::SecurityIdentity &cliIdentity, const std::string &vid, const std::string &comment) {
-  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
+void RdbmsCatalogue::modifyTapeComment(const common::dataStructures::SecurityIdentity &cliIdentity,
+  const std::string &vid, const std::string &comment) {
+  try {
+    const time_t now = time(nullptr);
+    const char *const sql =
+      "UPDATE TAPE SET "
+        "USER_COMMENT = :USER_COMMENT,"
+        "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
+        "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
+        "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
+      "WHERE "
+        "VID = :VID";
+    auto conn = m_connPool.getConn();
+    auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::ON);
+    stmt->bindString(":USER_COMMENT", comment);
+    stmt->bindString(":LAST_UPDATE_USER_NAME", cliIdentity.username);
+    stmt->bindString(":LAST_UPDATE_HOST_NAME", cliIdentity.host);
+    stmt->bindUint64(":LAST_UPDATE_TIME", now);
+    stmt->bindString(":VID", vid);
+    stmt->executeNonQuery();
+
+    if(0 == stmt->getNbAffectedRows()) {
+      throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist");
+    }
+  } catch(exception::UserError &) {
+    throw;
+  } catch (exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
 }
 
 //------------------------------------------------------------------------------
@@ -3749,11 +3773,13 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string &
         "TAPE_POOL_NAME AS TAPE_POOL_NAME,"
         "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES,"
         "DATA_IN_BYTES AS DATA_IN_BYTES,"
-        "LAST_FSEQ AS LAST_FSEQ,"
-        "LBP_IS_ON AS LBP_IS_ON "
+        "LAST_FSEQ AS LAST_FSEQ "
       "FROM "
         "TAPE "
       "WHERE "
+        "LBP_IS_ON IS NOT NULL AND "
+        "LABEL_DRIVE IS NOT NULL AND "
+        "LABEL_TIME IS NOT NULL AND "
         "IS_DISABLED = 0 AND "
         "IS_FULL = 0 AND "
         "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME";
@@ -3763,13 +3789,11 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string &
     auto rset = stmt->executeQuery();
     while (rset->next()) {
       TapeForWriting tape;
-
       tape.vid = rset->columnString("VID");
       tape.tapePool = rset->columnString("TAPE_POOL_NAME");
       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");
 
       tapes.push_back(tape);
     }
diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp
index 58aa626b0f..d3aace775f 100644
--- a/catalogue/RdbmsCatalogue.hpp
+++ b/catalogue/RdbmsCatalogue.hpp
@@ -145,8 +145,7 @@ public:
   virtual void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &cliIdentity, const std::string &name, const std::string &comment) override;
 
   /**
-   * Creates a tape which is assumed to have logical block protection (LBP)
-   * enabled.
+   * Creates a tape.
    *
    * @param encryptionKey The optional identifier of the encrption key.  This
    * optional parameter should either have a non-empty string value or no value
@@ -429,8 +428,8 @@ public:
 
   /**
    * Returns the list of tapes that can be written to by a tape drive in the
-   * specified logical library, in other words tapes that are not disabled, not
-   * full and are in the specified logical library.
+   * specified logical library, in other words tapes that are labelled, not
+   * disabled, not full and are in the specified logical library.
    *
    * @param logicalLibraryName The name of the logical library.
    */
diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp
index 1b5c87efbe..3caeb3924c 100644
--- a/catalogue/SqliteCatalogue.cpp
+++ b/catalogue/SqliteCatalogue.cpp
@@ -238,9 +238,9 @@ common::dataStructures::Tape SqliteCatalogue::selectTapeForUpdate(rdbms::Conn &c
     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");
-    tape.full = rset->columnUint64("IS_FULL");
-    tape.lbp = rset->columnUint64("LBP_IS_ON");
+    tape.disabled = rset->columnBool("IS_DISABLED");
+    tape.full = rset->columnBool("IS_FULL");
+    tape.lbp = rset->columnOptionalBool("LBP_IS_ON");
 
     tape.labelLog = getTapeLogFromRset(*rset, "LABEL_DRIVE", "LABEL_TIME");
     tape.lastReadLog = getTapeLogFromRset(*rset, "LAST_READ_DRIVE", "LAST_READ_TIME");
diff --git a/catalogue/TapeForWriting.cpp b/catalogue/TapeForWriting.cpp
index 1aed466113..7874afd2f6 100644
--- a/catalogue/TapeForWriting.cpp
+++ b/catalogue/TapeForWriting.cpp
@@ -27,8 +27,7 @@ namespace catalogue {
 TapeForWriting::TapeForWriting():
   lastFSeq(0),
   capacityInBytes(0),
-  dataOnTapeInBytes(0),
-  lbp(false) {
+  dataOnTapeInBytes(0) {
 }
 
 //------------------------------------------------------------------------------
@@ -44,11 +43,10 @@ bool TapeForWriting::operator==(const TapeForWriting &rhs) const {
 std::ostream &operator<<(std::ostream &os, const TapeForWriting &obj) {
   os <<
     "{"                  <<
-    "vid="               << obj.vid                      << "," <<
-    "lastFseq="          << obj.lastFSeq                 << "," <<
-    "capacityInBytes="   << obj.capacityInBytes          << "," <<
-    "dataOnTapeInBytes=" << obj.dataOnTapeInBytes        << "," <<
-    "lbp="               << (obj.lbp ? "true" : "false") <<
+    "vid="               << obj.vid << "," <<
+    "lastFseq="          << obj.lastFSeq << "," <<
+    "capacityInBytes="   << obj.capacityInBytes << "," <<
+    "dataOnTapeInBytes=" << obj.dataOnTapeInBytes <<
     "}";
 
   return os;
diff --git a/catalogue/TapeForWriting.hpp b/catalogue/TapeForWriting.hpp
index 8d9626919a..4b1e99136d 100644
--- a/catalogue/TapeForWriting.hpp
+++ b/catalogue/TapeForWriting.hpp
@@ -18,6 +18,8 @@
 
 #pragma once
 
+#include "common/optional.hpp"
+
 #include <ostream>
 #include <stdint.h>
 #include <string>
@@ -74,11 +76,6 @@ struct TapeForWriting {
    */
   uint64_t dataOnTapeInBytes;
 
-  /**
-   * True if the tape uses logical block protection.
-   */
-  bool lbp;
-
 }; // struct TapeForWriting
 
 /**
diff --git a/catalogue/catalogue_common_schema.sql b/catalogue/catalogue_common_schema.sql
index 3117962a08..4e1fefbb0e 100644
--- a/catalogue/catalogue_common_schema.sql
+++ b/catalogue/catalogue_common_schema.sql
@@ -86,7 +86,7 @@ CREATE TABLE TAPE(
   LAST_FSEQ               INTEGER        NOT NULL,
   IS_DISABLED             INTEGER        NOT NULL,
   IS_FULL                 INTEGER        NOT NULL,
-  LBP_IS_ON               INTEGER        NOT NULL,
+  LBP_IS_ON               INTEGER,
   LABEL_DRIVE             VARCHAR2(100),
   LABEL_TIME              INTEGER,
   LAST_READ_DRIVE         VARCHAR2(100),
diff --git a/catalogue/catalogue_schema.pdf b/catalogue/catalogue_schema.pdf
index 19bfcd4556bb0e7b930e007aeaafe46f6882c808..3c3f3032aa19cf04b9c6b168bb899167b956f6f1 100644
GIT binary patch
delta 4451
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
L=iyP-QX&5rMXFL9

delta 4477
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%0A_Fh{RK&yEMZx44J}nm`%s7;=W3;O
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

diff --git a/common/dataStructures/Tape.cpp b/common/dataStructures/Tape.cpp
index 97b66ebc3a..dcaaed5b9d 100644
--- a/common/dataStructures/Tape.cpp
+++ b/common/dataStructures/Tape.cpp
@@ -71,8 +71,8 @@ std::ostream &operator<<(std::ostream &os, const Tape &obj) {
      << " tapePoolName=" << obj.tapePoolName
      << " capacityInBytes=" << obj.capacityInBytes
      << " dataOnTapeInBytes=" << obj.dataOnTapeInBytes
-     << " encryptionKey=" << ((bool)obj.encryptionKey ? obj.encryptionKey.value() : "null")
-     << " lbp=" << obj.lbp
+     << " encryptionKey=" << (obj.encryptionKey ? obj.encryptionKey.value() : "null")
+     << " lbp=" << (obj.lbp ? (obj.lbp.value() ? "true" : "false") : "null")
      << " full=" << obj.full
      << " disabled=" << obj.disabled
      << " creationLog=" << obj.creationLog
diff --git a/common/dataStructures/Tape.hpp b/common/dataStructures/Tape.hpp
index d844976320..d3e88b90c4 100644
--- a/common/dataStructures/Tape.hpp
+++ b/common/dataStructures/Tape.hpp
@@ -57,7 +57,13 @@ struct Tape {
    */
   optional<std::string> encryptionKey;
 
-  bool lbp;
+  /**
+   * Specifies whether or not the tape has Logical Block Protection (LBP)
+   * enabled.  This value is not set until the tape is either labelled or
+   * imported as a tape containing pre-existing files.
+   */
+  optional<bool> lbp;
+
   bool full;
   bool disabled;
   EntryLog creationLog;
diff --git a/rdbms/OcciRset.hpp b/rdbms/OcciRset.hpp
index be4a488d1a..e5b4d59c7a 100644
--- a/rdbms/OcciRset.hpp
+++ b/rdbms/OcciRset.hpp
@@ -82,7 +82,7 @@ public:
   /**
    * Returns the value of the specified column as a string.
    *
-   * This method will return a nullptr column value as an optional with no value.
+   * This method will return a null column value as an optional with no value.
    *
    * @param colName The name of the column.
    * @return The string value of the specified column.
@@ -92,7 +92,7 @@ public:
   /**
    * Returns the value of the specified column as an integer.
    *
-   * This method will return a nullptr column value as an optional with no value.
+   * This method will return a null column value as an optional with no value.
    *
    * @param colName The name of the column.
    * @return The value of the specified column.
diff --git a/rdbms/Rset.cpp b/rdbms/Rset.cpp
index 1f29b5caa8..3ff6de5099 100644
--- a/rdbms/Rset.cpp
+++ b/rdbms/Rset.cpp
@@ -60,5 +60,37 @@ uint64_t Rset::columnUint64(const std::string &colName) const {
   }
 }
 
+//------------------------------------------------------------------------------
+// columnBool
+//------------------------------------------------------------------------------
+bool Rset::columnBool(const std::string &colName) const {
+  try {
+    const optional<bool> col = columnOptionalBool(colName);
+    if(col) {
+      return col.value();
+    } else {
+      throw NullDbValue(std::string("Database column ") + colName + " contains a nullptr value");
+    }
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
+}
+
+//------------------------------------------------------------------------------
+// columnOptionalBool
+//------------------------------------------------------------------------------
+optional<bool> Rset::columnOptionalBool(const std::string &colName) const {
+  try {
+    const auto column = columnOptionalUint64(colName);
+    if(column) {
+      return optional<bool>(column.value() != 0 ? true : false);
+    } else {
+      return nullopt;
+    }
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
+}
+
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/Rset.hpp b/rdbms/Rset.hpp
index 40c3d7573c..5aa3adfd25 100644
--- a/rdbms/Rset.hpp
+++ b/rdbms/Rset.hpp
@@ -74,7 +74,7 @@ public:
   /**
    * Returns the value of the specified column as a string.
    *
-   * This method will return a nullptr column value as an optional with no value.
+   * This method will return a null column value as an optional with no value.
    *
    * @param colName The name of the column.
    * @return The string value of the specified column.
@@ -92,16 +92,43 @@ public:
    */
   uint64_t columnUint64(const std::string &colName) const;
 
+  /**
+   * Returns the value of the specified column as a boolean.
+   *
+   * Please note that the underlying database column type is expected to be a
+   * number where a non-zero value means true and a value of zero means false.
+   *
+   * This method will throw an exception if the value of the specified column
+   * is nullptr.
+   *
+   * @param colName The name of the column.
+   * @return The value of the specified column.
+   */
+  bool columnBool(const std::string &colName) const;
+
   /**
    * Returns the value of the specified column as an integer.
    *
-   * This method will return a nullptr column value as an optional with no value.
+   * This method will return a null column value as an optional with no value.
    *
    * @param colName The name of the column.
    * @return The value of the specified column.
    */
   virtual optional<uint64_t> columnOptionalUint64(const std::string &colName) const = 0;
 
+  /**
+   * Returns the value of the specified column as a boolean.
+   *
+   * Please note that the underlying database column type is expected to be a
+   * number where a non-zero value means true and a value of zero means false.
+   *
+   * This method will return a null column value as an optional with no value.
+   *
+   * @param colName The name of the column.
+   * @return The value of the specified column.
+   */
+  virtual optional<bool> columnOptionalBool(const std::string &colName) const;
+
 }; // class Rset
 
 } // namespace rdbms
diff --git a/rdbms/SqliteRset.hpp b/rdbms/SqliteRset.hpp
index 7fb68efaed..6065d7285b 100644
--- a/rdbms/SqliteRset.hpp
+++ b/rdbms/SqliteRset.hpp
@@ -77,7 +77,7 @@ public:
   /**
    * Returns the value of the specified column as a string.
    *
-   * This method will return a nullptr column value as an optional with no value.
+   * This method will return a null column value as an optional with no value.
    *
    * @param colName The name of the column.
    * @return The string value of the specified column.
@@ -87,7 +87,7 @@ public:
   /**
    * Returns the value of the specified column as an integer.
    *
-   * This method will return a nullptr column value as an optional with no value.
+   * This method will return a null column value as an optional with no value.
    *
    * @param colName The name of the column.
    * @return The value of the specified column.
diff --git a/rdbms/Stmt.cpp b/rdbms/Stmt.cpp
index e345eba700..8d275f167e 100644
--- a/rdbms/Stmt.cpp
+++ b/rdbms/Stmt.cpp
@@ -33,5 +33,23 @@ Stmt::Stmt(const AutocommitMode autocommitMode): m_autoCommitMode(autocommitMode
 Stmt::~Stmt() throw() {
 }
 
+//------------------------------------------------------------------------------
+// bindBool
+//------------------------------------------------------------------------------
+void Stmt::bindBool(const std::string &paramName, const bool paramValue) {
+  bindOptionalBool(paramName, paramValue);
+}
+
+//------------------------------------------------------------------------------
+// bindOptionalBool
+//------------------------------------------------------------------------------
+void Stmt::bindOptionalBool(const std::string &paramName, const optional<bool> &paramValue) {
+  if(paramValue) {
+    bindOptionalUint64(paramName, paramValue.value() ? 1 : 0);
+  } else {
+    bindOptionalUint64(paramName, nullopt);
+  }
+}
+
 } // namespace rdbms
 } // namespace cta
diff --git a/rdbms/Stmt.hpp b/rdbms/Stmt.hpp
index ca18f722d3..8796d7221c 100644
--- a/rdbms/Stmt.hpp
+++ b/rdbms/Stmt.hpp
@@ -109,6 +109,22 @@ public:
    */
   virtual void bindOptionalUint64(const std::string &paramName, const optional<uint64_t> &paramValue) = 0;
 
+  /**
+   * Binds an SQL parameter.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */
+  void bindBool(const std::string &paramName, const bool paramValue);
+
+  /**
+   * Binds an SQL parameter.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */
+  void bindOptionalBool(const std::string &paramName, const optional<bool> &paramValue);
+
   /** 
    * Binds an SQL parameter of type string.
    *
-- 
GitLab