Commit a4116aa7 authored by Steven Murray's avatar Steven Murray
Browse files

Added Stmt::bindUint8()

parent 8e4a0dbe
......@@ -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'
......
......@@ -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
//------------------------------------------------------------------------------
......
......@@ -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.
*
......
......@@ -116,6 +116,38 @@ uint32_t Stmt::getParamIdx(const std::string &paramName) const {
}
}
//-----------------------------------------------------------------------------
// bindUint8
//-----------------------------------------------------------------------------
void Stmt::bindUint8(const std::string &paramName, 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 &paramName, const optional<uint8_t> &paramValue) {
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
//-----------------------------------------------------------------------------
......
......@@ -103,6 +103,22 @@ public:
*/
uint32_t getParamIdx(const std::string &paramName) const;
/**
* Binds an SQL parameter.
*
* @param paramName The name of the parameter.
* @param paramValue The value to be bound.
*/
void bindUint8(const std::string &paramName, 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 &paramName, const optional<uint8_t> &paramValue);
/**
* Binds an SQL parameter.
*
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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
//------------------------------------------------------------------------------
......
......@@ -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.
*
......
......@@ -170,6 +170,52 @@ MYSQL_STMT *MysqlStmt::get() const {
return m_stmt;
}
//------------------------------------------------------------------------------
// bindUint8
//------------------------------------------------------------------------------
void MysqlStmt::bindUint8(const std::string &paramName, 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 &paramName, const optional<uint8_t> &paramValue) {
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;
......
......@@ -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 &paramName, const uint8_t paramValue) override;
/**
* Binds an SQL parameter.
*