From e4b1895a2455da1c542f5f6ef230023dc723dcd5 Mon Sep 17 00:00:00 2001 From: Steven Murray <Steven.Murray@cern.ch> Date: Thu, 5 Dec 2019 12:04:36 +0100 Subject: [PATCH] Added Stmt::bindUint8() --- catalogue/CMakeLists.txt | 4 + rdbms/Rset.cpp | 15 +++ rdbms/Rset.hpp | 11 +++ rdbms/Stmt.cpp | 32 +++++++ rdbms/Stmt.hpp | 16 ++++ rdbms/StmtTest.cpp | 163 +++++++++++++++++++++++++++++++++ rdbms/wrapper/Mysql.hpp | 107 ++++++++++++++++++++++ rdbms/wrapper/MysqlRset.cpp | 19 ++++ rdbms/wrapper/MysqlRset.hpp | 10 ++ rdbms/wrapper/MysqlStmt.cpp | 49 ++++++++++ rdbms/wrapper/MysqlStmt.hpp | 16 ++++ rdbms/wrapper/OcciRset.cpp | 26 ++++++ rdbms/wrapper/OcciRset.hpp | 10 ++ rdbms/wrapper/OcciStmt.cpp | 24 +++++ rdbms/wrapper/OcciStmt.hpp | 16 ++++ rdbms/wrapper/PostgresRset.cpp | 29 ++++++ rdbms/wrapper/PostgresRset.hpp | 10 ++ rdbms/wrapper/PostgresStmt.cpp | 25 +++++ rdbms/wrapper/PostgresStmt.hpp | 16 ++++ rdbms/wrapper/RsetWrapper.hpp | 10 ++ rdbms/wrapper/SqliteRset.cpp | 16 ++++ rdbms/wrapper/SqliteRset.hpp | 10 ++ rdbms/wrapper/SqliteStmt.cpp | 33 +++++++ rdbms/wrapper/SqliteStmt.hpp | 16 ++++ rdbms/wrapper/StmtWrapper.hpp | 16 ++++ 25 files changed, 699 insertions(+) diff --git a/catalogue/CMakeLists.txt b/catalogue/CMakeLists.txt index 4b77cb7163..e053625f0f 100644 --- a/catalogue/CMakeLists.txt +++ b/catalogue/CMakeLists.txt @@ -101,6 +101,7 @@ add_custom_command (OUTPUT sqlite_catalogue_schema.sql mysql_catalogue_schema.sq ${CMAKE_CURRENT_SOURCE_DIR}/sqlite_catalogue_schema_header.sql ${CMAKE_CURRENT_SOURCE_DIR}/common_catalogue_schema.sql ${CMAKE_CURRENT_SOURCE_DIR}/sqlite_catalogue_schema_trailer.sql + | sed 's/UINT8TYPE/INTEGER/g' | sed 's/UINT16TYPE/INTEGER/g' | sed 's/UINT32TYPE/INTEGER/g' | sed 's/UINT64TYPE/INTEGER/g' @@ -111,6 +112,7 @@ add_custom_command (OUTPUT sqlite_catalogue_schema.sql mysql_catalogue_schema.sq ${CMAKE_CURRENT_SOURCE_DIR}/mysql_catalogue_schema_header.sql ${CMAKE_CURRENT_SOURCE_DIR}/common_catalogue_schema.sql ${CMAKE_CURRENT_SOURCE_DIR}/mysql_catalogue_schema_trailer.sql + | sed 's/UINT8TYPE/TINYINT UNSIGNED/g' | sed 's/UINT16TYPE/SMALLINT UNSIGNED/g' | sed 's/UINT32TYPE/INT UNSIGNED/g' | sed 's/UINT64TYPE/BIGINT UNSIGNED/g' @@ -121,6 +123,7 @@ add_custom_command (OUTPUT sqlite_catalogue_schema.sql mysql_catalogue_schema.sq ${CMAKE_CURRENT_SOURCE_DIR}/oracle_catalogue_schema_header.sql ${CMAKE_CURRENT_SOURCE_DIR}/common_catalogue_schema.sql ${CMAKE_CURRENT_SOURCE_DIR}/oracle_catalogue_schema_trailer.sql + | sed 's/UINT8TYPE/NUMERIC\(3, 0\)/g' | sed 's/UINT16TYPE/NUMERIC\(5, 0\)/g' | sed 's/UINT32TYPE/NUMERIC\(10, 0\)/g' | sed 's/UINT64TYPE/NUMERIC\(20, 0\)/g' @@ -131,6 +134,7 @@ add_custom_command (OUTPUT sqlite_catalogue_schema.sql mysql_catalogue_schema.sq ${CMAKE_CURRENT_SOURCE_DIR}/postgres_catalogue_schema_header.sql ${CMAKE_CURRENT_SOURCE_DIR}/common_catalogue_schema.sql ${CMAKE_CURRENT_SOURCE_DIR}/postgres_catalogue_schema_trailer.sql + | sed 's/UINT8TYPE/NUMERIC\(3, 0\)/g' | sed 's/UINT16TYPE/NUMERIC\(5, 0\)/g' | sed 's/UINT32TYPE/NUMERIC\(10, 0\)/g' | sed 's/UINT64TYPE/NUMERIC\(20, 0\)/g' diff --git a/rdbms/Rset.cpp b/rdbms/Rset.cpp index 1e62622372..b90497df13 100644 --- a/rdbms/Rset.cpp +++ b/rdbms/Rset.cpp @@ -254,6 +254,21 @@ optional<std::string> Rset::columnOptionalString(const std::string &colName) con } } +//------------------------------------------------------------------------------ +// columnOptionalUint8 +//------------------------------------------------------------------------------ +optional<uint8_t> Rset::columnOptionalUint8(const std::string &colName) const { + try { + if(nullptr == m_impl) { + throw InvalidResultSet("This result set is invalid"); + } + return m_impl->columnOptionalUint8(colName); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + //------------------------------------------------------------------------------ // columnOptionalUint16 //------------------------------------------------------------------------------ diff --git a/rdbms/Rset.hpp b/rdbms/Rset.hpp index 815db48183..dd70e53faf 100644 --- a/rdbms/Rset.hpp +++ b/rdbms/Rset.hpp @@ -180,6 +180,17 @@ public: */ bool columnBool(const std::string &colName) const; + /** + * Returns the value of the specified column as an integer. + * + * 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. + * @throw InvalidResultSet if the result is invalid. + */ + optional<uint8_t> columnOptionalUint8(const std::string &colName) const; + /** * Returns the value of the specified column as an integer. * diff --git a/rdbms/Stmt.cpp b/rdbms/Stmt.cpp index 1e576bcf78..cd949b6993 100644 --- a/rdbms/Stmt.cpp +++ b/rdbms/Stmt.cpp @@ -116,6 +116,38 @@ uint32_t Stmt::getParamIdx(const std::string ¶mName) const { } } +//----------------------------------------------------------------------------- +// bindUint8 +//----------------------------------------------------------------------------- +void Stmt::bindUint8(const std::string ¶mName, const uint8_t paramValue) { + try { + if(nullptr != m_stmt) { + return m_stmt->bindUint8(paramName, paramValue); + } else { + throw exception::Exception("Stmt does not contain a cached statement"); + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + +//----------------------------------------------------------------------------- +// bindOptionalUint8 +//----------------------------------------------------------------------------- +void Stmt::bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) { + try { + if(nullptr != m_stmt) { + return m_stmt->bindOptionalUint8(paramName, paramValue); + } else { + throw exception::Exception("Stmt does not contain a cached statement"); + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + //----------------------------------------------------------------------------- // bindUint16 //----------------------------------------------------------------------------- diff --git a/rdbms/Stmt.hpp b/rdbms/Stmt.hpp index 8e0c1e2571..46ca376768 100644 --- a/rdbms/Stmt.hpp +++ b/rdbms/Stmt.hpp @@ -103,6 +103,22 @@ public: */ uint32_t getParamIdx(const std::string ¶mName) const; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindUint8(const std::string ¶mName, const uint8_t paramValue); + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue); + /** * Binds an SQL parameter. * diff --git a/rdbms/StmtTest.cpp b/rdbms/StmtTest.cpp index 8b4ec4775c..42a58c39ab 100644 --- a/rdbms/StmtTest.cpp +++ b/rdbms/StmtTest.cpp @@ -66,6 +66,7 @@ std::string cta_rdbms_StmtTest::getCreateStmtTestTableSql() { "CREATE TABLE STMT_TEST(" "\n" " ID UINT64TYPE CONSTRAINT STMT_TEST_ID_NN NOT NULL," "\n" " DOUBLE_COL FLOAT," "\n" + " UINT8_COL UINT8TYPE," "\n" " UINT16_COL UINT16TYPE," "\n" " UINT32_COL UINT32TYPE," "\n" " UINT64_COL UINT64TYPE," "\n" @@ -79,22 +80,26 @@ std::string cta_rdbms_StmtTest::getCreateStmtTestTableSql() { case Login::DBTYPE_IN_MEMORY: break; case Login::DBTYPE_ORACLE: + utils::searchAndReplace(sql, "UINT8TYPE", "NUMERIC(3, 0)"); utils::searchAndReplace(sql, "UINT16TYPE", "NUMERIC(5, 0)"); utils::searchAndReplace(sql, "UINT32TYPE", "NUMERIC(10, 0)"); utils::searchAndReplace(sql, "UINT64TYPE", "NUMERIC(20, 0)"); utils::searchAndReplace(sql, "VARCHAR", "VARCHAR2"); break; case Login::DBTYPE_SQLITE: + utils::searchAndReplace(sql, "UINT8TYPE", "INTEGER"); utils::searchAndReplace(sql, "UINT16TYPE", "INTEGER"); utils::searchAndReplace(sql, "UINT32TYPE", "INTEGER"); utils::searchAndReplace(sql, "UINT64TYPE", "INTEGER"); break; case Login::DBTYPE_MYSQL: + utils::searchAndReplace(sql, "UINT8TYPE", "TINYINT UNSIGNED"); utils::searchAndReplace(sql, "UINT16TYPE", "SMALLINT UNSIGNED"); utils::searchAndReplace(sql, "UINT32TYPE", "INT UNSIGNED"); utils::searchAndReplace(sql, "UINT64TYPE", "BIGINT UNSIGNED"); break; case Login::DBTYPE_POSTGRESQL: + utils::searchAndReplace(sql, "UINT8TYPE", "NUMERIC(3, 0)"); utils::searchAndReplace(sql, "UINT16TYPE", "NUMERIC(5, 0)"); utils::searchAndReplace(sql, "UINT32TYPE", "NUMERIC(10, 0)"); utils::searchAndReplace(sql, "UINT64TYPE", "NUMERIC(20, 0)"); @@ -173,6 +178,164 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindDouble) { } } +TEST_P(cta_rdbms_StmtTest, insert_with_bindUint8) { + using namespace cta::rdbms; + + const uint8_t insertValue = 123; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" "\n" + " ID," "\n" + " UINT8_COL) " "\n" + "VALUES(" "\n" + " 1," "\n" + " :UINT8_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindUint8(":UINT8_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT" "\n" + " UINT8_COL AS UINT8_COL" "\n" + "FROM" "\n" + " STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalUint8("UINT8_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindUint8_2_pow_8_minus_1) { + using namespace cta::rdbms; + + const uint8_t insertValue = 255U; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" "\n" + " ID," "\n" + " UINT8_COL)" "\n" + "VALUES(" "\n" + " 1," "\n" + " :UINT8_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindUint8(":UINT8_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT" "\n" + " UINT8_COL AS UINT8_COL" "\n" + "FROM" "\n" + " STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalUint8("UINT8_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindOptionalUint8_null) { + using namespace cta::rdbms; + + const cta::optional<uint8_t> insertValue; // Null value + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" "\n" + " ID," "\n" + " UINT8_COL) " "\n" + "VALUES(" "\n" + " 1," "\n" + " :UINT8_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindOptionalUint8(":UINT8_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT" "\n" + " UINT8_COL AS UINT8_COL" "\n" + "FROM" "\n" + " STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalUint8("UINT8_COL"); + + ASSERT_FALSE((bool)selectValue); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindOptionalUint8) { + using namespace cta::rdbms; + + const cta::optional<uint8_t> insertValue = 123; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" "\n" + " ID," "\n" + " UINT8_COL) " "\n" + "VALUES(" "\n" + " 1," "\n" + " :UINT8_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindOptionalUint8(":UINT8_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT" "\n" + " UINT8_COL AS UINT8_COL" "\n" + "FROM" "\n" + " STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalUint8("UINT8_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + TEST_P(cta_rdbms_StmtTest, insert_with_bindUint16) { using namespace cta::rdbms; diff --git a/rdbms/wrapper/Mysql.hpp b/rdbms/wrapper/Mysql.hpp index 01b4731a33..98d60d2a5b 100644 --- a/rdbms/wrapper/Mysql.hpp +++ b/rdbms/wrapper/Mysql.hpp @@ -98,6 +98,7 @@ class Mysql { } enum buffer_types { + placeholder_uint8, placeholder_uint16, placeholder_uint32, placeholder_uint64, @@ -115,6 +116,7 @@ class Mysql { virtual bool get_is_unsigned() = 0; virtual my_bool* get_error() { return &error; } // following is to access data + virtual uint8_t get_uint8() = 0; virtual uint16_t get_uint16() = 0; virtual uint32_t get_uint32() = 0; virtual uint64_t get_uint64() = 0; @@ -124,6 +126,66 @@ class Mysql { virtual bool reset() = 0; }; + struct Placeholder_Uint8: Placeholder { + uint8_t val; + + Placeholder_Uint8() + : Placeholder(), val(0) { + + } + + std::string show() override { + std::stringstream ss; + ss << "['" << idx << "' '" << is_null << "' '" << length << "' '" << val << "' '" << get_buffer_length() << "']"; + return ss.str(); + } + + buffer_types get_buffer_type() override { + return placeholder_uint8; + } + + void* get_buffer() override { + return &val; + } + + unsigned long get_buffer_length() override { + return sizeof(uint8_t); + } + + bool get_is_unsigned() override { + return true; + } + + uint8_t get_uint8() override { + return val; + } + + uint16_t get_uint16() override { + return val; + } + + uint32_t get_uint32() override { + return val; + } + + uint64_t get_uint64() override { + return val; + } + + std::string get_string() override { + return std::to_string(val); + } + + double get_double() override { + return val; + } + + bool reset() override { + return false; + } + + }; + struct Placeholder_Uint16: Placeholder { uint16_t val; @@ -154,6 +216,16 @@ class Mysql { return true; } + uint8_t get_uint8() override { + if(std::numeric_limits<uint8_t>::max() < val) { + std::ostringstream msg; + msg << "Cannot convert uint16 to uint8: Overflow: uint16=" << val << + " maxUint8=" << std::numeric_limits<uint8_t>::max(); + throw exception::Exception(msg.str()); + } + return val; + } + uint16_t get_uint16() override { return val; } @@ -210,6 +282,16 @@ class Mysql { return true; } + uint8_t get_uint8() override { + if(std::numeric_limits<uint8_t>::max() < val) { + std::ostringstream msg; + msg << "Cannot convert uint32 to uint8: Overflow: uint32=" << val << + " maxUint8=" << std::numeric_limits<uint8_t>::max(); + throw exception::Exception(msg.str()); + } + return val; + } + uint16_t get_uint16() override { if(std::numeric_limits<uint16_t>::max() < val) { std::ostringstream msg; @@ -272,6 +354,16 @@ class Mysql { return true; } + uint8_t get_uint8() override { + if(std::numeric_limits<uint8_t>::max() < val) { + std::ostringstream msg; + msg << "Cannot convert uint64 to uint8: Overflow: uint64=" << val << + " maxUint8=" << std::numeric_limits<uint8_t>::max(); + throw exception::Exception(msg.str()); + } + return val; + } + uint16_t get_uint16() override { if(std::numeric_limits<uint16_t>::max() < val) { std::ostringstream msg; @@ -349,6 +441,17 @@ class Mysql { return false; } + uint8_t get_uint8() override { + const uint64_t i = std::stoll(val); + if(std::numeric_limits<uint8_t>::max() > i) { + std::ostringstream msg; + msg << "Failed to convert string to uint8: Overflow: string=" << val << " maxUint8=" << + std::numeric_limits<uint8_t>::max(); + throw exception::Exception(msg.str()); + } + return i; + } + uint16_t get_uint16() override { const uint64_t i = std::stoll(val); if(std::numeric_limits<uint16_t>::max() > i) { @@ -425,6 +528,10 @@ class Mysql { return true; } + uint8_t get_uint8() override { + throw val; + } + uint16_t get_uint16() override { throw val; } diff --git a/rdbms/wrapper/MysqlRset.cpp b/rdbms/wrapper/MysqlRset.cpp index f2d94573e1..5792224cb2 100644 --- a/rdbms/wrapper/MysqlRset.cpp +++ b/rdbms/wrapper/MysqlRset.cpp @@ -119,6 +119,25 @@ optional<std::string> MysqlRset::columnOptionalString(const std::string &colName return optional<std::string>(holder->get_string()); } +//------------------------------------------------------------------------------ +// columnOptionalUint8 +//------------------------------------------------------------------------------ +optional<uint8_t> MysqlRset::columnOptionalUint8(const std::string &colName) const { + if (not m_fields.exists(colName)) { + throw exception::Exception(std::string(__FUNCTION__) + " column does not exist: " + colName); + return nullopt; + } + + Mysql::Placeholder* holder = m_stmt.columnHolder(colName); // m_holders[idx]; + + // the value can be null + if (holder->get_is_null() and *holder->get_is_null()) { + return nullopt; + } + + return optional<uint8_t>(holder->get_uint8()); +} + //------------------------------------------------------------------------------ // columnOptionalUint16 //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/MysqlRset.hpp b/rdbms/wrapper/MysqlRset.hpp index 4f520c30b7..97a2f0b069 100644 --- a/rdbms/wrapper/MysqlRset.hpp +++ b/rdbms/wrapper/MysqlRset.hpp @@ -94,6 +94,16 @@ public: */ optional<std::string> columnOptionalString(const std::string &colName) const override; + /** + * Returns the value of the specified column as an integer. + * + * 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. + */ + optional<uint8_t> columnOptionalUint8(const std::string &colName) const override; + /** * Returns the value of the specified column as an integer. * diff --git a/rdbms/wrapper/MysqlStmt.cpp b/rdbms/wrapper/MysqlStmt.cpp index bb76b13b61..3bb54a9619 100644 --- a/rdbms/wrapper/MysqlStmt.cpp +++ b/rdbms/wrapper/MysqlStmt.cpp @@ -170,6 +170,52 @@ MYSQL_STMT *MysqlStmt::get() const { return m_stmt; } +//------------------------------------------------------------------------------ +// bindUint8 +//------------------------------------------------------------------------------ +void MysqlStmt::bindUint8(const std::string ¶mName, const uint8_t paramValue) { + try { + bindOptionalUint8(paramName, paramValue); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// bindOptionalUint8 +//------------------------------------------------------------------------------ +void MysqlStmt::bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) { + try { + const unsigned int paramIdx = getParamIdx(paramName); // starts from 1. + const unsigned int idx = paramIdx - 1; + + Mysql::Placeholder_Uint8* holder = dynamic_cast<Mysql::Placeholder_Uint8*>(m_placeholder[idx]); + // if already exists, try to reuse + if (!holder and m_placeholder[idx]) { + throw exception::Exception(std::string(__FUNCTION__) + " can't cast from Placeholder to Placeholder_Uint16. " ); + } + + if (!holder) { + holder = new Mysql::Placeholder_Uint8(); + holder->idx = idx; + holder->length = sizeof(uint8_t); + } + + if (paramValue) { + holder->val = paramValue.value(); + } else { + holder->is_null = true; + } + // delete m_placeholder[idx]; // remove the previous placeholder + + m_placeholder[idx] = holder; + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + + getSqlForException() + ": " + ex.getMessage().str()); + } +} + //------------------------------------------------------------------------------ // bindUint16 //------------------------------------------------------------------------------ @@ -536,6 +582,9 @@ bool MysqlStmt::do_bind() { } switch(holder->get_buffer_type()) { + case Mysql::Placeholder::placeholder_uint8: + bind[idx].buffer_type = MYSQL_TYPE_TINY; + break; case Mysql::Placeholder::placeholder_uint16: bind[idx].buffer_type = MYSQL_TYPE_SHORT; break; diff --git a/rdbms/wrapper/MysqlStmt.hpp b/rdbms/wrapper/MysqlStmt.hpp index ea12143f3b..fd8842df28 100644 --- a/rdbms/wrapper/MysqlStmt.hpp +++ b/rdbms/wrapper/MysqlStmt.hpp @@ -84,6 +84,22 @@ public: */ MYSQL_STMT *get() const; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindUint8(const std::string ¶mName, const uint8_t paramValue) override; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) override; + /** * Binds an SQL parameter. * diff --git a/rdbms/wrapper/OcciRset.cpp b/rdbms/wrapper/OcciRset.cpp index 6094d1bdd8..d0da2c0d7d 100644 --- a/rdbms/wrapper/OcciRset.cpp +++ b/rdbms/wrapper/OcciRset.cpp @@ -162,6 +162,32 @@ optional<std::string> OcciRset::columnOptionalString(const std::string &colName) } } +//------------------------------------------------------------------------------ +// columnOptionalUint8 +//------------------------------------------------------------------------------ +optional<uint8_t> OcciRset::columnOptionalUint8(const std::string &colName) const { + try { + threading::Mutex locker(m_mutex); + + const int colIdx = m_colNameToIdx.getIdx(colName); + const std::string stringValue = m_rset->getString(colIdx); + if(stringValue.empty()) { + return nullopt; + } + if(!utils::isValidUInt(stringValue)) { + throw exception::Exception(std::string("Column ") + colName + " contains the value " + stringValue + + " which is not a valid unsigned integer"); + } + return utils::toUint8(stringValue); + } catch(exception::Exception &ne) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() + ": " + + ne.getMessage().str()); + } catch(std::exception &se) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() + ": " + + se.what()); + } +} + //------------------------------------------------------------------------------ // columnOptionalUint16 //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/OcciRset.hpp b/rdbms/wrapper/OcciRset.hpp index 2725658fbf..f567902b2a 100644 --- a/rdbms/wrapper/OcciRset.hpp +++ b/rdbms/wrapper/OcciRset.hpp @@ -98,6 +98,16 @@ public: */ optional<std::string> columnOptionalString(const std::string &colName) const override; + /** + * Returns the value of the specified column as an integer. + * + * 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. + */ + optional<uint8_t> columnOptionalUint8(const std::string &colName) const override; + /** * Returns the value of the specified column as an integer. * diff --git a/rdbms/wrapper/OcciStmt.cpp b/rdbms/wrapper/OcciStmt.cpp index 46034805f2..e8e5e1bb11 100644 --- a/rdbms/wrapper/OcciStmt.cpp +++ b/rdbms/wrapper/OcciStmt.cpp @@ -87,6 +87,30 @@ void OcciStmt::close() { } } +//------------------------------------------------------------------------------ +// bindUint8 +//------------------------------------------------------------------------------ +void OcciStmt::bindUint8(const std::string ¶mName, const uint8_t paramValue) { + try { + bindOptionalUint8(paramName, paramValue); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// bindOptionalUint8 +//------------------------------------------------------------------------------ +void OcciStmt::bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) { + try { + return bindOptionalInteger<uint8_t>(paramName, paramValue); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + //------------------------------------------------------------------------------ // bindUint16 //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/OcciStmt.hpp b/rdbms/wrapper/OcciStmt.hpp index 08919b2b9c..4b73c4ca6c 100644 --- a/rdbms/wrapper/OcciStmt.hpp +++ b/rdbms/wrapper/OcciStmt.hpp @@ -81,6 +81,22 @@ public: */ void close() override; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindUint8(const std::string ¶mName, const uint8_t paramValue) override; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) override; + /** * Binds an SQL parameter. * diff --git a/rdbms/wrapper/PostgresRset.cpp b/rdbms/wrapper/PostgresRset.cpp index eab066f0ea..ab9024e713 100644 --- a/rdbms/wrapper/PostgresRset.cpp +++ b/rdbms/wrapper/PostgresRset.cpp @@ -109,6 +109,35 @@ optional<std::string> PostgresRset::columnOptionalString(const std::string &colN return optional<std::string>(PQgetvalue(m_resItr->get(), 0, ifield)); } +//------------------------------------------------------------------------------ +// columnOptionalUint8 +//------------------------------------------------------------------------------ +optional<uint8_t> PostgresRset::columnOptionalUint8(const std::string &colName) const { + + if (nullptr == m_resItr->get()) { + throw exception::Exception(std::string(__FUNCTION__) + " no row available"); + } + + const int ifield = PQfnumber(m_resItr->get(), colName.c_str()); + if (ifield < 0) { + throw exception::Exception(std::string(__FUNCTION__) + " column does not exist: " + colName); + } + + // the value can be null + if (PQgetisnull(m_resItr->get(), 0, ifield)) { + return nullopt; + } + + const std::string stringValue(PQgetvalue(m_resItr->get(), 0, ifield)); + + if(!utils::isValidUInt(stringValue)) { + throw exception::Exception(std::string("Column ") + colName + " contains the value " + stringValue + + " which is not a valid unsigned integer"); + } + + return utils::toUint8(stringValue); +} + //------------------------------------------------------------------------------ // columnOptionalUint16 //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/PostgresRset.hpp b/rdbms/wrapper/PostgresRset.hpp index 9d79c46de3..024312394b 100644 --- a/rdbms/wrapper/PostgresRset.hpp +++ b/rdbms/wrapper/PostgresRset.hpp @@ -78,6 +78,16 @@ public: */ optional<std::string> columnOptionalString(const std::string &colName) const override; + /** + * Returns the value of the specified column as an integer. + * + * 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. + */ + optional<uint8_t> columnOptionalUint8(const std::string &colName) const override; + /** * Returns the value of the specified column as an integer. * diff --git a/rdbms/wrapper/PostgresStmt.cpp b/rdbms/wrapper/PostgresStmt.cpp index dee2dcfc31..745c6d3576 100644 --- a/rdbms/wrapper/PostgresStmt.cpp +++ b/rdbms/wrapper/PostgresStmt.cpp @@ -102,6 +102,19 @@ void PostgresStmt::bindOptionalString(const std::string ¶mName, const option } } +//------------------------------------------------------------------------------ +// bindOptionalUint8 +//------------------------------------------------------------------------------ +void PostgresStmt::bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) { + try { + return bindOptionalInteger<uint8_t>(paramName, paramValue); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed for SQL statement " + + getSqlForException() + ": " + ex.getMessage().str()); + throw; + } +} + //------------------------------------------------------------------------------ // bindOptionalUint16 //------------------------------------------------------------------------------ @@ -156,6 +169,18 @@ void PostgresStmt::bindString(const std::string ¶mName, const std::string &p } } +//------------------------------------------------------------------------------ +// bindUint8 +//------------------------------------------------------------------------------ +void PostgresStmt::bindUint8(const std::string ¶mName, const uint8_t paramValue) { + try { + bindOptionalUint8(paramName, paramValue); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + //------------------------------------------------------------------------------ // bindUint16 //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/PostgresStmt.hpp b/rdbms/wrapper/PostgresStmt.hpp index 7055487134..26d167aa0a 100644 --- a/rdbms/wrapper/PostgresStmt.hpp +++ b/rdbms/wrapper/PostgresStmt.hpp @@ -76,6 +76,14 @@ public: */ void bindOptionalString(const std::string ¶mName, const optional<std::string> ¶mValue) override; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) override; + /** * Binds an SQL parameter. * @@ -120,6 +128,14 @@ public: */ void bindString(const std::string ¶mName, const std::string ¶mValue) override; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindUint8(const std::string ¶mName, const uint8_t paramValue) override; + /** * Binds an SQL parameter. * diff --git a/rdbms/wrapper/RsetWrapper.hpp b/rdbms/wrapper/RsetWrapper.hpp index a8963fb165..cfec4e27a3 100644 --- a/rdbms/wrapper/RsetWrapper.hpp +++ b/rdbms/wrapper/RsetWrapper.hpp @@ -80,6 +80,16 @@ public: */ virtual optional<std::string> columnOptionalString(const std::string &colName) const = 0; + /** + * Returns the value of the specified column as an integer. + * + * 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<uint8_t> columnOptionalUint8(const std::string &colName) const = 0; + /** * Returns the value of the specified column as an integer. * diff --git a/rdbms/wrapper/SqliteRset.cpp b/rdbms/wrapper/SqliteRset.cpp index 1e5b367ff2..ea7a551c0e 100644 --- a/rdbms/wrapper/SqliteRset.cpp +++ b/rdbms/wrapper/SqliteRset.cpp @@ -256,6 +256,22 @@ optional<std::string> SqliteRset::columnOptionalString(const std::string &colNam } } +//------------------------------------------------------------------------------ +// columnOptionalUint8 +//------------------------------------------------------------------------------ +optional<uint8_t> SqliteRset::columnOptionalUint8(const std::string &colName) const { + try { + const ColumnNameToIdxAndType::IdxAndType idxAndType = m_colNameToIdxAndType.getIdxAndType(colName); + if(SQLITE_NULL == idxAndType.colType) { + return nullopt; + } else { + return optional<uint8_t>(sqlite3_column_int(m_stmt.get(), idxAndType.colIdx)); + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + //------------------------------------------------------------------------------ // columnOptionalUint16 //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/SqliteRset.hpp b/rdbms/wrapper/SqliteRset.hpp index 24667a5911..0a0bed7e6d 100644 --- a/rdbms/wrapper/SqliteRset.hpp +++ b/rdbms/wrapper/SqliteRset.hpp @@ -93,6 +93,16 @@ public: */ optional<std::string> columnOptionalString(const std::string &colName) const override; + /** + * Returns the value of the specified column as an integer. + * + * 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. + */ + optional<uint8_t> columnOptionalUint8(const std::string &colName) const override; + /** * Returns the value of the specified column as an integer. * diff --git a/rdbms/wrapper/SqliteStmt.cpp b/rdbms/wrapper/SqliteStmt.cpp index ae64ccbf04..305214eace 100644 --- a/rdbms/wrapper/SqliteStmt.cpp +++ b/rdbms/wrapper/SqliteStmt.cpp @@ -149,6 +149,39 @@ sqlite3_stmt *SqliteStmt::get() const { return m_stmt; } +//------------------------------------------------------------------------------ +// bindUint8 +//------------------------------------------------------------------------------ +void SqliteStmt::bindUint8(const std::string ¶mName, const uint8_t paramValue) { + try { + bindOptionalUint8(paramName, paramValue); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// bindOptionalUint8 +//------------------------------------------------------------------------------ +void SqliteStmt::bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) { + try { + const unsigned int paramIdx = getParamIdx(paramName); + int bindRc = 0; + if(paramValue) { + bindRc = sqlite3_bind_int(m_stmt, paramIdx, paramValue.value()); + } else { + bindRc = sqlite3_bind_null(m_stmt, paramIdx); + } + if(SQLITE_OK != bindRc) { + throw exception::Exception(Sqlite::rcToStr(bindRc)); + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + + getSqlForException() + ": " + ex.getMessage().str()); + } +} + //------------------------------------------------------------------------------ // bindUint16 //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/SqliteStmt.hpp b/rdbms/wrapper/SqliteStmt.hpp index 3d19b8c8f8..3213cd090b 100644 --- a/rdbms/wrapper/SqliteStmt.hpp +++ b/rdbms/wrapper/SqliteStmt.hpp @@ -75,6 +75,22 @@ public: */ sqlite3_stmt *get() const; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindUint8(const std::string ¶mName, const uint8_t paramValue) override; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) override; + /** * Binds an SQL parameter. * diff --git a/rdbms/wrapper/StmtWrapper.hpp b/rdbms/wrapper/StmtWrapper.hpp index 45af44db86..f5c54ebd60 100644 --- a/rdbms/wrapper/StmtWrapper.hpp +++ b/rdbms/wrapper/StmtWrapper.hpp @@ -95,6 +95,22 @@ public: */ uint32_t getParamIdx(const std::string ¶mName) const; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + virtual void bindUint8(const std::string ¶mName, const uint8_t paramValue) = 0; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + virtual void bindOptionalUint8(const std::string ¶mName, const optional<uint8_t> ¶mValue) = 0; + /** * Binds an SQL parameter. * -- GitLab