Commit 0b9a48d9 authored by Steven Murray's avatar Steven Murray
Browse files

Added Stmt::bindUint16()

parent 0cf85cc0
......@@ -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/UINT16TYPE/INTEGER/g'
| sed 's/UINT64TYPE/INTEGER/g'
| sed 's/NUMERIC\([^\)]*\)/INTEGER/g'
| sed 's/CHECKSUM_BLOB_TYPE/BLOB\(200\)/g'
......@@ -109,6 +110,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/UINT16TYPE/SMALLINT_UNSIGNED/g'
| sed 's/UINT64TYPE/BIGINT UNSIGNED/g'
| sed 's/NUMERIC\([^\)]*\)/BIGINT UNSIGNED/g'
| sed 's/CHECKSUM_BLOB_TYPE/VARBINARY\(200\)/g'
......@@ -117,6 +119,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/UINT16TYPE/NUMERIC(5, 0)/g'
| sed 's/UINT64TYPE/NUMERIC(20, 0)/g'
| sed 's/VARCHAR/VARCHAR2/g'
| sed 's/CHECKSUM_BLOB_TYPE/RAW\(200\)/g'
......@@ -125,6 +128,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/UINT16TYPE/NUMERIC(5, 0)/g'
| sed 's/UINT64TYPE/NUMERIC(20, 0)/g'
| sed 's/CHECKSUM_BLOB_TYPE/BYTEA/g'
> postgres_catalogue_schema.sql
......
......@@ -94,6 +94,27 @@ std::string Rset::columnString(const std::string &colName) const {
}
}
//------------------------------------------------------------------------------
// columnUint16
//------------------------------------------------------------------------------
uint16_t Rset::columnUint16(const std::string &colName) const {
try {
if(nullptr == m_impl) {
throw InvalidResultSet("This result set is invalid");
}
const optional<uint16_t> col = columnOptionalUint16(colName);
if(col) {
return col.value();
} else {
throw NullDbValue(std::string("Database column ") + colName + " contains a null value");
}
} catch(exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
throw;
}
}
//------------------------------------------------------------------------------
// columnUint64
//------------------------------------------------------------------------------
......@@ -233,6 +254,21 @@ optional<std::string> Rset::columnOptionalString(const std::string &colName) con
}
}
//------------------------------------------------------------------------------
// columnOptionalUint16
//------------------------------------------------------------------------------
optional<uint16_t> Rset::columnOptionalUint16(const std::string &colName) const {
try {
if(nullptr == m_impl) {
throw InvalidResultSet("This result set is invalid");
}
return m_impl->columnOptionalUint16(colName);
} catch(exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
throw;
}
}
//------------------------------------------------------------------------------
// columnOptionalUint64
//------------------------------------------------------------------------------
......
......@@ -141,6 +141,18 @@ public:
*/
optional<std::string> columnOptionalString(const std::string &colName) const;
/**
* Returns the value of the specified column as an integer.
*
* 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.
* @throw InvalidResultSet if the result is invalid.
*/
uint16_t columnUint16(const std::string &colName) const;
/**
* Returns the value of the specified column as an integer.
*
......@@ -168,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<uint16_t> columnOptionalUint16(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 {
}
}
//-----------------------------------------------------------------------------
// bindUint16
//-----------------------------------------------------------------------------
void Stmt::bindUint16(const std::string &paramName, const uint16_t paramValue) {
try {
if(nullptr != m_stmt) {
return m_stmt->bindUint16(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;
}
}
//-----------------------------------------------------------------------------
// bindOptionalUint16
//-----------------------------------------------------------------------------
void Stmt::bindOptionalUint16(const std::string &paramName, const optional<uint16_t> &paramValue) {
try {
if(nullptr != m_stmt) {
return m_stmt->bindOptionalUint16(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;
}
}
//-----------------------------------------------------------------------------
// bindUint64
//-----------------------------------------------------------------------------
......
......@@ -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 bindUint16(const std::string &paramName, const uint16_t paramValue);
/**
* Binds an SQL parameter.
*
* @param paramName The name of the parameter.
* @param paramValue The value to be bound.
*/
void bindOptionalUint16(const std::string &paramName, const optional<uint16_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"
" UINT16_COL UINT16TYPE," "\n"
" UINT64_COL UINT64TYPE," "\n"
" STRING_COL VARCHAR(100)," "\n"
" BOOL_COL CHAR(1) DEFAULT '0'," "\n"
......@@ -77,16 +78,20 @@ std::string cta_rdbms_StmtTest::getCreateStmtTestTableSql() {
case Login::DBTYPE_IN_MEMORY:
break;
case Login::DBTYPE_ORACLE:
utils::searchAndReplace(sql, "UINT16TYPE", "NUMERIC(5, 0)");
utils::searchAndReplace(sql, "UINT64TYPE", "NUMERIC(20, 0)");
utils::searchAndReplace(sql, "VARCHAR", "VARCHAR2");
break;
case Login::DBTYPE_SQLITE:
utils::searchAndReplace(sql, "UINT16TYPE", "INTEGER");
utils::searchAndReplace(sql, "UINT64TYPE", "INTEGER");
break;
case Login::DBTYPE_MYSQL:
utils::searchAndReplace(sql, "UINT16TYPE", "SMALLINT UNSIGNED");
utils::searchAndReplace(sql, "UINT64TYPE", "BIGINT UNSIGNED");
break;
case Login::DBTYPE_POSTGRESQL:
utils::searchAndReplace(sql, "UINT16TYPE", "NUMERIC(5, 0)");
utils::searchAndReplace(sql, "UINT64TYPE", "NUMERIC(20, 0)");
break;
case Login::DBTYPE_NONE:
......@@ -163,6 +168,164 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindDouble) {
}
}
TEST_P(cta_rdbms_StmtTest, insert_with_bindUint16) {
using namespace cta::rdbms;
const uint16_t insertValue = 1234;
// Insert a row into the test table
{
const char *const sql =
"INSERT INTO STMT_TEST(" "\n"
" ID," "\n"
" UINT16_COL) " "\n"
"VALUES(" "\n"
" 1," "\n"
" :UINT16_COL)";
auto stmt = m_conn.createStmt(sql);
stmt.bindUint16(":UINT16_COL", insertValue);
stmt.executeNonQuery();
}
// Select the row back from the table
{
const char *const sql =
"SELECT" "\n"
" UINT16_COL AS UINT16_COL" "\n"
"FROM" "\n"
" STMT_TEST";
auto stmt = m_conn.createStmt(sql);
auto rset = stmt.executeQuery();
ASSERT_TRUE(rset.next());
const auto selectValue = rset.columnOptionalUint16("UINT16_COL");
ASSERT_TRUE((bool)selectValue);
ASSERT_EQ(insertValue,selectValue.value());
ASSERT_FALSE(rset.next());
}
}
TEST_P(cta_rdbms_StmtTest, insert_with_bindUint16_2_pow_16_minus_1) {
using namespace cta::rdbms;
const uint16_t insertValue = 65535U;
// Insert a row into the test table
{
const char *const sql =
"INSERT INTO STMT_TEST(" "\n"
" ID," "\n"
" UINT16_COL)" "\n"
"VALUES(" "\n"
" 1," "\n"
" :UINT16_COL)";
auto stmt = m_conn.createStmt(sql);
stmt.bindUint16(":UINT16_COL", insertValue);
stmt.executeNonQuery();
}
// Select the row back from the table
{
const char *const sql =
"SELECT" "\n"
" UINT16_COL AS UINT16_COL" "\n"
"FROM" "\n"
" STMT_TEST";
auto stmt = m_conn.createStmt(sql);
auto rset = stmt.executeQuery();
ASSERT_TRUE(rset.next());
const auto selectValue = rset.columnOptionalUint16("UINT16_COL");
ASSERT_TRUE((bool)selectValue);
ASSERT_EQ(insertValue,selectValue.value());
ASSERT_FALSE(rset.next());
}
}
TEST_P(cta_rdbms_StmtTest, insert_with_bindOptionalUint16_null) {
using namespace cta::rdbms;
const cta::optional<uint16_t> insertValue; // Null value
// Insert a row into the test table
{
const char *const sql =
"INSERT INTO STMT_TEST(" "\n"
" ID," "\n"
" UINT16_COL) " "\n"
"VALUES(" "\n"
" 1," "\n"
" :UINT16_COL)";
auto stmt = m_conn.createStmt(sql);
stmt.bindOptionalUint16(":UINT16_COL", insertValue);
stmt.executeNonQuery();
}
// Select the row back from the table
{
const char *const sql =
"SELECT" "\n"
" UINT16_COL AS UINT16_COL" "\n"
"FROM" "\n"
" STMT_TEST";
auto stmt = m_conn.createStmt(sql);
auto rset = stmt.executeQuery();
ASSERT_TRUE(rset.next());
const auto selectValue = rset.columnOptionalUint16("UINT16_COL");
ASSERT_FALSE((bool)selectValue);
ASSERT_FALSE(rset.next());
}
}
TEST_P(cta_rdbms_StmtTest, insert_with_bindOptionalUint16) {
using namespace cta::rdbms;
const cta::optional<uint16_t> insertValue = 1234;
// Insert a row into the test table
{
const char *const sql =
"INSERT INTO STMT_TEST(" "\n"
" ID," "\n"
" UINT16_COL) " "\n"
"VALUES(" "\n"
" 1," "\n"
" :UINT16_COL)";
auto stmt = m_conn.createStmt(sql);
stmt.bindOptionalUint16(":UINT16_COL", insertValue);
stmt.executeNonQuery();
}
// Select the row back from the table
{
const char *const sql =
"SELECT" "\n"
" UINT16_COL AS UINT16_COL" "\n"
"FROM" "\n"
" STMT_TEST";
auto stmt = m_conn.createStmt(sql);
auto rset = stmt.executeQuery();
ASSERT_TRUE(rset.next());
const auto selectValue = rset.columnOptionalUint16("UINT16_COL");
ASSERT_TRUE((bool)selectValue);
ASSERT_EQ(insertValue,selectValue.value());
ASSERT_FALSE(rset.next());
}
}
TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64) {
using namespace cta::rdbms;
......
......@@ -32,6 +32,7 @@ typedef char my_bool;
extern "C" void mysql_free_result(MYSQL_RES *result);
#include <vector>
#include <limits>
#include <map>
#include <memory>
#include <stdint.h>
......@@ -97,6 +98,7 @@ class Mysql {
}
enum buffer_types {
placeholder_uint16,
placeholder_uint64,
placeholder_string,
placeholder_double,
......@@ -112,6 +114,7 @@ class Mysql {
virtual bool get_is_unsigned() = 0;
virtual my_bool* get_error() { return &error; }
// following is to access data
virtual uint16_t get_uint16() = 0;
virtual uint64_t get_uint64() = 0;
virtual std::string get_string() = 0;
virtual double get_double() = 0;
......@@ -119,6 +122,58 @@ class Mysql {
virtual bool reset() = 0;
};
struct Placeholder_Uint16: Placeholder {
uint16_t val;
Placeholder_Uint16()
: 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_uint16;
}
void* get_buffer() override {
return &val;
}
unsigned long get_buffer_length() override {
return sizeof(uint16_t);
}
bool get_is_unsigned() override {
return true;
}
uint16_t get_uint16() 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_Uint64: Placeholder {
uint64_t val;
......@@ -127,7 +182,7 @@ class Mysql {
}
std::string show() {
std::string show() override {
std::stringstream ss;
ss << "['" << idx << "' '" << is_null << "' '" << length << "' '" << val << "' '" << get_buffer_length() << "']";
return ss.str();
......@@ -149,19 +204,29 @@ class Mysql {
return true;
}
uint64_t get_uint64() {
uint16_t get_uint16() override {
if(std::numeric_limits<uint16_t>::max() < val) {
std::ostringstream msg;
msg << "Cannot convert uint64 to uint16: Overflow: uint64=" << val <<
" maxUint16=" << std::numeric_limits<uint16_t>::max();
throw exception::Exception(msg.str());
}
return val;
}
std::string get_string() {
uint64_t get_uint64() override {
return val;
}
std::string get_string() override {
return std::to_string(val);
}
double get_double() {
double get_double() override {
return val;
}
bool reset() {
bool reset() override {
return false;
}
......@@ -183,7 +248,7 @@ class Mysql {
delete [] val;
}
std::string show() {
std::string show() override {
std::stringstream ss;
ss << "['" << idx << "' '" << is_null << "' '" << length << "' '" << val << "' '" << get_buffer_length() << "']";
return ss.str();
......@@ -206,23 +271,34 @@ class Mysql {
return false;
}
uint16_t get_uint16() override {
const uint64_t i = std::stoll(val);
if(std::numeric_limits<uint16_t>::max() > i) {
std::ostringstream msg;
msg << "Failed to convert string to uint16: Overflow: string=" << val << " maxUint16=" <<
std::numeric_limits<uint16_t>::max();
throw exception::Exception(msg.str());
}
return i;
}
// note: allow users try to convert from string to int,
// but users need to catch the exception.
uint64_t get_uint64() {
uint64_t get_uint64() override {
return std::stoll(val);
}
std::string get_string() {
std::string get_string() override {
return std::string(val, val+*get_length());
}
// note: allow users try to convert from string to int,
// but users need to catch the exception.
double get_double() {
double get_double() override {
return std::stod(val);
}
bool reset() {
bool reset() override {
memset(val, 0, buf_sz);
return true;
......@@ -260,6 +336,10 @@ class Mysql {
return true;
}
uint16_t get_uint16() override {
throw val;
}
uint64_t get_uint64() override {
return val;
}
......
......@@ -119,6 +119,25 @@ optional<std::string> MysqlRset::columnOptionalString(const std::string &colName
return optional<std::string>(holder->get_string());
}
//------------------------------------------------------------------------------
// columnOptionalUint16
//------------------------------------------------------------------------------
optional<uint16_t> MysqlRset::columnOptionalUint16(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<uint16_t>(holder->get_uint16());
}
//------------------------------------------------------------------------------
// columnOptionalUint64
//------------------------------------------------------------------------------
......
......@@ -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<uint16_t> columnOptionalUint16(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;
}
//------------------------------------------------------------------------------
// bindUint16
//------------------------------------------------------------------------------
void MysqlStmt::bindUint16(const std::string &paramName, const uint16_t paramValue) {
try {
bindOptionalUint16(paramName, paramValue);
} catch(exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
throw;
}
}
//------------------------------------------------------------------------------
// bindOptionalUint16
//------------------------------------------------------------------------------
void MysqlStmt::bindOptionalUint16(const std::string &paramName, const optional<uint16_t> &paramValue) {
try {
const unsigned int paramIdx = getParamIdx(paramName); // starts from 1.