From 39a630b7a151bd3428541eda7f3b01f57c98ef1e Mon Sep 17 00:00:00 2001 From: zussel Date: Wed, 1 Jan 2020 19:08:42 +0100 Subject: [PATCH 01/18] added database_error - consists of specific database error informations - sql state - internal error code - error message --- include/matador/db/mssql/mssql_connection.hpp | 3 +- include/matador/db/mssql/mssql_exception.hpp | 19 ++---- include/matador/db/mssql/mssql_result.hpp | 6 +- include/matador/db/mysql/mysql_connection.hpp | 3 +- include/matador/db/mysql/mysql_constants.hpp | 5 ++ include/matador/db/mysql/mysql_exception.hpp | 25 +------- .../db/postgresql/postgresql_connection.hpp | 3 +- .../db/postgresql/postgresql_exception.hpp | 28 +-------- .../matador/db/sqlite/sqlite_connection.hpp | 3 +- .../matador/db/sqlite/sqlite_exception.hpp | 10 +--- include/matador/sql/connection_impl.hpp | 3 +- include/matador/sql/database_error.hpp | 34 +++++++++++ include/matador/sql/memory_connection.hpp | 3 +- include/matador/sql/types.hpp | 2 +- src/db/mssql/mssql_connection.cpp | 51 ++++++++-------- src/db/mssql/mssql_exception.cpp | 58 +++++++++--------- src/db/mssql/mssql_parameter_binder.cpp | 4 +- src/db/mssql/mssql_result.cpp | 20 +++---- src/db/mssql/mssql_statement.cpp | 14 ++--- src/db/mysql/mysql_connection.cpp | 15 +++-- src/db/mysql/mysql_exception.cpp | 59 ++----------------- src/db/mysql/mysql_prepared_result.cpp | 2 +- src/db/mysql/mysql_result.cpp | 2 +- src/db/mysql/mysql_statement.cpp | 21 ++++--- src/db/postgresql/postgresql_connection.cpp | 21 ++++--- src/db/postgresql/postgresql_exception.cpp | 38 +++--------- src/db/postgresql/postgresql_statement.cpp | 46 ++------------- src/db/sqlite/sqlite_connection.cpp | 24 ++++---- src/db/sqlite/sqlite_exception.cpp | 15 +---- src/db/sqlite/sqlite_parameter_binder.cpp | 32 +++++----- src/db/sqlite/sqlite_prepared_result.cpp | 2 +- src/db/sqlite/sqlite_statement.cpp | 6 +- src/sql/CMakeLists.txt | 4 +- src/sql/database_error.cpp | 53 +++++++++++++++++ test/sql/ConnectionTestUnit.cpp | 21 +++++++ test/sql/ConnectionTestUnit.hpp | 2 + 36 files changed, 311 insertions(+), 346 deletions(-) create mode 100644 include/matador/sql/database_error.hpp create mode 100644 src/sql/database_error.cpp diff --git a/include/matador/db/mssql/mssql_connection.hpp b/include/matador/db/mssql/mssql_connection.hpp index 944bf9688..bfdd4ef96 100644 --- a/include/matador/db/mssql/mssql_connection.hpp +++ b/include/matador/db/mssql/mssql_connection.hpp @@ -76,7 +76,8 @@ class OOS_MSSQL_API mssql_connection : public connection_impl void rollback() override; std::string type() const override; - std::string version() const override; + std::string client_version() const override; + std::string server_version() const override; bool exists(const std::string &tablename) override; std::vector describe(const std::string &table) override; diff --git a/include/matador/db/mssql/mssql_exception.hpp b/include/matador/db/mssql/mssql_exception.hpp index f45157e0a..85dc9c222 100644 --- a/include/matador/db/mssql/mssql_exception.hpp +++ b/include/matador/db/mssql/mssql_exception.hpp @@ -41,24 +41,13 @@ namespace matador { namespace mssql { -void throw_error(SQLRETURN ret, SQLSMALLINT htype, SQLHANDLE hndl, const std::string &source, const std::string &sql = ""); +void throw_database_error(SQLRETURN ret, SQLSMALLINT htype, SQLHANDLE hndl, const std::string &source, const std::string &sql = ""); -void throw_error(const std::string &source, const std::string &sql = ""); +//void throw_error(SQLRETURN ret, SQLSMALLINT htype, SQLHANDLE hndl, const std::string &source, const std::string &sql = ""); -bool is_success(SQLRETURN ret); - -class mssql_exception : public sql_exception -{ -public: - mssql_exception(const std::string &source, const std::string &what); -}; +//void throw_error(const std::string &source, const std::string &sql = ""); -class mssql_stmt_exception : public sql_exception -{ -public: - explicit mssql_stmt_exception(const std::string &what); - mssql_stmt_exception(const std::string &source, const std::string &what); -}; +bool is_success(SQLRETURN ret); } diff --git a/include/matador/db/mssql/mssql_result.hpp b/include/matador/db/mssql/mssql_result.hpp index e937b2f26..2f010b7a8 100644 --- a/include/matador/db/mssql/mssql_result.hpp +++ b/include/matador/db/mssql/mssql_result.hpp @@ -67,7 +67,7 @@ class mssql_result : public detail::result_impl auto type = (SQLSMALLINT)type2int(matador::data_type_traits::builtin_type()); SQLRETURN ret = SQLGetData(stmt_, (SQLUSMALLINT)(index), type, &val, sizeof(T), &info); if (!SQL_SUCCEEDED(ret)) { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } return val; } @@ -79,7 +79,7 @@ class mssql_result : public detail::result_impl SQLLEN info = 0; SQLRETURN ret = SQLGetData(stmt_, (SQLUSMALLINT)(index), SQL_C_CHAR, buf, 1024, &info); if (!SQL_SUCCEEDED(ret)) { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } return std::string(buf, info); } @@ -117,7 +117,7 @@ class mssql_result : public detail::result_impl } else { std::stringstream msg; msg << "error on retrieving value for column " << id << " (type " << typeid(T).name() << ")"; - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", msg.str()); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", msg.str()); } } diff --git a/include/matador/db/mysql/mysql_connection.hpp b/include/matador/db/mysql/mysql_connection.hpp index 08be3c350..80d08c05c 100644 --- a/include/matador/db/mysql/mysql_connection.hpp +++ b/include/matador/db/mysql/mysql_connection.hpp @@ -90,7 +90,8 @@ class OOS_MYSQL_API mysql_connection : public connection_impl void rollback() override; std::string type() const override; - std::string version() const override; + std::string client_version() const override; + std::string server_version() const override; bool exists(const std::string &tablename) override; std::vector describe(const std::string &table) override; diff --git a/include/matador/db/mysql/mysql_constants.hpp b/include/matador/db/mysql/mysql_constants.hpp index f8f296a27..0e555149f 100644 --- a/include/matador/db/mysql/mysql_constants.hpp +++ b/include/matador/db/mysql/mysql_constants.hpp @@ -18,6 +18,11 @@ class mysql static const long version = MYSQL_VERSION_ID; }; +#if MYSQL_VERSION_ID >= 80000 +typedef bool mysql_bool; +#else +typedef my_bool bool; +#endif } } #endif /* MYSQL_CONSTANTS_HPP */ \ No newline at end of file diff --git a/include/matador/db/mysql/mysql_exception.hpp b/include/matador/db/mysql/mysql_exception.hpp index 6fc72f424..8dc183a1c 100644 --- a/include/matador/db/mysql/mysql_exception.hpp +++ b/include/matador/db/mysql/mysql_exception.hpp @@ -32,7 +32,6 @@ #include "matador/sql/sql_exception.hpp" #ifdef _MSC_VER -//#include #include #else #include @@ -42,29 +41,9 @@ namespace matador { namespace mysql { -void throw_error(const std::string &source, const std::string &sql = ""); +void throw_error(MYSQL *db, const std::string &source, const std::string &sql = ""); -void throw_error(int ec, MYSQL *db, const std::string &source, const std::string &sql = ""); - -void throw_stmt_error(int ec, MYSQL_STMT *stmt, const std::string &source, const std::string &sql = ""); - -class mysql_exception : public sql_exception -{ -public: - mysql_exception(const std::string &source, const std::string &what); - mysql_exception(MYSQL *db, const std::string &source, const std::string &what); - - virtual ~mysql_exception() throw(); -}; - -class mysql_stmt_exception : public sql_exception -{ -public: - explicit mysql_stmt_exception(const std::string &what); - mysql_stmt_exception(MYSQL_STMT *stmt, const std::string &source, const std::string &what); - - virtual ~mysql_stmt_exception() throw(); -}; +void throw_stmt_error(MYSQL_STMT *stmt, const std::string &source, const std::string &sql = ""); } diff --git a/include/matador/db/postgresql/postgresql_connection.hpp b/include/matador/db/postgresql/postgresql_connection.hpp index 26f9db607..10e98a041 100644 --- a/include/matador/db/postgresql/postgresql_connection.hpp +++ b/include/matador/db/postgresql/postgresql_connection.hpp @@ -72,7 +72,8 @@ class MATADOR_POSTGRESQL_API postgresql_connection : public connection_impl void rollback() override; std::string type() const override; - std::string version() const override; + std::string client_version() const override; + std::string server_version() const override; bool exists(const std::string &table_name) override; std::vector describe(const std::string &table) override; diff --git a/include/matador/db/postgresql/postgresql_exception.hpp b/include/matador/db/postgresql/postgresql_exception.hpp index c1e74e09d..e8db1533e 100644 --- a/include/matador/db/postgresql/postgresql_exception.hpp +++ b/include/matador/db/postgresql/postgresql_exception.hpp @@ -14,33 +14,7 @@ namespace matador { namespace postgresql { -#define THROW_POSTGRESQL_ERROR(db, source, msg) \ - do { \ - std::stringstream what; \ - what << msg; \ - throw postgresql_exception(db, source, what.str()); \ - } while (false) - -void throw_error(const std::string &source, const std::string &sql = ""); - -void throw_error(int ec, PGconn *db, const std::string &source, const std::string &sql = ""); - -class postgresql_exception : public sql_exception -{ -public: - postgresql_exception(const std::string &source, const std::string &what); - postgresql_exception(PGconn *db, const std::string &source, const std::string &what); - - ~postgresql_exception() noexcept override = default; -}; - -class postgresql_stmt_exception : public sql_exception -{ -public: - explicit postgresql_stmt_exception(const std::string &what); - - ~postgresql_stmt_exception() noexcept override = default; -}; +void throw_database_error(PGresult *res, PGconn *db, const std::string &source, const std::string &sql = ""); } diff --git a/include/matador/db/sqlite/sqlite_connection.hpp b/include/matador/db/sqlite/sqlite_connection.hpp index bdcc027f7..55bd2a914 100644 --- a/include/matador/db/sqlite/sqlite_connection.hpp +++ b/include/matador/db/sqlite/sqlite_connection.hpp @@ -80,7 +80,8 @@ class OOS_SQLITE_API sqlite_connection : public connection_impl void rollback() override; std::string type() const override; - std::string version() const override; + std::string client_version() const override; + std::string server_version() const override; bool exists(const std::string &table_name) override; std::vector describe(const std::string &table) override; diff --git a/include/matador/db/sqlite/sqlite_exception.hpp b/include/matador/db/sqlite/sqlite_exception.hpp index d3ef1ecb5..576d7df3b 100644 --- a/include/matador/db/sqlite/sqlite_exception.hpp +++ b/include/matador/db/sqlite/sqlite_exception.hpp @@ -37,15 +37,7 @@ namespace matador { namespace sqlite { -void throw_error(int ec, sqlite3 *db, const std::string &source, const std::string &sql = ""); - -class sqlite_exception : public sql_exception -{ -public: - explicit sqlite_exception(const std::string &what); - - ~sqlite_exception() noexcept override = default; -}; +void throw_database_error(int ec, sqlite3 *db, const std::string &source, const std::string &sql = ""); } diff --git a/include/matador/sql/connection_impl.hpp b/include/matador/sql/connection_impl.hpp index 5ae6533ee..999f58180 100644 --- a/include/matador/sql/connection_impl.hpp +++ b/include/matador/sql/connection_impl.hpp @@ -54,7 +54,8 @@ class OOS_SQL_API connection_impl virtual void rollback() = 0; virtual std::string type() const = 0; - virtual std::string version() const = 0; + virtual std::string client_version() const = 0; + virtual std::string server_version() const = 0; virtual bool exists(const std::string &table_name) = 0; virtual std::vector describe(const std::string &table) = 0; diff --git a/include/matador/sql/database_error.hpp b/include/matador/sql/database_error.hpp new file mode 100644 index 000000000..3f1590c24 --- /dev/null +++ b/include/matador/sql/database_error.hpp @@ -0,0 +1,34 @@ +// +// Created by sascha on 28.12.19. +// + +#ifndef MATADOR_DATABASE_ERROR_HPP +#define MATADOR_DATABASE_ERROR_HPP + +#include + +namespace matador { + +class database_error : public std::runtime_error +{ +public: + database_error(const std::string &what, std::string source, long ec, std::string sql = ""); + database_error(const std::string &what, std::string source, std::string sqlstate, long ec, std::string sql = ""); + database_error(const std::string &what, std::string source, std::string sqlstate, std::string sql = ""); + + ~database_error() noexcept override = default; + + const char* source() const noexcept; + long error_code() const noexcept; + const char* sql_state() const noexcept; + const char* sql_statement() const noexcept; + +private: + std::string source_; + long error_code_ = 0; + std::string sqlstate_; + std::string sql_stmt_; +}; + +} +#endif //MATADOR_DATABASE_ERROR_HPP diff --git a/include/matador/sql/memory_connection.hpp b/include/matador/sql/memory_connection.hpp index fac548925..dd6e8c1eb 100644 --- a/include/matador/sql/memory_connection.hpp +++ b/include/matador/sql/memory_connection.hpp @@ -31,7 +31,8 @@ class memory_connection : public matador::connection_impl void rollback() override {} std::string type() const override { return "memory"; }; - std::string version() const override { return "0.6.0"; }; + std::string client_version() const override { return "0.6.1"; }; + std::string server_version() const override { return "0.6.1"; }; virtual const char *type_string(database_type) const { return nullptr; } diff --git a/include/matador/sql/types.hpp b/include/matador/sql/types.hpp index c83f06b0a..945eda12f 100644 --- a/include/matador/sql/types.hpp +++ b/include/matador/sql/types.hpp @@ -192,7 +192,7 @@ template <> struct data_type_traits inline static database_type type() { return database_type::type_bool; } inline static data_type builtin_type() { return data_type::type_bool; } inline static unsigned long size() { return sizeof(bool); } - inline static const char* name() { return "unsigned bool"; } + inline static const char* name() { return "bool"; } }; template <> struct data_type_traits diff --git a/src/db/mssql/mssql_connection.cpp b/src/db/mssql/mssql_connection.cpp index 5201f15d5..2ee9d91e2 100644 --- a/src/db/mssql/mssql_connection.cpp +++ b/src/db/mssql/mssql_connection.cpp @@ -52,7 +52,7 @@ void mssql_connection::open(const std::string &connection) std::smatch what; if (!std::regex_match(connection, what, DNS_RGX)) { - throw_error("mssql:connect", "invalid dns: " + connection); + throw std::logic_error("mssql:connect invalid dns: " + connection); } const std::string user = what[1].str(); @@ -78,19 +78,19 @@ void mssql_connection::open(const std::string &connection) SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &odbc_); if (ret != SQL_SUCCESS) { SQLFreeHandle(SQL_HANDLE_ENV, odbc_); - throw_error(ret, SQL_HANDLE_ENV, odbc_, "mssql", "couldn't get odbc handle"); + throw_database_error(ret, SQL_HANDLE_ENV, odbc_, "mssql"); } ret = SQLSetEnvAttr(odbc_, SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3, 0); if (ret != SQL_SUCCESS) { SQLFreeHandle(SQL_HANDLE_ENV, odbc_); - throw_error(ret, SQL_HANDLE_ENV, odbc_, "mssql", "couldn't set odbc driver version"); + throw_database_error(ret, SQL_HANDLE_ENV, odbc_, "mssql"); } ret = SQLAllocHandle(SQL_HANDLE_DBC, odbc_, &connection_); if (ret != SQL_SUCCESS) { SQLFreeHandle(SQL_HANDLE_ENV, odbc_); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "couldn't get connection handle"); + throw_database_error(ret, SQL_HANDLE_DBC, connection_, "mssql"); } SQLSetConnectAttr(connection_, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0); @@ -100,7 +100,7 @@ void mssql_connection::open(const std::string &connection) SQLCHAR retconstring[1024]; ret = SQLDriverConnect(connection_, nullptr, (SQLCHAR*)dns.c_str(), SQL_NTS, retconstring, 1024, nullptr, SQL_DRIVER_NOPROMPT); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on connect"); + throw_database_error(ret, SQL_HANDLE_DBC, connection_, "mssql"); is_open_ = true; } @@ -118,15 +118,15 @@ void mssql_connection::close() SQLRETURN ret = SQLDisconnect(connection_); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on disconnect"); + throw_database_error(ret, SQL_HANDLE_DBC, connection_, "mssql"); ret = SQLFreeHandle(SQL_HANDLE_DBC, connection_); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on freeing connection"); + throw_database_error(ret, SQL_HANDLE_DBC, connection_, "mssql"); connection_ = nullptr; ret = SQLFreeHandle(SQL_HANDLE_ENV, odbc_); - throw_error(ret, SQL_HANDLE_ENV, odbc_, "mssql", "error on freeing odbc"); + throw_database_error(ret, SQL_HANDLE_ENV, odbc_, "mssql"); odbc_ = nullptr; @@ -142,13 +142,13 @@ matador::detail::result_impl *mssql_connection::execute(const matador::sql &sql) detail::result_impl* mssql_connection::execute(const std::string &sqlstr) { if (!connection_) { - throw_error("mssql", "no odbc connection established"); + throw std::logic_error("mssql no odbc connection established"); } // create statement handle SQLHANDLE stmt; SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, connection_, &stmt); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on creating sql statement"); + throw_database_error(ret, SQL_HANDLE_DBC, connection_, "mssql", sqlstr); // execute statement // int retry = retries_; @@ -160,7 +160,7 @@ detail::result_impl* mssql_connection::execute(const std::string &sqlstr) } while (retry-- && !(SQL_SUCCEEDED(ret) || SQL_NO_DATA)); */ - throw_error(ret, SQL_HANDLE_STMT, stmt, sqlstr, "error on query execute"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql", sqlstr); return new mssql_result(stmt); } @@ -190,7 +190,12 @@ std::string mssql_connection::type() const return "mssql"; } -std::string mssql_connection::version() const +std::string mssql_connection::client_version() const +{ + return "1.1.1"; +} + +std::string mssql_connection::server_version() const { return "1.1.1"; } @@ -214,7 +219,7 @@ std::vector mssql_connection::describe(const std::string &table) // create statement handle SQLHANDLE stmt; SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, connection_, &stmt); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on creating sql statement"); + throw_database_error(ret, SQL_HANDLE_DBC, connection_, "mssql"); //std::string stmt("EXEC SP_COLUMNS " + table); @@ -225,7 +230,7 @@ std::vector mssql_connection::describe(const std::string &table) strcpy((char*)buf, table.c_str()); #endif ret = SQLColumns(stmt, nullptr, 0, nullptr, 0, buf, SQL_NTS, nullptr, 0); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on executing column description"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); //std::unique_ptr res(static_cast(execute(stmt))); // bind to columns we need (column name, data type of column and index) @@ -240,22 +245,22 @@ std::vector mssql_connection::describe(const std::string &table) // column name ret = SQLBindCol(stmt, 4, SQL_C_CHAR, column, sizeof(column), &indicator[0]); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (column)"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); // data type ret = SQLBindCol(stmt, 5, SQL_C_SSHORT, &data_type, sizeof(data_type), &indicator[1]); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (data type)"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); // type name ret = SQLBindCol(stmt, 6, SQL_C_CHAR, type, sizeof(type), &indicator[2]); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (type name)"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); // size ret = SQLBindCol(stmt, 7, SQL_C_SLONG, &size, sizeof(size), &indicator[3]); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (data size)"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); // nullable ret = SQLBindCol(stmt, 11, SQL_C_SSHORT, ¬_null, 0, &indicator[4]); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (not null)"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); // index (1 based) ret = SQLBindCol(stmt, 17, SQL_C_SLONG, &pos, 0, &indicator[5]); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "error on sql columns statement (pos)"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); std::vector fields; @@ -329,13 +334,13 @@ basic_dialect* mssql_connection::dialect() void mssql_connection::execute_no_result(const std::string &stmt) { if (!connection_) { - throw_error("mssql", "no odbc connection established"); + throw std::logic_error("mssql no odbc connection established"); } // create statement handle SQLHANDLE handle; SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, connection_, &handle); - throw_error(ret, SQL_HANDLE_DBC, connection_, "mssql", "error on creating sql statement"); + throw_database_error(ret, SQL_HANDLE_DBC, connection_, "mssql", stmt); // execute statement // int retry = retries_; @@ -347,7 +352,7 @@ void mssql_connection::execute_no_result(const std::string &stmt) } while (retry-- && !(SQL_SUCCEEDED(ret) || SQL_NO_DATA)); */ - throw_error(ret, SQL_HANDLE_STMT, handle, stmt, "error on query execute"); + throw_database_error(ret, SQL_HANDLE_STMT, handle, "mssql", stmt); } } diff --git a/src/db/mssql/mssql_exception.cpp b/src/db/mssql/mssql_exception.cpp index 9c21e4eb9..eb65eaad0 100644 --- a/src/db/mssql/mssql_exception.cpp +++ b/src/db/mssql/mssql_exception.cpp @@ -17,8 +17,9 @@ #include "matador/db/mssql/mssql_exception.hpp" +#include "matador/sql/database_error.hpp" + #include -#include #include #include @@ -34,7 +35,7 @@ std::string error_message(const std::string &source, const std::string &sql) return msg.str(); } -void throw_error(SQLRETURN ret, SQLSMALLINT htype, SQLHANDLE hndl, const std::string &source, const std::string &msg) +void throw_database_error(SQLRETURN ret, SQLSMALLINT htype, SQLHANDLE hndl, const std::string &source, const std::string &sql) { if (SQL_SUCCEEDED(ret) || ret == SQL_NO_DATA) { return; @@ -46,39 +47,42 @@ void throw_error(SQLRETURN ret, SQLSMALLINT htype, SQLHANDLE hndl, const std::st ret = SQL_ERROR; SQLSMALLINT i = 0; - std::stringstream text; - do { - ret = SQLGetDiagRec(htype, hndl, ++i, state, &error, data, 511, &over_by); - if (ret == SQL_SUCCESS) { - text << "odbc error [" << state << "] " << msg << " " << i << " (" << error << "): " << data; - } - } while (ret == SQL_SUCCESS); - - throw mssql_exception(source, text.str()); + ret = SQLGetDiagRec(htype, hndl, ++i, state, &error, data, 511, &over_by); + if (ret == SQL_SUCCESS) { + std::string what(reinterpret_cast(data)); + std::string sqlstate(reinterpret_cast(state)); + throw database_error(what, source, sqlstate, error, sql); + } } -void throw_error(const std::string &source, const std::string &sql) -{ - throw mssql_exception(source, sql); -} +//void throw_error(SQLRETURN ret, SQLSMALLINT htype, SQLHANDLE hndl, const std::string &source, const std::string &msg) +//{ +// if (SQL_SUCCEEDED(ret) || ret == SQL_NO_DATA) { +// return; +// } +// SQLCHAR state[6]; +// SQLINTEGER error; +// SQLCHAR data[512]; +// SQLSMALLINT over_by; +// +// ret = SQL_ERROR; +// SQLSMALLINT i = 0; +// std::stringstream text; +// do { +// ret = SQLGetDiagRec(htype, hndl, ++i, state, &error, data, 511, &over_by); +// if (ret == SQL_SUCCESS) { +// text << "odbc error [" << state << "] " << msg << " " << i << " (" << error << "): " << data; +// } +// } while (ret == SQL_SUCCESS); +// +// throw mssql_exception(source, text.str()); +//} bool is_success(SQLRETURN ret) { return ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO; } -mssql_exception::mssql_exception(const std::string &source, const std::string &what) - : sql_exception("mssql", (source + ": " + what).c_str()) -{} - -mssql_stmt_exception::mssql_stmt_exception(const std::string &what) - : sql_exception("mssql", what.c_str()) -{} - -mssql_stmt_exception::mssql_stmt_exception(const std::string &source, const std::string &what) - : sql_exception("mssql", error_message(source, what).c_str()) -{} - } } diff --git a/src/db/mssql/mssql_parameter_binder.cpp b/src/db/mssql/mssql_parameter_binder.cpp index 593cb256e..6d0f478c5 100644 --- a/src/db/mssql/mssql_parameter_binder.cpp +++ b/src/db/mssql/mssql_parameter_binder.cpp @@ -119,14 +119,14 @@ void bind_value(SQLHANDLE stmt, SQLUSMALLINT ctype, SQLUSMALLINT type, mssql_par { SQLLEN buffer_length(0); SQLRETURN ret = SQLBindParameter(stmt, (SQLUSMALLINT)index, SQL_PARAM_INPUT, ctype, type, v->len, 0, v->data, buffer_length, nullptr); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "couldn't bind parameter"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); } void bind_value(SQLHANDLE stmt, SQLUSMALLINT ctype, SQLUSMALLINT type, mssql_parameter_binder::value_t *v, unsigned short scale, size_t index) { SQLLEN buffer_length(0); SQLRETURN ret = SQLBindParameter(stmt, (SQLUSMALLINT)index, SQL_PARAM_INPUT, ctype, type, v->len, scale, v->data, buffer_length, nullptr); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "couldn't bind parameter"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); } mssql_parameter_binder::mssql_parameter_binder(SQLHANDLE stmt) diff --git a/src/db/mssql/mssql_result.cpp b/src/db/mssql/mssql_result.cpp index c0c589603..9bb975b0a 100644 --- a/src/db/mssql/mssql_result.cpp +++ b/src/db/mssql/mssql_result.cpp @@ -36,7 +36,7 @@ mssql_result::mssql_result(SQLHANDLE stmt) // get row and column information SQLLEN r(0); SQLRETURN ret = SQLRowCount(stmt, &r); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "couldn't retrieve row count"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); if (r != SQL_ERROR && r >= 0) { rows = (unsigned long) r; @@ -44,7 +44,7 @@ mssql_result::mssql_result(SQLHANDLE stmt) SQLSMALLINT columns = 0; ret = SQLNumResultCols(stmt, &columns); - throw_error(ret, SQL_HANDLE_STMT, stmt, "mssql", "couldn't get column count"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt, "mssql"); } mssql_result::~mssql_result() @@ -71,7 +71,7 @@ bool mssql_result::fetch() if (SQL_SUCCEEDED(ret)) { return true; } else { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on fetching next row"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); return false; } } @@ -168,7 +168,7 @@ void mssql_result::serialize(const char *, char *x, size_t s) if (ret == SQL_SUCCESS) { return; } else { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } } @@ -210,7 +210,7 @@ void mssql_result::read_column(const char *, std::string &val) if (SQL_SUCCEEDED(ret)) { val.assign(buf, info); } else { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } } @@ -222,7 +222,7 @@ void mssql_result::read_column(const char *, std::string &val, size_t s) if (SQL_SUCCEEDED(ret)) { val.assign(buf.data(), info); } else { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } } @@ -234,7 +234,7 @@ void mssql_result::read_column(const char *, char &val) if (SQL_SUCCEEDED(ret)) { return; } else { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } } @@ -245,7 +245,7 @@ void mssql_result::read_column(const char *, unsigned char &val) if (SQL_SUCCEEDED(ret)) { return; } else { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } } @@ -258,7 +258,7 @@ void mssql_result::read_column(char const *, date &x) if (SQL_SUCCEEDED(ret)) { x.set(ds.day, ds.month, ds.year); } else { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } } @@ -271,7 +271,7 @@ void mssql_result::read_column(char const *, time &x) if (SQL_SUCCEEDED(ret)) { x.set(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fraction / 1000 / 1000); } else { - throw_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", "error on retrieving column value"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql"); } } diff --git a/src/db/mssql/mssql_statement.cpp b/src/db/mssql/mssql_statement.cpp index 584645ad7..16a3cca49 100644 --- a/src/db/mssql/mssql_statement.cpp +++ b/src/db/mssql/mssql_statement.cpp @@ -31,7 +31,7 @@ mssql_statement::mssql_statement(mssql_connection &db, const matador::sql &stmt) , db_(db.handle()) { if (!db_) { - throw_error("mssql", "no odbc connection established"); + throw std::logic_error("mssql no odbc connection established"); } create_statement(); @@ -65,7 +65,7 @@ detail::result_impl* mssql_statement::execute() // get data from map auto it = binder_->data_to_put_map().find(pid); if (it == binder_->data_to_put_map().end()) { - throw_error("mssql", "couldn't find data to put"); + throw std::logic_error("mssql couldn't find data to put"); } mssql_parameter_binder::value_t *val = it->second; // Todo @@ -80,19 +80,19 @@ detail::result_impl* mssql_statement::execute() ret = SQLParamData(stmt_, &pid); if (!is_success(ret) && ret != SQL_NEED_DATA) { // error - throw_error(ret, SQL_HANDLE_STMT, stmt_, "execute->SQLParamData", str()); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", str()); } else if (ret == SQL_NEED_DATA) { // determine next column data pointer it = binder_->data_to_put_map().find(pid); if (it == binder_->data_to_put_map().end()) { - throw_error("mssql", "couldn't find data to put"); + throw std::logic_error("mssql couldn't find data to put"); } val = it->second; } } } else { // check result - throw_error(ret, SQL_HANDLE_STMT, stmt_, str(), "error on query execute"); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", str()); } binder_->reset(); @@ -108,10 +108,10 @@ void mssql_statement::create_statement() { // create statement handle SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, db_, &stmt_); - throw_error(ret, SQL_HANDLE_DBC, db_, "mssql", "error on creating sql statement"); + throw_database_error(ret, SQL_HANDLE_DBC, db_, "mssql"); ret = SQLPrepare(stmt_, (SQLCHAR*)str().c_str(), SQL_NTS); - throw_error(ret, SQL_HANDLE_STMT, stmt_, str()); + throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql", str()); binder_ = matador::make_unique(stmt_); } diff --git a/src/db/mysql/mysql_connection.cpp b/src/db/mysql/mysql_connection.cpp index 80054b0a2..9a742c461 100644 --- a/src/db/mysql/mysql_connection.cpp +++ b/src/db/mysql/mysql_connection.cpp @@ -49,7 +49,7 @@ void mysql_connection::open(const std::string &connection) std::smatch what; if (!std::regex_match(connection, what, DNS_RGX)) { - throw_error("mysql:connect", "invalid dns: " + connection); + throw std::logic_error("mysql:connect invalid dns: " + connection); } const std::string user = what[1].str(); @@ -65,14 +65,14 @@ void mysql_connection::open(const std::string &connection) if (!mysql_init(&mysql_)) { - throw_error("mysql", "initialization failed"); + throw_error(&mysql_, "mysql"); } if (!mysql_real_connect(&mysql_, host.c_str(), user.c_str(), !passwd.empty() ? passwd.c_str() : nullptr, db_.c_str(), port, nullptr, 0)) { // disconnect all handles mysql_close(&mysql_); // throw exception - throw_error(-1, &mysql_, "mysql"); + throw_error(&mysql_, "mysql"); } is_open_ = true; } @@ -138,11 +138,16 @@ std::string mysql_connection::type() const return "mysql"; } -std::string mysql_connection::version() const +std::string mysql_connection::client_version() const { return mysql_get_server_info(const_cast(&mysql_)); } +std::string mysql_connection::server_version() const +{ + return mysql_get_client_info(); +} + bool mysql_connection::exists(const std::string &tablename) { std::string stmt("SHOW TABLES LIKE '" + tablename + "'"); @@ -175,7 +180,7 @@ std::vector mysql_connection::describe(const std::string &table) mysql_result *mysql_connection::execute_internal(const std::string &sql) { if (mysql_query(&mysql_, sql.c_str())) { - throw mysql_exception(&mysql_, "mysql_query", sql); + throw_error(&mysql_, "mysql_query", sql); } return new mysql_result(&mysql_); } diff --git a/src/db/mysql/mysql_exception.cpp b/src/db/mysql/mysql_exception.cpp index 8d93ee97d..3709705ed 100644 --- a/src/db/mysql/mysql_exception.cpp +++ b/src/db/mysql/mysql_exception.cpp @@ -17,71 +17,24 @@ #include "matador/db/mysql/mysql_exception.hpp" +#include "matador/sql/database_error.hpp" + #include -#include namespace matador { namespace mysql { -std::string error_message(MYSQL *db, const std::string &source, const std::string &sql) +void throw_error(MYSQL *db, const std::string &source, const std::string &sql) { - std::stringstream msg; - msg << source << ": " << mysql_error(db) << " (" << sql << ")"; - return msg.str(); + throw database_error(mysql_error(db), source, mysql_errno(db), sql); } -std::string error_message(MYSQL_STMT *stmt, const std::string &source, const std::string &sql) +void throw_stmt_error(MYSQL_STMT *stmt, const std::string &source, const std::string &sql) { - std::stringstream msg; - msg << source << ": " << mysql_stmt_error(stmt) << " (" << sql << ")"; - return msg.str(); + throw database_error(mysql_stmt_error(stmt), source, mysql_stmt_errno(stmt), sql); } -void throw_error(const std::string &source, const std::string &msg) -{ - throw mysql_exception(source, msg); -} - -void throw_error(int ec, MYSQL *db, const std::string &source, const std::string &sql) -{ - if (ec == 0) { - return; - } - throw mysql_exception(db, source, sql); -} - -void throw_stmt_error(int ec, MYSQL_STMT *stmt, const std::string &source, const std::string &sql) -{ - if (ec == 0) { - return; - } - throw mysql_stmt_exception(stmt, source, sql); -} - -mysql_exception::mysql_exception(const std::string &source, const std::string &what) - : sql_exception("mysql", (source + ": " + what).c_str()) -{} - - -mysql_exception::mysql_exception(MYSQL *db, const std::string &source, const std::string &what) - : sql_exception("mysql", error_message(db, source, what).c_str()) -{} - -mysql_exception::~mysql_exception() throw() -{} - -mysql_stmt_exception::mysql_stmt_exception(const std::string &what) - : sql_exception("mysql", what.c_str()) -{} - -mysql_stmt_exception::mysql_stmt_exception(MYSQL_STMT *stmt, const std::string &source, const std::string &what) - : sql_exception("mysql", error_message(stmt, source, what).c_str()) -{} - -mysql_stmt_exception::~mysql_stmt_exception() throw() -{} - } } diff --git a/src/db/mysql/mysql_prepared_result.cpp b/src/db/mysql/mysql_prepared_result.cpp index 81bb9ee06..1c4ac39ee 100644 --- a/src/db/mysql/mysql_prepared_result.cpp +++ b/src/db/mysql/mysql_prepared_result.cpp @@ -67,7 +67,7 @@ bool mysql_prepared_result::prepare_fetch() if (ret == MYSQL_NO_DATA) { return false; } else if (ret == 1) { - throw_stmt_error(ret, stmt, "mysql", ""); + throw_stmt_error(stmt, "mysql", ""); } prepare_binding_ = false; return true; diff --git a/src/db/mysql/mysql_result.cpp b/src/db/mysql/mysql_result.cpp index 71ed61dda..099b0186d 100644 --- a/src/db/mysql/mysql_result.cpp +++ b/src/db/mysql/mysql_result.cpp @@ -36,7 +36,7 @@ mysql_result::mysql_result(MYSQL *c) { res_ = mysql_store_result(c); if (res_ == nullptr && mysql_errno(c) > 0) { - throw_error(-1, c, "mysql", ""); + throw_error(c, "mysql", ""); } else if (res_) { rows_ = (size_type)mysql_num_rows(res_); fields_ = mysql_num_fields(res_); diff --git a/src/db/mysql/mysql_statement.cpp b/src/db/mysql/mysql_statement.cpp index a58690e25..892bcd9f1 100644 --- a/src/db/mysql/mysql_statement.cpp +++ b/src/db/mysql/mysql_statement.cpp @@ -33,9 +33,9 @@ mysql_statement::mysql_statement(mysql_connection &db, const matador::sql &stmt) : statement_impl(db.dialect(), stmt) , stmt_(mysql_stmt_init(db.handle())) { - int res = mysql_stmt_prepare(stmt_, str().c_str(), str().size()); - - throw_stmt_error(res, stmt_, "mysql", str()); + if (mysql_stmt_prepare(stmt_, str().c_str(), str().size()) != 0) { + throw_stmt_error(stmt_, "mysql", str()); + } binder_ = matador::make_unique(columns().size(), bind_vars().size()); } @@ -74,14 +74,17 @@ detail::result_impl* mysql_statement::execute() current_result->free(); } if (!binder_->host_array().empty()) { - int res = mysql_stmt_bind_param(stmt_, binder_->host_array().data()); - throw_stmt_error(res, stmt_, "mysql", str()); + if (mysql_stmt_bind_param(stmt_, binder_->host_array().data()) != 0) { + throw_stmt_error(stmt_, "mysql", str()); + } } - int res = mysql_stmt_execute(stmt_); - throw_stmt_error(res, stmt_, "mysql", str()); - res = mysql_stmt_store_result(stmt_); - throw_stmt_error(res, stmt_, "mysql", str()); + if (mysql_stmt_execute(stmt_) != 0) { + throw_stmt_error(stmt_, "mysql", str()); + } + if (mysql_stmt_store_result(stmt_) != 0) { + throw_stmt_error(stmt_, "mysql", str()); + } current_result = new mysql_prepared_result(this, stmt_, binder_->bindings(), binder_->result_infos()); return current_result; } diff --git a/src/db/postgresql/postgresql_connection.cpp b/src/db/postgresql/postgresql_connection.cpp index 4c4859462..eb4aedcea 100644 --- a/src/db/postgresql/postgresql_connection.cpp +++ b/src/db/postgresql/postgresql_connection.cpp @@ -4,6 +4,9 @@ #include #include +#include + +#include "matador/sql/database_error.hpp" #include "matador/db/postgresql/postgresql_connection.hpp" #include "matador/db/postgresql/postgresql_statement.hpp" @@ -41,7 +44,7 @@ void postgresql_connection::open(const std::string &dns) std::smatch what; if (!std::regex_match(dns, what, DNS_RGX)) { - throw_error("mysql:connect", "invalid dns: " + dns); + throw std::logic_error("mysql:connect invalid dns: " + dns); } const std::string user = what[1].str(); @@ -60,9 +63,8 @@ void postgresql_connection::open(const std::string &dns) conn_ = PQconnectdb(connection.c_str()); if (PQstatus(conn_) == CONNECTION_BAD) { - std::string error = PQerrorMessage(conn_); PQfinish(conn_); - throw postgresql_exception("open", error + "(" + dns + ")"); + throw database_error(PQerrorMessage(conn_), "postgresql", sqlca.sqlstate); } is_open_ = true; @@ -115,7 +117,12 @@ std::string postgresql_connection::type() const return "postgresql"; } -std::string postgresql_connection::version() const +std::string postgresql_connection::client_version() const +{ + return ""; +} + +std::string postgresql_connection::server_version() const { return ""; } @@ -171,10 +178,8 @@ postgresql_result* postgresql_connection::execute_internal(const std::string &st { PGresult *res = PQexec(conn_, stmt.c_str()); - auto status = PQresultStatus(res); - if (status != PGRES_TUPLES_OK && status != PGRES_COMMAND_OK) { - THROW_POSTGRESQL_ERROR(conn_, "execute", "error on sql statement"); - } + throw_database_error(res, conn_, "postgresql", stmt); + return new postgresql_result(res); } diff --git a/src/db/postgresql/postgresql_exception.cpp b/src/db/postgresql/postgresql_exception.cpp index f63d94e3b..2442398bd 100644 --- a/src/db/postgresql/postgresql_exception.cpp +++ b/src/db/postgresql/postgresql_exception.cpp @@ -2,7 +2,9 @@ // Created by sascha on 24.05.19. // -#include +#include "matador/sql/database_error.hpp" + +#include #include "matador/db/postgresql/postgresql_exception.hpp" @@ -10,38 +12,14 @@ namespace matador { namespace postgresql { -std::string error_message(PGconn *db, const std::string &source, const std::string &sql) -{ - std::stringstream msg; - msg << source << ": " << PQerrorMessage(db) << " (" << sql << ")"; - return msg.str(); -} - -void throw_error(const std::string &source, const std::string &msg) +void throw_database_error(PGresult *res, PGconn *db, const std::string &source, const std::string &sql) { - throw postgresql_exception(source, msg); -} - -void throw_error(int ec, PGconn *db, const std::string &source, const std::string &sql) -{ - if (ec == 0) { - return; + if (res == nullptr || + (PQresultStatus(res) != PGRES_COMMAND_OK && + PQresultStatus(res) != PGRES_TUPLES_OK)) { + database_error(PQerrorMessage(db), source, sqlca.sqlstate, sql); } - throw postgresql_exception(db, source, sql); } -postgresql_exception::postgresql_exception(const std::string &source, const std::string &what) - : sql_exception("postgresql", (source + ": " + what).c_str()) -{} - - -postgresql_exception::postgresql_exception(PGconn *db, const std::string &source, const std::string &what) - : sql_exception("postgresql", error_message(db, source, what).c_str()) -{} - -postgresql_stmt_exception::postgresql_stmt_exception(const std::string &what) - : sql_exception("postgresql", what.c_str()) -{} - } } \ No newline at end of file diff --git a/src/db/postgresql/postgresql_statement.cpp b/src/db/postgresql/postgresql_statement.cpp index b36eaa924..935a3620b 100644 --- a/src/db/postgresql/postgresql_statement.cpp +++ b/src/db/postgresql/postgresql_statement.cpp @@ -27,44 +27,9 @@ postgresql_statement::postgresql_statement(postgresql_connection &db, const mata name_ = generate_statement_name(stmt); res_ = PQprepare(db.handle(), name_.c_str(), str().c_str(), bind_vars().size(), nullptr); - if (res_ == nullptr) { - THROW_POSTGRESQL_ERROR(db_.handle(), "execute", "error on sql statement"); - } else if (PQresultStatus(res_) != PGRES_COMMAND_OK) { - THROW_POSTGRESQL_ERROR(db_.handle(), "execute", "error on sql statement"); - } -} -//postgresql_statement::postgresql_statement(const postgresql_statement &x) -// : statement_impl(x) -// , db_(x.db_) -// , result_size(x.result_size) -// , host_size(x.host_size) -// , host_strings_(x.host_strings_) -// , host_params_(x.host_params_) -// , name_(x.name_) -//{ -// if (res_ != nullptr) { -// PQclear(res_); -// } -// res_ = x.res_; -//} -// -//postgresql_statement &postgresql_statement::operator=(const postgresql_statement &x) -//{ -// db_ = x.db_; -// result_size = x.result_size; -// host_index = x.host_index; -// host_size = x.host_size; -// host_strings_ = x.host_strings_; -// host_params_ = x.host_params_; -// name_ = x.name_; -// -// if (res_ != nullptr) { -// PQclear(res_); -// } -// res_ = x.res_; -// return *this; -//} + throw_database_error(res_, db_.handle(), "postgresql", str()); +} postgresql_statement::~postgresql_statement() { @@ -82,10 +47,9 @@ void postgresql_statement::clear() detail::result_impl *postgresql_statement::execute() { PGresult *res = PQexecPrepared(db_.handle(), name_.c_str(), binder_->params().size(), binder_->params().data(), nullptr, nullptr, 0); - auto status = PQresultStatus(res); - if (status != PGRES_TUPLES_OK && status != PGRES_COMMAND_OK) { - THROW_POSTGRESQL_ERROR(db_.handle(), "execute", "error on sql statement"); - } + + throw_database_error(res, db_.handle(), "postgresql", str()); + return new postgresql_prepared_result(this, res); } diff --git a/src/db/sqlite/sqlite_connection.cpp b/src/db/sqlite/sqlite_connection.cpp index 81027fae5..8ffcd10f5 100644 --- a/src/db/sqlite/sqlite_connection.cpp +++ b/src/db/sqlite/sqlite_connection.cpp @@ -45,9 +45,8 @@ sqlite_connection::~sqlite_connection() void sqlite_connection::open(const std::string &db) { int ret = sqlite3_open(db.c_str(), &sqlite_db_); - if (ret != SQLITE_OK) { - throw sqlite_exception("couldn't connect sql: " + db); - } + + throw_database_error(ret, sqlite_db_, "sqlite"); } bool sqlite_connection::is_open() const @@ -58,8 +57,8 @@ bool sqlite_connection::is_open() const void sqlite_connection::close() { int ret = sqlite3_close(sqlite_db_); - - throw_error(ret, sqlite_db_, "sqlite_close"); + + throw_database_error(ret, sqlite_db_, "sqlite_close"); sqlite_db_ = nullptr; } @@ -89,7 +88,12 @@ std::string sqlite_connection::type() const return "sqlite"; } -std::string sqlite_connection::version() const +std::string sqlite_connection::client_version() const +{ + return SQLITE_VERSION; +} + +std::string sqlite_connection::server_version() const { return SQLITE_VERSION; } @@ -180,11 +184,9 @@ sqlite_result *sqlite_connection::execute_internal(const std::string &stmt) std::unique_ptr res(new sqlite_result); char *errmsg = nullptr; int ret = sqlite3_exec(sqlite_db_, stmt.c_str(), parse_result, res.get(), &errmsg); - if (ret != SQLITE_OK) { - std::string error(errmsg); - sqlite3_free(errmsg); - throw sqlite_exception(error); - } + + throw_database_error(ret, sqlite_db_, "sqlite", stmt); + return res.release(); } } diff --git a/src/db/sqlite/sqlite_exception.cpp b/src/db/sqlite/sqlite_exception.cpp index 8e65207c9..d27a53bb4 100644 --- a/src/db/sqlite/sqlite_exception.cpp +++ b/src/db/sqlite/sqlite_exception.cpp @@ -15,7 +15,7 @@ * along with OpenObjectStore OOS. If not, see . */ -#include +#include "matador/sql/database_error.hpp" #include "matador/db/sqlite/sqlite_exception.hpp" @@ -23,23 +23,14 @@ namespace matador { namespace sqlite { -void throw_error(int ec, sqlite3 *db, const std::string &source, const std::string &sql) +void throw_error(int ec, sqlite3 *db, const std::string &sql) { if (ec == SQLITE_OK) { return; } - std::stringstream msg; - msg << source << ": " << sqlite3_errmsg(db); - if (!sql.empty()) { - msg << " (" << sql << ")"; - } - throw sqlite_exception(msg.str()); + throw database_error(sqlite3_errmsg(db), "sqlite", sqlite3_errcode(db), sql); } -sqlite_exception::sqlite_exception(const std::string &what) - : sql_exception("sqlite", what.c_str()) -{} - } } diff --git a/src/db/sqlite/sqlite_parameter_binder.cpp b/src/db/sqlite/sqlite_parameter_binder.cpp index 34593a7a6..f2fd97a5f 100644 --- a/src/db/sqlite/sqlite_parameter_binder.cpp +++ b/src/db/sqlite/sqlite_parameter_binder.cpp @@ -42,79 +42,79 @@ size_t sqlite_parameter_binder::current_index() const void sqlite_parameter_binder::bind(char i, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(short i, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(int i, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(long i, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(long long i, size_t index) { int ret = sqlite3_bind_int64(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(unsigned char i, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(unsigned short i, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(unsigned int i, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(unsigned long i, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(unsigned long long i, size_t index) { int ret = sqlite3_bind_int64(stmt_, (int)index, i); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(bool b, size_t index) { int ret = sqlite3_bind_int(stmt_, (int)index, b); - throw_error(ret, db_, "sqlite3_bind_int"); + throw_database_error(ret, db_, "sqlite3_bind_int"); } void sqlite_parameter_binder::bind(float d, size_t index) { int ret = sqlite3_bind_double(stmt_, (int)index, d); - throw_error(ret, db_, "sqlite3_bind_double"); + throw_database_error(ret, db_, "sqlite3_bind_double"); } void sqlite_parameter_binder::bind(double d, size_t index) { int ret = sqlite3_bind_double(stmt_, (int)index, d); - throw_error(ret, db_, "sqlite3_bind_double"); + throw_database_error(ret, db_, "sqlite3_bind_double"); } void sqlite_parameter_binder::bind(const char *x, size_t len, size_t index) @@ -122,13 +122,13 @@ void sqlite_parameter_binder::bind(const char *x, size_t len, size_t index) auto size = strlen(x); len = (size > len) ? len : size; int ret = sqlite3_bind_text(stmt_, (int)index, x, (int)len, nullptr); - throw_error(ret, db_, "sqlite3_bind_text"); + throw_database_error(ret, db_, "sqlite3_bind_text"); } void sqlite_parameter_binder::bind(const std::string &x, size_t index) { int ret = sqlite3_bind_text(stmt_, (int)index, x.c_str(), (int)x.size(), nullptr); - throw_error(ret, db_, "sqlite3_bind_text"); + throw_database_error(ret, db_, "sqlite3_bind_text"); } void sqlite_parameter_binder::bind(const std::string &x, size_t len, size_t index) @@ -136,7 +136,7 @@ void sqlite_parameter_binder::bind(const std::string &x, size_t len, size_t inde auto size = x.size(); len = (size > len) ? len : size; int ret = sqlite3_bind_text(stmt_, (int)index, x.data(), (int)len, nullptr); - throw_error(ret, db_, "sqlite3_bind_text"); + throw_database_error(ret, db_, "sqlite3_bind_text"); } void sqlite_parameter_binder::bind(const matador::time &x, size_t index) diff --git a/src/db/sqlite/sqlite_prepared_result.cpp b/src/db/sqlite/sqlite_prepared_result.cpp index 213c1c167..428b73bed 100644 --- a/src/db/sqlite/sqlite_prepared_result.cpp +++ b/src/db/sqlite/sqlite_prepared_result.cpp @@ -186,7 +186,7 @@ bool sqlite_prepared_result::prepare_fetch() ret_ = sqlite3_step(stmt_); if (ret_ != SQLITE_DONE && ret_ != SQLITE_ROW) { sqlite3 *db = sqlite3_db_handle(stmt_); - throw_error(ret_, db, "sqlite3_step"); + throw_database_error(ret_, db, "sqlite3_step"); } } else { first_ = false; diff --git a/src/db/sqlite/sqlite_statement.cpp b/src/db/sqlite/sqlite_statement.cpp index 6eb5a662c..38b581f3d 100644 --- a/src/db/sqlite/sqlite_statement.cpp +++ b/src/db/sqlite/sqlite_statement.cpp @@ -37,7 +37,7 @@ sqlite_statement::sqlite_statement(sqlite_connection &db, const matador::sql &sq { // prepare sqlite statement int ret = sqlite3_prepare_v2(db_.handle(), str().c_str(), str().size(), &stmt_, nullptr); - throw_error(ret, db_.handle(), "sqlite3_prepare_v2", str()); + throw_database_error(ret, db_.handle(), "sqlite3_prepare_v2", str()); binder_ = matador::make_unique(db.handle(), stmt_); } @@ -53,7 +53,7 @@ detail::result_impl* sqlite_statement::execute() int ret = sqlite3_step(stmt_); if (ret != SQLITE_ROW && ret != SQLITE_DONE) { - throw_error(ret, db_.handle(), "sqlite3_step"); + throw_database_error(ret, db_.handle(), "sqlite3_step"); } return new sqlite_prepared_result(stmt_, ret); } @@ -72,7 +72,7 @@ void sqlite_statement::clear() return; } int ret = sqlite3_finalize(stmt_); - throw_error(ret, db_.handle(), "sqlite3_finalize"); + throw_database_error(ret, db_.handle(), "sqlite3_finalize"); stmt_ = nullptr; } diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index fb520ef04..7ed67c583 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -23,7 +23,7 @@ SET(SOURCES type.cpp query_value_column_processor.cpp query_value_creator.cpp - connection_impl.cpp value_visitor.cpp) + connection_impl.cpp value_visitor.cpp database_error.cpp) SET(HEADER ${CMAKE_SOURCE_DIR}/include/matador/sql/condition.hpp @@ -57,7 +57,7 @@ SET(HEADER ${CMAKE_SOURCE_DIR}/include/matador/sql/basic_dialect_compiler.hpp ${CMAKE_SOURCE_DIR}/include/matador/sql/basic_dialect_linker.hpp ${CMAKE_SOURCE_DIR}/include/matador/sql/query_value_column_processor.hpp - ${CMAKE_SOURCE_DIR}/include/matador/sql/query_value_creator.hpp ../../include/matador/sql/parameter_binder.hpp ../../include/matador/sql/value_visitor.hpp) + ${CMAKE_SOURCE_DIR}/include/matador/sql/query_value_creator.hpp ../../include/matador/sql/parameter_binder.hpp ../../include/matador/sql/value_visitor.hpp ../../include/matador/sql/database_error.hpp) ADD_LIBRARY(matador-sql SHARED ${SOURCES} ${HEADER}) diff --git a/src/sql/database_error.cpp b/src/sql/database_error.cpp new file mode 100644 index 000000000..fdfbc002e --- /dev/null +++ b/src/sql/database_error.cpp @@ -0,0 +1,53 @@ +// +// Created by sascha on 28.12.19. +// + +#include "matador/sql/database_error.hpp" + +#include + +namespace matador { + +database_error::database_error(const std::string &what, std::string source, long ec, std::string sql) + : std::runtime_error(what) + , source_(std::move(source)) + , error_code_(ec) + , sql_stmt_(std::move(sql)) +{} + +database_error::database_error(const std::string &what, std::string source, std::string sqlstate, long ec, + std::string sql) + : std::runtime_error(what) + , source_(std::move(source)) + , error_code_(ec) + , sqlstate_(std::move(sqlstate)) + , sql_stmt_(std::move(sql)) +{} + +database_error::database_error(const std::string &what, std::string source, std::string sqlstate, std::string sql) + : std::runtime_error(what) + , source_(std::move(source)) + , sqlstate_(std::move(sqlstate)) + , sql_stmt_(std::move(sql)) +{} + +const char *database_error::source() const noexcept +{ + return source_.c_str(); +} + +long database_error::error_code() const noexcept +{ + return error_code_; +} + +const char *database_error::sql_state() const noexcept +{ + return sqlstate_.c_str(); +} + +const char *database_error::sql_statement() const noexcept +{ + return sql_stmt_.c_str(); +} +} \ No newline at end of file diff --git a/test/sql/ConnectionTestUnit.cpp b/test/sql/ConnectionTestUnit.cpp index f1d31c5b6..fff92b0e6 100644 --- a/test/sql/ConnectionTestUnit.cpp +++ b/test/sql/ConnectionTestUnit.cpp @@ -18,6 +18,7 @@ #include "ConnectionTestUnit.hpp" #include "matador/sql/connection.hpp" +#include "matador/sql/database_error.hpp" #include @@ -27,10 +28,12 @@ using namespace std; ConnectionTestUnit::ConnectionTestUnit(const std::string &prefix, std::string dns) : unit_test(prefix + "_conn", prefix + " connection test unit") , dns_(std::move(dns)) + , db_vendor_(prefix) { add_test("open_close", std::bind(&ConnectionTestUnit::test_open_close, this), "connect sql test"); add_test("reopen", std::bind(&ConnectionTestUnit::test_reopen, this), "reopen sql test"); add_test("reconnect", std::bind(&ConnectionTestUnit::test_reconnect, this), "reconnect sql test"); + add_test("connection_failed", std::bind(&ConnectionTestUnit::test_connection_failed, this), "connection failed test"); } void ConnectionTestUnit::test_open_close() @@ -88,6 +91,24 @@ void ConnectionTestUnit::test_reconnect() UNIT_ASSERT_FALSE(conn.is_connected()); } +void ConnectionTestUnit::test_connection_failed() +{ + string dns = db_vendor_ + "://sa:Sa%%docker18@127.0.0.1/matador_test (FreeTDS)"; + + matador::connection conn(dns); + + bool caught_exception = false; + try { + conn.connect(); + } catch (database_error &ex) { + caught_exception = true; + UNIT_EXPECT_EQUAL("42000", ex.sql_state()); + } catch (...) { + UNIT_FAIL("caught from exception"); + } + UNIT_ASSERT_TRUE(caught_exception); +} + std::string ConnectionTestUnit::connection_string() { return dns_; diff --git a/test/sql/ConnectionTestUnit.hpp b/test/sql/ConnectionTestUnit.hpp index 0e2dfc921..e77a1f9b1 100644 --- a/test/sql/ConnectionTestUnit.hpp +++ b/test/sql/ConnectionTestUnit.hpp @@ -33,12 +33,14 @@ class ConnectionTestUnit : public matador::unit_test void test_open_close(); void test_reopen(); void test_reconnect(); + void test_connection_failed(); protected: std::string connection_string(); private: std::string dns_; + std::string db_vendor_; }; #endif /* SESSION_TEST_UNIT_HPP */ \ No newline at end of file From 762c1f755d6632e580325388e21609403592a742 Mon Sep 17 00:00:00 2001 From: zussel Date: Thu, 2 Jan 2020 07:27:12 +0100 Subject: [PATCH 02/18] fixed mysql bool type --- include/matador/db/mysql/mysql_bool.hpp | 29 +++++++++++++++++ include/matador/db/mysql/mysql_constants.hpp | 5 --- .../db/mysql/mysql_parameter_binder.hpp | 4 ++- .../db/mysql/mysql_prepared_result.hpp | 7 ++-- .../matador/db/mysql/mysql_result_info.hpp | 4 +-- src/db/mysql/CMakeLists.txt | 2 +- src/db/mysql/mysql_parameter_binder.cpp | 16 +++++----- src/db/mysql/mysql_prepared_result.cpp | 32 ++++++++++++------- 8 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 include/matador/db/mysql/mysql_bool.hpp diff --git a/include/matador/db/mysql/mysql_bool.hpp b/include/matador/db/mysql/mysql_bool.hpp new file mode 100644 index 000000000..e77e03328 --- /dev/null +++ b/include/matador/db/mysql/mysql_bool.hpp @@ -0,0 +1,29 @@ +// +// Created by sascha on 02.01.20. +// + +#ifndef MATADOR_MYSQL_BOOL_HPP +#define MATADOR_MYSQL_BOOL_HPP + +#include + +namespace matador { + +namespace mysql { + +typedef std::vector t_bool_vector; + +template < class T > +void set_my_bool(T &mybool, t_bool_vector::reference ref_bool) { + mybool = decltype(mybool)(&ref_bool); +} + +template < class T > +void set_my_bool(T &mybool, bool &b) { + mybool = decltype(mybool)(b); +} + +} +} + +#endif //MATADOR_MYSQL_BOOL_HPP diff --git a/include/matador/db/mysql/mysql_constants.hpp b/include/matador/db/mysql/mysql_constants.hpp index 0e555149f..f8f296a27 100644 --- a/include/matador/db/mysql/mysql_constants.hpp +++ b/include/matador/db/mysql/mysql_constants.hpp @@ -18,11 +18,6 @@ class mysql static const long version = MYSQL_VERSION_ID; }; -#if MYSQL_VERSION_ID >= 80000 -typedef bool mysql_bool; -#else -typedef my_bool bool; -#endif } } #endif /* MYSQL_CONSTANTS_HPP */ \ No newline at end of file diff --git a/include/matador/db/mysql/mysql_parameter_binder.hpp b/include/matador/db/mysql/mysql_parameter_binder.hpp index 5c8cd1930..e7341dcf8 100644 --- a/include/matador/db/mysql/mysql_parameter_binder.hpp +++ b/include/matador/db/mysql/mysql_parameter_binder.hpp @@ -8,6 +8,7 @@ #include "matador/sql/parameter_binder.hpp" #include "matador/db/mysql/mysql_result_info.hpp" +#include "matador/db/mysql/mysql_bool.hpp" #ifdef _MSC_VER #include @@ -55,10 +56,11 @@ class mysql_parameter_binder : public detail::parameter_binder_impl std::vector& bindings(); std::vector& result_infos(); + private: std::vector host_array_; std::vector bind_; - std::vector is_null_vector; + t_bool_vector is_null_vector; std::vector info_; size_t index_ = 0; diff --git a/include/matador/db/mysql/mysql_prepared_result.hpp b/include/matador/db/mysql/mysql_prepared_result.hpp index 6bd4e5794..c997ed93b 100644 --- a/include/matador/db/mysql/mysql_prepared_result.hpp +++ b/include/matador/db/mysql/mysql_prepared_result.hpp @@ -4,6 +4,7 @@ #include "matador/sql/result_impl.hpp" #include "matador/db/mysql/mysql_result_info.hpp" +#include "matador/db/mysql/mysql_bool.hpp" #ifdef _MSC_VER //#include @@ -89,9 +90,11 @@ class mysql_prepared_result : public detail::result_impl bind_[index].buffer= (char *)&value; bind_[index].buffer_length = sizeof(T); bind_[index].buffer_type = type; - bind_[index].is_null = &info_[index].is_null; + set_my_bool(bind_[index].is_null, info_[index].is_null); +// bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - bind_[index].error = &info_[index].error; + set_my_bool(bind_[index].error, info_[index].error); +// bind_[index].error = &info_[index].error; } void prepare_bind_column(int index, enum_field_types type, matador::date &value); diff --git a/include/matador/db/mysql/mysql_result_info.hpp b/include/matador/db/mysql/mysql_result_info.hpp index 2b5605a96..9d82eb558 100644 --- a/include/matador/db/mysql/mysql_result_info.hpp +++ b/include/matador/db/mysql/mysql_result_info.hpp @@ -16,8 +16,8 @@ namespace mysql { struct mysql_result_info { unsigned long length = 0; - my_bool is_null = false; - my_bool error = false; + bool is_null = false; + bool error = false; char *buffer = nullptr; unsigned long buffer_length = 0; bool is_allocated = false; diff --git a/src/db/mysql/CMakeLists.txt b/src/db/mysql/CMakeLists.txt index 82ab64a01..51d0c25ac 100644 --- a/src/db/mysql/CMakeLists.txt +++ b/src/db/mysql/CMakeLists.txt @@ -18,7 +18,7 @@ SET(HEADER ../../../include/matador/db/mysql/mysql_types.hpp ../../../include/matador/db/mysql/mysql_dialect.hpp ../../../include/matador/db/mysql/mysql_constants.hpp - ../../../include/matador/db/mysql/mysql_parameter_binder.hpp) + ../../../include/matador/db/mysql/mysql_parameter_binder.hpp ../../../include/matador/db/mysql/mysql_bool.hpp) ADD_LIBRARY(matador-mysql SHARED ${SOURCES} ${HEADER}) diff --git a/src/db/mysql/mysql_parameter_binder.cpp b/src/db/mysql/mysql_parameter_binder.cpp index 3dc2950c3..3b5e36da9 100644 --- a/src/db/mysql/mysql_parameter_binder.cpp +++ b/src/db/mysql/mysql_parameter_binder.cpp @@ -15,21 +15,21 @@ namespace matador { namespace mysql { template < class T > -void bind_value(enum_field_types type, T value, MYSQL_BIND &bind, my_bool &is_null) +void bind_value(enum_field_types type, T value, MYSQL_BIND &bind, t_bool_vector::reference is_null) { if (bind.buffer == nullptr) { // allocating memory bind.buffer = new char[sizeof(T)]; bind.buffer_type = type; bind.buffer_length = sizeof(T); - bind.is_null = &is_null; + bind.is_null = decltype(bind.is_null)(&is_null); bind.is_unsigned = std::is_unsigned::value; } *static_cast(bind.buffer) = value; is_null = false; } -void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bind, my_bool &is_null) +void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bind, t_bool_vector::reference is_null) { std::size_t len(strlen(value) + 1); if (bind.buffer_length < len) { @@ -38,7 +38,7 @@ void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bi bind.buffer = nullptr; bind.buffer_length = 0; bind.buffer_type = type; - bind.is_null = &is_null; + bind.is_null = decltype(bind.is_null)(&is_null); } if (bind.buffer == nullptr) { // allocating memory @@ -54,13 +54,13 @@ void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bi is_null = false; } -void bind_value(enum_field_types type, const matador::date &x, MYSQL_BIND &bind, my_bool &is_null) +void bind_value(enum_field_types type, const matador::date &x, MYSQL_BIND &bind, t_bool_vector::reference is_null) { if (bind.buffer == nullptr) { size_t s = sizeof(MYSQL_TIME); bind.buffer = new char[s]; bind.buffer_length = (unsigned long)s; - bind.is_null = &is_null; + bind.is_null = decltype(bind.is_null)(&is_null); bind.buffer_type = type; bind.length = nullptr; } @@ -73,7 +73,7 @@ void bind_value(enum_field_types type, const matador::date &x, MYSQL_BIND &bind, mt->time_type = MYSQL_TIMESTAMP_DATE; } -void bind_value(enum_field_types type, const matador::time &x, MYSQL_BIND &bind, my_bool &is_null) +void bind_value(enum_field_types type, const matador::time &x, MYSQL_BIND &bind, t_bool_vector::reference is_null) { if (bind.buffer == nullptr) { size_t s = sizeof(MYSQL_TIME); @@ -81,7 +81,7 @@ void bind_value(enum_field_types type, const matador::time &x, MYSQL_BIND &bind, bind.buffer_length = (unsigned long)s; bind.buffer_type = type; bind.length = nullptr; - bind.is_null = &is_null; + bind.is_null = decltype(bind.is_null)(&is_null); } memset(bind.buffer, 0, sizeof(MYSQL_TIME)); is_null = false; diff --git a/src/db/mysql/mysql_prepared_result.cpp b/src/db/mysql/mysql_prepared_result.cpp index 1c4ac39ee..2f3213e58 100644 --- a/src/db/mysql/mysql_prepared_result.cpp +++ b/src/db/mysql/mysql_prepared_result.cpp @@ -373,9 +373,11 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_type = type; bind_[index].buffer = info_[index].buffer; bind_[index].buffer_length = info_[index].buffer_length; - bind_[index].is_null = &info_[index].is_null; + set_my_bool(bind_[index].is_null, info_[index].is_null); +// bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - bind_[index].error = &info_[index].error; + set_my_bool(bind_[index].error, info_[index].error); +// bind_[index].error = &info_[index].error; } void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type, matador::time &) @@ -390,9 +392,11 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_type = type; bind_[index].buffer = info_[index].buffer; bind_[index].buffer_length = info_[index].buffer_length; - bind_[index].is_null = &info_[index].is_null; + set_my_bool(bind_[index].is_null, info_[index].is_null); +// bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - bind_[index].error = &info_[index].error; + set_my_bool(bind_[index].error, info_[index].error); +// bind_[index].error = &info_[index].error; } void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type, std::string & /*value*/) @@ -400,9 +404,11 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_type = type; bind_[index].buffer = nullptr; bind_[index].buffer_length = 0; - bind_[index].is_null = &info_[index].is_null; + set_my_bool(bind_[index].is_null, info_[index].is_null); +// bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - bind_[index].error = &info_[index].error; + set_my_bool(bind_[index].error, info_[index].error); +// bind_[index].error = &info_[index].error; } void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type, char *x, size_t s) @@ -410,9 +416,11 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_type = type; bind_[index].buffer= x; bind_[index].buffer_length = (unsigned long) s; - bind_[index].is_null = &info_[index].is_null; + set_my_bool(bind_[index].is_null, info_[index].is_null); +// bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - bind_[index].error = &info_[index].error; + set_my_bool(bind_[index].error, info_[index].error); +// bind_[index].error = &info_[index].error; } void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type, std::string & /*value*/, size_t s) @@ -428,10 +436,12 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_length = info_[index].buffer_length; bind_[index].buffer = nullptr; bind_[index].buffer_length = 0; - bind_[index].is_null = &info_[index].is_null; + set_my_bool(bind_[index].is_null, info_[index].is_null); +// bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - bind_[index].error = &info_[index].error;} - + set_my_bool(bind_[index].error, info_[index].error); +// bind_[index].error = &info_[index].error; } } +} From 9869f4ede37be748102fa92fce55a84b016902f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 2 Jan 2020 10:55:49 +0100 Subject: [PATCH 03/18] handle my_bool for mysql 8 --- include/matador/db/mysql/mysql_bool.hpp | 23 ++------------ .../db/mysql/mysql_parameter_binder.hpp | 2 +- .../db/mysql/mysql_prepared_result.hpp | 6 ++-- .../matador/db/mysql/mysql_result_info.hpp | 6 ++-- src/db/mysql/mysql_parameter_binder.cpp | 8 ++--- src/db/mysql/mysql_prepared_result.cpp | 30 +++++++------------ 6 files changed, 24 insertions(+), 51 deletions(-) diff --git a/include/matador/db/mysql/mysql_bool.hpp b/include/matador/db/mysql/mysql_bool.hpp index e77e03328..e1803a77e 100644 --- a/include/matador/db/mysql/mysql_bool.hpp +++ b/include/matador/db/mysql/mysql_bool.hpp @@ -5,25 +5,8 @@ #ifndef MATADOR_MYSQL_BOOL_HPP #define MATADOR_MYSQL_BOOL_HPP -#include - -namespace matador { - -namespace mysql { - -typedef std::vector t_bool_vector; - -template < class T > -void set_my_bool(T &mybool, t_bool_vector::reference ref_bool) { - mybool = decltype(mybool)(&ref_bool); -} - -template < class T > -void set_my_bool(T &mybool, bool &b) { - mybool = decltype(mybool)(b); -} - -} -} +#if !MARIADB_PACKAGE_VERSION_ID && MYSQL_VERSION_ID >= 80001 +typedef bool my_bool; +#endif #endif //MATADOR_MYSQL_BOOL_HPP diff --git a/include/matador/db/mysql/mysql_parameter_binder.hpp b/include/matador/db/mysql/mysql_parameter_binder.hpp index e7341dcf8..334923079 100644 --- a/include/matador/db/mysql/mysql_parameter_binder.hpp +++ b/include/matador/db/mysql/mysql_parameter_binder.hpp @@ -60,7 +60,7 @@ class mysql_parameter_binder : public detail::parameter_binder_impl private: std::vector host_array_; std::vector bind_; - t_bool_vector is_null_vector; + std::vector is_null_vector; std::vector info_; size_t index_ = 0; diff --git a/include/matador/db/mysql/mysql_prepared_result.hpp b/include/matador/db/mysql/mysql_prepared_result.hpp index c997ed93b..e98ea10ad 100644 --- a/include/matador/db/mysql/mysql_prepared_result.hpp +++ b/include/matador/db/mysql/mysql_prepared_result.hpp @@ -90,11 +90,9 @@ class mysql_prepared_result : public detail::result_impl bind_[index].buffer= (char *)&value; bind_[index].buffer_length = sizeof(T); bind_[index].buffer_type = type; - set_my_bool(bind_[index].is_null, info_[index].is_null); -// bind_[index].is_null = &info_[index].is_null; + bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - set_my_bool(bind_[index].error, info_[index].error); -// bind_[index].error = &info_[index].error; + bind_[index].error = &info_[index].error; } void prepare_bind_column(int index, enum_field_types type, matador::date &value); diff --git a/include/matador/db/mysql/mysql_result_info.hpp b/include/matador/db/mysql/mysql_result_info.hpp index 9d82eb558..6878ffb2e 100644 --- a/include/matador/db/mysql/mysql_result_info.hpp +++ b/include/matador/db/mysql/mysql_result_info.hpp @@ -1,6 +1,8 @@ #ifndef MYSQL_RESULT_INFO_HPP #define MYSQL_RESULT_INFO_HPP +#include "matador/db/mysql/mysql_bool.hpp" + #ifdef _MSC_VER #include #else @@ -16,8 +18,8 @@ namespace mysql { struct mysql_result_info { unsigned long length = 0; - bool is_null = false; - bool error = false; + my_bool is_null = false; + my_bool error = false; char *buffer = nullptr; unsigned long buffer_length = 0; bool is_allocated = false; diff --git a/src/db/mysql/mysql_parameter_binder.cpp b/src/db/mysql/mysql_parameter_binder.cpp index 3b5e36da9..fbe9525ba 100644 --- a/src/db/mysql/mysql_parameter_binder.cpp +++ b/src/db/mysql/mysql_parameter_binder.cpp @@ -15,7 +15,7 @@ namespace matador { namespace mysql { template < class T > -void bind_value(enum_field_types type, T value, MYSQL_BIND &bind, t_bool_vector::reference is_null) +void bind_value(enum_field_types type, T value, MYSQL_BIND &bind, my_bool &is_null) { if (bind.buffer == nullptr) { // allocating memory @@ -29,7 +29,7 @@ void bind_value(enum_field_types type, T value, MYSQL_BIND &bind, t_bool_vector: is_null = false; } -void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bind, t_bool_vector::reference is_null) +void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bind, my_bool &is_null) { std::size_t len(strlen(value) + 1); if (bind.buffer_length < len) { @@ -54,7 +54,7 @@ void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bi is_null = false; } -void bind_value(enum_field_types type, const matador::date &x, MYSQL_BIND &bind, t_bool_vector::reference is_null) +void bind_value(enum_field_types type, const matador::date &x, MYSQL_BIND &bind, my_bool &is_null) { if (bind.buffer == nullptr) { size_t s = sizeof(MYSQL_TIME); @@ -73,7 +73,7 @@ void bind_value(enum_field_types type, const matador::date &x, MYSQL_BIND &bind, mt->time_type = MYSQL_TIMESTAMP_DATE; } -void bind_value(enum_field_types type, const matador::time &x, MYSQL_BIND &bind, t_bool_vector::reference is_null) +void bind_value(enum_field_types type, const matador::time &x, MYSQL_BIND &bind, my_bool &is_null) { if (bind.buffer == nullptr) { size_t s = sizeof(MYSQL_TIME); diff --git a/src/db/mysql/mysql_prepared_result.cpp b/src/db/mysql/mysql_prepared_result.cpp index 2f3213e58..1a9fd35bd 100644 --- a/src/db/mysql/mysql_prepared_result.cpp +++ b/src/db/mysql/mysql_prepared_result.cpp @@ -373,11 +373,9 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_type = type; bind_[index].buffer = info_[index].buffer; bind_[index].buffer_length = info_[index].buffer_length; - set_my_bool(bind_[index].is_null, info_[index].is_null); -// bind_[index].is_null = &info_[index].is_null; + bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - set_my_bool(bind_[index].error, info_[index].error); -// bind_[index].error = &info_[index].error; + bind_[index].error = &info_[index].error; } void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type, matador::time &) @@ -392,11 +390,9 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_type = type; bind_[index].buffer = info_[index].buffer; bind_[index].buffer_length = info_[index].buffer_length; - set_my_bool(bind_[index].is_null, info_[index].is_null); -// bind_[index].is_null = &info_[index].is_null; + bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - set_my_bool(bind_[index].error, info_[index].error); -// bind_[index].error = &info_[index].error; + bind_[index].error = &info_[index].error; } void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type, std::string & /*value*/) @@ -404,11 +400,9 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_type = type; bind_[index].buffer = nullptr; bind_[index].buffer_length = 0; - set_my_bool(bind_[index].is_null, info_[index].is_null); -// bind_[index].is_null = &info_[index].is_null; + bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - set_my_bool(bind_[index].error, info_[index].error); -// bind_[index].error = &info_[index].error; + bind_[index].error = &info_[index].error; } void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type, char *x, size_t s) @@ -416,11 +410,9 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_type = type; bind_[index].buffer= x; bind_[index].buffer_length = (unsigned long) s; - set_my_bool(bind_[index].is_null, info_[index].is_null); -// bind_[index].is_null = &info_[index].is_null; + bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - set_my_bool(bind_[index].error, info_[index].error); -// bind_[index].error = &info_[index].error; + bind_[index].error = &info_[index].error; } void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type, std::string & /*value*/, size_t s) @@ -436,11 +428,9 @@ void mysql_prepared_result::prepare_bind_column(int index, enum_field_types type bind_[index].buffer_length = info_[index].buffer_length; bind_[index].buffer = nullptr; bind_[index].buffer_length = 0; - set_my_bool(bind_[index].is_null, info_[index].is_null); -// bind_[index].is_null = &info_[index].is_null; + bind_[index].is_null = &info_[index].is_null; bind_[index].length = &info_[index].length; - set_my_bool(bind_[index].error, info_[index].error); -// bind_[index].error = &info_[index].error; + bind_[index].error = &info_[index].error; } } From 9a088695d9c513efd4324f157f20b8e78a38f7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 2 Jan 2020 10:56:27 +0100 Subject: [PATCH 04/18] added sqlstate for mysql database error --- src/db/mysql/mysql_exception.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/mysql/mysql_exception.cpp b/src/db/mysql/mysql_exception.cpp index 3709705ed..5891cbd9c 100644 --- a/src/db/mysql/mysql_exception.cpp +++ b/src/db/mysql/mysql_exception.cpp @@ -27,12 +27,12 @@ namespace mysql { void throw_error(MYSQL *db, const std::string &source, const std::string &sql) { - throw database_error(mysql_error(db), source, mysql_errno(db), sql); + throw database_error(mysql_error(db), source, mysql_sqlstate(db), mysql_errno(db), sql); } void throw_stmt_error(MYSQL_STMT *stmt, const std::string &source, const std::string &sql) { - throw database_error(mysql_stmt_error(stmt), source, mysql_stmt_errno(stmt), sql); + throw database_error(mysql_stmt_error(stmt), source, mysql_stmt_sqlstate(stmt), mysql_stmt_errno(stmt), sql); } } From f850c75a5550c9200e05deba3c0496fccf73af2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 2 Jan 2020 10:56:59 +0100 Subject: [PATCH 05/18] added sqlstate database error for postgresql --- src/db/postgresql/postgresql_connection.cpp | 4 ++-- src/db/postgresql/postgresql_exception.cpp | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/db/postgresql/postgresql_connection.cpp b/src/db/postgresql/postgresql_connection.cpp index eb4aedcea..10b2170c6 100644 --- a/src/db/postgresql/postgresql_connection.cpp +++ b/src/db/postgresql/postgresql_connection.cpp @@ -4,7 +4,6 @@ #include #include -#include #include "matador/sql/database_error.hpp" @@ -63,8 +62,9 @@ void postgresql_connection::open(const std::string &dns) conn_ = PQconnectdb(connection.c_str()); if (PQstatus(conn_) == CONNECTION_BAD) { + std::string msg = PQerrorMessage(conn_); PQfinish(conn_); - throw database_error(PQerrorMessage(conn_), "postgresql", sqlca.sqlstate); + throw database_error(msg, "postgresql", "42000"); } is_open_ = true; diff --git a/src/db/postgresql/postgresql_exception.cpp b/src/db/postgresql/postgresql_exception.cpp index 2442398bd..813f0cb20 100644 --- a/src/db/postgresql/postgresql_exception.cpp +++ b/src/db/postgresql/postgresql_exception.cpp @@ -4,8 +4,6 @@ #include "matador/sql/database_error.hpp" -#include - #include "matador/db/postgresql/postgresql_exception.hpp" namespace matador { @@ -17,7 +15,7 @@ void throw_database_error(PGresult *res, PGconn *db, const std::string &source, if (res == nullptr || (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK)) { - database_error(PQerrorMessage(db), source, sqlca.sqlstate, sql); + database_error(PQerrorMessage(db), source, PQresultErrorField(res, PG_DIAG_SQLSTATE), sql); } } From ee5801cfe6d9d5a092e51fef1ced95469e1259e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 2 Jan 2020 10:57:19 +0100 Subject: [PATCH 06/18] enhanced db connection failed test --- test/sql/ConnectionTestUnit.cpp | 24 +++++++++++++++++++++++- test/sql/ConnectionTestUnit.hpp | 3 +++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/test/sql/ConnectionTestUnit.cpp b/test/sql/ConnectionTestUnit.cpp index fff92b0e6..e348e3183 100644 --- a/test/sql/ConnectionTestUnit.cpp +++ b/test/sql/ConnectionTestUnit.cpp @@ -93,7 +93,12 @@ void ConnectionTestUnit::test_reconnect() void ConnectionTestUnit::test_connection_failed() { - string dns = db_vendor_ + "://sa:Sa%%docker18@127.0.0.1/matador_test (FreeTDS)"; + if (db_vendor_ == "sqlite") { + UNIT_INFO("skipping connection fail test for sqlite"); + return; + } + + string dns = get_invalid_dns(db_vendor_); matador::connection conn(dns); @@ -113,3 +118,20 @@ std::string ConnectionTestUnit::connection_string() { return dns_; } + +std::string ConnectionTestUnit::get_invalid_dns(const std::string &db_vendor) +{ + std::string dns = db_vendor + "://"; + if (db_vendor == "mysql") { + dns += "sascha:sascha@127.0.0.1/matador_invalid"; + } else if (db_vendor == "mssql") { + dns += "sa:Sa%%docker18@127.0.0.1/matador_test (FreeTDS)"; + } else if (db_vendor == "sqlite") { + dns += "test.sqlite"; + } else if (db_vendor == "postgresql") { + dns += "test:test123@127.0.0.1/matador_invalid"; + } else { + UNIT_FAIL("unknown db vendor " + db_vendor); + } + return dns; +} diff --git a/test/sql/ConnectionTestUnit.hpp b/test/sql/ConnectionTestUnit.hpp index e77a1f9b1..f9aedd048 100644 --- a/test/sql/ConnectionTestUnit.hpp +++ b/test/sql/ConnectionTestUnit.hpp @@ -38,6 +38,9 @@ class ConnectionTestUnit : public matador::unit_test protected: std::string connection_string(); +private: + std::string get_invalid_dns(const std::string &db_vendor); + private: std::string dns_; std::string db_vendor_; From e0bb776f3573fa159c977ca897390f186fa57e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 2 Jan 2020 11:14:17 +0100 Subject: [PATCH 07/18] fixed sqlite throw_database_error --- include/matador/db/sqlite/sqlite_exception.hpp | 2 -- src/db/sqlite/sqlite_exception.cpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/matador/db/sqlite/sqlite_exception.hpp b/include/matador/db/sqlite/sqlite_exception.hpp index 576d7df3b..51c970556 100644 --- a/include/matador/db/sqlite/sqlite_exception.hpp +++ b/include/matador/db/sqlite/sqlite_exception.hpp @@ -31,8 +31,6 @@ #include -#include "matador/sql/sql_exception.hpp" - namespace matador { namespace sqlite { diff --git a/src/db/sqlite/sqlite_exception.cpp b/src/db/sqlite/sqlite_exception.cpp index d27a53bb4..b971e8c43 100644 --- a/src/db/sqlite/sqlite_exception.cpp +++ b/src/db/sqlite/sqlite_exception.cpp @@ -23,12 +23,12 @@ namespace matador { namespace sqlite { -void throw_error(int ec, sqlite3 *db, const std::string &sql) +void throw_database_error(int ec, sqlite3 *db, const std::string &source, const std::string &sql) { if (ec == SQLITE_OK) { return; } - throw database_error(sqlite3_errmsg(db), "sqlite", sqlite3_errcode(db), sql); + throw database_error(sqlite3_errmsg(db), source, sqlite3_errcode(db), sql); } } From 6734a70f721f51843db02ed648151cffce15bd19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 2 Jan 2020 11:14:35 +0100 Subject: [PATCH 08/18] added dll export wor windows --- include/matador/sql/database_error.hpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/include/matador/sql/database_error.hpp b/include/matador/sql/database_error.hpp index 3f1590c24..455123e19 100644 --- a/include/matador/sql/database_error.hpp +++ b/include/matador/sql/database_error.hpp @@ -5,11 +5,25 @@ #ifndef MATADOR_DATABASE_ERROR_HPP #define MATADOR_DATABASE_ERROR_HPP +#ifdef _MSC_VER +#ifdef matador_sql_EXPORTS + #define OOS_SQL_API __declspec(dllexport) + #define EXPIMP_SQL_TEMPLATE + #else + #define OOS_SQL_API __declspec(dllimport) + #define EXPIMP_SQL_TEMPLATE extern + #endif + #pragma warning(disable: 4251) + #pragma warning(disable: 4355) +#else +#define OOS_SQL_API +#endif + #include namespace matador { -class database_error : public std::runtime_error +class OOS_SQL_API database_error : public std::runtime_error { public: database_error(const std::string &what, std::string source, long ec, std::string sql = ""); From bb3c9c2fb1042c3252b63d567cd9eb091974afe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 2 Jan 2020 11:14:50 +0100 Subject: [PATCH 09/18] removed unused test class --- test/test_matador.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_matador.cpp b/test/test_matador.cpp index 1edfe2a2d..327dea974 100644 --- a/test/test_matador.cpp +++ b/test/test_matador.cpp @@ -81,7 +81,6 @@ int main(int argc, char *argv[]) suite.register_unit(new DateTestUnit); suite.register_unit(new TimeTestUnit); suite.register_unit(new BlobTestUnit); -// suite.register_unit(new VarCharTestUnit); suite.register_unit(new FactoryTestUnit); suite.register_unit(new StringTestUnit); suite.register_unit(new SequencerTestUnit); From 0ddcb9802b326b3809479e98229ad5322f8cf684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Fri, 3 Jan 2020 09:19:25 +0100 Subject: [PATCH 10/18] restructured connection unit test --- test/sql/ConnectionTestUnit.cpp | 32 ++++++-------------------------- test/sql/ConnectionTestUnit.hpp | 6 ------ 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/test/sql/ConnectionTestUnit.cpp b/test/sql/ConnectionTestUnit.cpp index e348e3183..256f1c27d 100644 --- a/test/sql/ConnectionTestUnit.cpp +++ b/test/sql/ConnectionTestUnit.cpp @@ -21,6 +21,7 @@ #include "matador/sql/database_error.hpp" #include +#include using namespace matador; using namespace std; @@ -38,7 +39,7 @@ ConnectionTestUnit::ConnectionTestUnit(const std::string &prefix, std::string dn void ConnectionTestUnit::test_open_close() { - matador::connection conn(connection_string()); + matador::connection conn(dns_); UNIT_ASSERT_FALSE(conn.is_connected()); @@ -53,7 +54,7 @@ void ConnectionTestUnit::test_open_close() void ConnectionTestUnit::test_reopen() { - matador::connection conn(connection_string()); + matador::connection conn(dns_); UNIT_ASSERT_FALSE(conn.is_connected()); @@ -74,7 +75,7 @@ void ConnectionTestUnit::test_reopen() void ConnectionTestUnit::test_reconnect() { - matador::connection conn(connection_string()); + matador::connection conn(dns_); UNIT_ASSERT_FALSE(conn.is_connected()); @@ -98,7 +99,8 @@ void ConnectionTestUnit::test_connection_failed() return; } - string dns = get_invalid_dns(db_vendor_); + std::regex re("(matador_test)"); + string dns = std::regex_replace(dns_, re, "matador_invalid"); matador::connection conn(dns); @@ -113,25 +115,3 @@ void ConnectionTestUnit::test_connection_failed() } UNIT_ASSERT_TRUE(caught_exception); } - -std::string ConnectionTestUnit::connection_string() -{ - return dns_; -} - -std::string ConnectionTestUnit::get_invalid_dns(const std::string &db_vendor) -{ - std::string dns = db_vendor + "://"; - if (db_vendor == "mysql") { - dns += "sascha:sascha@127.0.0.1/matador_invalid"; - } else if (db_vendor == "mssql") { - dns += "sa:Sa%%docker18@127.0.0.1/matador_test (FreeTDS)"; - } else if (db_vendor == "sqlite") { - dns += "test.sqlite"; - } else if (db_vendor == "postgresql") { - dns += "test:test123@127.0.0.1/matador_invalid"; - } else { - UNIT_FAIL("unknown db vendor " + db_vendor); - } - return dns; -} diff --git a/test/sql/ConnectionTestUnit.hpp b/test/sql/ConnectionTestUnit.hpp index f9aedd048..ecabcc63e 100644 --- a/test/sql/ConnectionTestUnit.hpp +++ b/test/sql/ConnectionTestUnit.hpp @@ -35,12 +35,6 @@ class ConnectionTestUnit : public matador::unit_test void test_reconnect(); void test_connection_failed(); -protected: - std::string connection_string(); - -private: - std::string get_invalid_dns(const std::string &db_vendor); - private: std::string dns_; std::string db_vendor_; From 78a8329b9369c8b079b9b96d940992c513eb2757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 5 Jan 2020 13:34:53 +0100 Subject: [PATCH 11/18] added missing include --- include/matador/db/mysql/mysql_bool.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/matador/db/mysql/mysql_bool.hpp b/include/matador/db/mysql/mysql_bool.hpp index e1803a77e..7f88d33af 100644 --- a/include/matador/db/mysql/mysql_bool.hpp +++ b/include/matador/db/mysql/mysql_bool.hpp @@ -5,6 +5,12 @@ #ifndef MATADOR_MYSQL_BOOL_HPP #define MATADOR_MYSQL_BOOL_HPP +#ifdef _MSC_VER +#include +#else +#include +#endif + #if !MARIADB_PACKAGE_VERSION_ID && MYSQL_VERSION_ID >= 80001 typedef bool my_bool; #endif From d5e4b5eb9831556a991c1feeae71da152590d588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 5 Jan 2020 13:35:05 +0100 Subject: [PATCH 12/18] removed obsolete decltype --- src/db/mysql/mysql_parameter_binder.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/db/mysql/mysql_parameter_binder.cpp b/src/db/mysql/mysql_parameter_binder.cpp index fbe9525ba..d0c4fcee1 100644 --- a/src/db/mysql/mysql_parameter_binder.cpp +++ b/src/db/mysql/mysql_parameter_binder.cpp @@ -22,7 +22,7 @@ void bind_value(enum_field_types type, T value, MYSQL_BIND &bind, my_bool &is_nu bind.buffer = new char[sizeof(T)]; bind.buffer_type = type; bind.buffer_length = sizeof(T); - bind.is_null = decltype(bind.is_null)(&is_null); + bind.is_null = &is_null; bind.is_unsigned = std::is_unsigned::value; } *static_cast(bind.buffer) = value; @@ -38,7 +38,7 @@ void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bi bind.buffer = nullptr; bind.buffer_length = 0; bind.buffer_type = type; - bind.is_null = decltype(bind.is_null)(&is_null); + bind.is_null = &is_null; } if (bind.buffer == nullptr) { // allocating memory @@ -60,7 +60,7 @@ void bind_value(enum_field_types type, const matador::date &x, MYSQL_BIND &bind, size_t s = sizeof(MYSQL_TIME); bind.buffer = new char[s]; bind.buffer_length = (unsigned long)s; - bind.is_null = decltype(bind.is_null)(&is_null); + bind.is_null = &is_null; bind.buffer_type = type; bind.length = nullptr; } @@ -81,7 +81,7 @@ void bind_value(enum_field_types type, const matador::time &x, MYSQL_BIND &bind, bind.buffer_length = (unsigned long)s; bind.buffer_type = type; bind.length = nullptr; - bind.is_null = decltype(bind.is_null)(&is_null); + bind.is_null = &is_null; } memset(bind.buffer, 0, sizeof(MYSQL_TIME)); is_null = false; @@ -105,7 +105,6 @@ mysql_parameter_binder::mysql_parameter_binder(size_t column_size, size_t bind_v host_array_.resize(bind_var_size); is_null_vector.assign(bind_var_size, false); } - } void mysql_parameter_binder::reset() From fef36c24056214ca38e5bbc889add960148d4bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 5 Jan 2020 16:29:59 +0100 Subject: [PATCH 13/18] added is_null_t for bool vector --- .../db/mysql/mysql_parameter_binder.hpp | 8 +++- include/matador/db/mysql/mysql_statement.hpp | 4 -- src/db/mysql/mysql_parameter_binder.cpp | 48 +++++++++++-------- src/db/mysql/mysql_statement.cpp | 7 --- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/include/matador/db/mysql/mysql_parameter_binder.hpp b/include/matador/db/mysql/mysql_parameter_binder.hpp index 334923079..49425ac80 100644 --- a/include/matador/db/mysql/mysql_parameter_binder.hpp +++ b/include/matador/db/mysql/mysql_parameter_binder.hpp @@ -57,10 +57,16 @@ class mysql_parameter_binder : public detail::parameter_binder_impl std::vector& result_infos(); + void bind_null(std::size_t index); private: + struct is_null_t + { + my_bool is_null = false; + }; + std::vector host_array_; std::vector bind_; - std::vector is_null_vector; + std::vector is_null_vector; std::vector info_; size_t index_ = 0; diff --git a/include/matador/db/mysql/mysql_statement.hpp b/include/matador/db/mysql/mysql_statement.hpp index c3fc49f6c..0a31907e2 100644 --- a/include/matador/db/mysql/mysql_statement.hpp +++ b/include/matador/db/mysql/mysql_statement.hpp @@ -59,10 +59,6 @@ class mysql_statement : public matador::detail::statement_impl protected: detail::parameter_binder_impl *binder() const override; -private: - -// void bind_null(std::size_t index); - private: MYSQL_STMT *stmt_ = nullptr; diff --git a/src/db/mysql/mysql_parameter_binder.cpp b/src/db/mysql/mysql_parameter_binder.cpp index d0c4fcee1..06fd8baa0 100644 --- a/src/db/mysql/mysql_parameter_binder.cpp +++ b/src/db/mysql/mysql_parameter_binder.cpp @@ -103,7 +103,7 @@ mysql_parameter_binder::mysql_parameter_binder(size_t column_size, size_t bind_v if (bind_var_size) { host_array_.resize(bind_var_size); - is_null_vector.assign(bind_var_size, false); + is_null_vector.assign(bind_var_size, is_null_t()); } } @@ -135,82 +135,82 @@ size_t mysql_parameter_binder::current_index() const void mysql_parameter_binder::bind(char i, size_t index) { - bind_value(MYSQL_TYPE_VAR_STRING, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_VAR_STRING, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(short i, size_t index) { - bind_value(MYSQL_TYPE_SHORT, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_SHORT, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(int i, size_t index) { - bind_value(MYSQL_TYPE_LONG, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_LONG, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(long i, size_t index) { - bind_value(MYSQL_TYPE_LONG, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_LONG, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(long long i, size_t index) { - bind_value(MYSQL_TYPE_LONGLONG, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_LONGLONG, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(unsigned char i, size_t index) { - bind_value(MYSQL_TYPE_VAR_STRING, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_VAR_STRING, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(unsigned short i, size_t index) { - bind_value(MYSQL_TYPE_SHORT, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_SHORT, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(unsigned int i, size_t index) { - bind_value(MYSQL_TYPE_LONG, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_LONG, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(unsigned long i, size_t index) { - bind_value(MYSQL_TYPE_LONG, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_LONG, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(unsigned long long i, size_t index) { - bind_value(MYSQL_TYPE_LONGLONG, i, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_LONGLONG, i, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(bool b, size_t index) { - bind_value(MYSQL_TYPE_TINY, b, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_TINY, b, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(float d, size_t index) { - bind_value(MYSQL_TYPE_FLOAT, d, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_FLOAT, d, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(double d, size_t index) { - bind_value(MYSQL_TYPE_DOUBLE, d, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_DOUBLE, d, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(const char *x, size_t size, size_t index) { - bind_value(MYSQL_TYPE_VAR_STRING, x, size, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_VAR_STRING, x, size, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(const std::string &x, size_t index) { - bind_value(MYSQL_TYPE_STRING, x.data(), x.size(), host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_STRING, x.data(), x.size(), host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(const std::string &x, size_t size, size_t index) { - bind_value(MYSQL_TYPE_VAR_STRING, x.data(), size, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_VAR_STRING, x.data(), size, host_array_[index], is_null_vector[index].is_null); } void mysql_parameter_binder::bind(const matador::time &x, size_t index) @@ -220,16 +220,16 @@ void mysql_parameter_binder::bind(const matador::time &x, size_t index) // doesn't support fractional seconds // so we use a datetime string here std::string tstr = to_string(x, "%FT%T"); - bind_value(MYSQL_TYPE_VAR_STRING, tstr.c_str(), tstr.size(), host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_VAR_STRING, tstr.c_str(), tstr.size(), host_array_[index], is_null_vector[index].is_null); } else { - bind_value(MYSQL_TYPE_TIMESTAMP, x, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_TIMESTAMP, x, host_array_[index], is_null_vector[index].is_null); } } void mysql_parameter_binder::bind(const matador::date &x, size_t index) { - bind_value(MYSQL_TYPE_DATE, x, host_array_[index], is_null_vector[index]); + bind_value(MYSQL_TYPE_DATE, x, host_array_[index], is_null_vector[index].is_null); } std::vector &mysql_parameter_binder::host_array() @@ -246,5 +246,13 @@ std::vector &mysql_parameter_binder::result_infos() { return info_; } + +void mysql_parameter_binder::bind_null(std::size_t index) +{ + MYSQL_BIND &bind = host_array_[index]; + is_null_vector[index].is_null = true; + bind.is_null = &is_null_vector[index].is_null; +} + } } diff --git a/src/db/mysql/mysql_statement.cpp b/src/db/mysql/mysql_statement.cpp index 892bcd9f1..10cbb0c4f 100644 --- a/src/db/mysql/mysql_statement.cpp +++ b/src/db/mysql/mysql_statement.cpp @@ -89,13 +89,6 @@ detail::result_impl* mysql_statement::execute() return current_result; } -//void mysql_statement::bind_null(std::size_t index) -//{ -// MYSQL_BIND &bind = host_array[index]; -// is_null_vector[index] = true; -// bind.is_null = &is_null_vector[index]; -//} - detail::parameter_binder_impl *mysql_statement::binder() const { return binder_.get(); From 1e548bd5dbc70127d033b9d06e85c05ee9e29125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 5 Jan 2020 16:31:55 +0100 Subject: [PATCH 14/18] added missing include --- include/matador/db/mysql/mysql_bool.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/matador/db/mysql/mysql_bool.hpp b/include/matador/db/mysql/mysql_bool.hpp index e1803a77e..7f88d33af 100644 --- a/include/matador/db/mysql/mysql_bool.hpp +++ b/include/matador/db/mysql/mysql_bool.hpp @@ -5,6 +5,12 @@ #ifndef MATADOR_MYSQL_BOOL_HPP #define MATADOR_MYSQL_BOOL_HPP +#ifdef _MSC_VER +#include +#else +#include +#endif + #if !MARIADB_PACKAGE_VERSION_ID && MYSQL_VERSION_ID >= 80001 typedef bool my_bool; #endif From 6ee581126650f1c8ecb1c4f74a28be685d3fd813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 5 Jan 2020 17:45:53 +0100 Subject: [PATCH 15/18] changed demo test --- test/orm/OrmTestUnit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/orm/OrmTestUnit.cpp b/test/orm/OrmTestUnit.cpp index 429827a29..73f6d867f 100644 --- a/test/orm/OrmTestUnit.cpp +++ b/test/orm/OrmTestUnit.cpp @@ -48,7 +48,7 @@ struct person void serialize(SERIALIZER &serializer) { serializer.serialize("id", id); serializer.serialize("name", name, 255); - serializer.serialize("ip", ip); + serializer.serialize("ip", ip, 255); serializer.serialize("age", age); serializer.serialize("person_color", colors, "person_id", "color", matador::cascade_type::ALL); // table name member left column right column cascade type From 68ee5f2b584e1769000116c462221d44fb98f296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 6 Jan 2020 14:27:46 +0100 Subject: [PATCH 16/18] added documentation to class database_error --- include/matador/sql/database_error.hpp | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/include/matador/sql/database_error.hpp b/include/matador/sql/database_error.hpp index 455123e19..d1add3e1f 100644 --- a/include/matador/sql/database_error.hpp +++ b/include/matador/sql/database_error.hpp @@ -23,18 +23,80 @@ namespace matador { +/** + * @brief Thrown by db backend containing all available error informations + * + * This exception is thrown by the database backend and contains + * all available error informations provided by the backend + */ class OOS_SQL_API database_error : public std::runtime_error { public: + /** + * Creates a database error exception with error code. + * + * @param what Error message + * @param source Database vendor string + * @param ec Error code + * @param sql Optional sql statement string + */ database_error(const std::string &what, std::string source, long ec, std::string sql = ""); + + /** + * Creates a database error exception with sql state and error code. + * + * @param what Error message + * @param source Database vendor string + * @param sqlstate SQL State + * @param ec Error code + * @param sql Optional sql statement string + */ database_error(const std::string &what, std::string source, std::string sqlstate, long ec, std::string sql = ""); + + /** + * Creates a database error exception with sql state. + * + * @param what Error message + * @param source Database vendor string + * @param sqlstate SQL State + * @param sql Optional sql statement string + */ database_error(const std::string &what, std::string source, std::string sqlstate, std::string sql = ""); + /** + * Destroy the database error + */ ~database_error() noexcept override = default; + /** + * Returns the database vendor string. + * + * @return Database vendor string + */ const char* source() const noexcept; + + /** + * Returns a proprietary error code depending + * on the database backend. + * + * @return Proprietary database error code + */ long error_code() const noexcept; + + /** + * Returns the sql state according to the SQL standard + * provided by the database backend. It is a 5 char long + * string representing a sql error code. + * + * @return SQL State + */ const char* sql_state() const noexcept; + + /** + * If available it returns a corresponding sql statement. + * + * @return Optional corresponding sql statement + */ const char* sql_statement() const noexcept; private: From 7fa3dd72fe729e4d2631e68ebe995a0683c0f9b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 6 Jan 2020 14:28:03 +0100 Subject: [PATCH 17/18] initialized identifier value --- include/matador/utils/identifier.hpp | 4 ++-- include/matador/utils/identifier_setter.hpp | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/matador/utils/identifier.hpp b/include/matador/utils/identifier.hpp index b8b77432c..0379528b9 100644 --- a/include/matador/utils/identifier.hpp +++ b/include/matador/utils/identifier.hpp @@ -227,7 +227,7 @@ class identifier::value>::type> : T& reference() { return id_; } private: - T id_; + T id_ = {}; static std::type_index type_index_; }; @@ -459,7 +459,7 @@ class OOS_UTILS_API identifier> : public basic_identifier * * @param val String value of the identifier */ - explicit identifier(std::string val) : id_(std::move(val)) + explicit identifier(const std::string& val) : id_(val) { } /** diff --git a/include/matador/utils/identifier_setter.hpp b/include/matador/utils/identifier_setter.hpp index 68ea0ccca..d754f3b63 100644 --- a/include/matador/utils/identifier_setter.hpp +++ b/include/matador/utils/identifier_setter.hpp @@ -49,7 +49,7 @@ class identifier_setter void serialize(const char *id, identifier &x) { reading_pk_ = true; - V val; + V val = {}; serialize(id, val); x.value(val); reading_pk_ = false; @@ -59,10 +59,7 @@ class identifier_setter void serialize(const char*, V &) {} void serialize(const char*, char *, size_t) {} void serialize(const char*, std::string &, size_t) {} -// template < class HAS_ONE > void serialize(const char*, object_holder&, cascade_type) {} - -// template < class HAS_MANY > void serialize(const char *, abstract_has_many &, const char *, const char *, cascade_type) {} void serialize(const char *, abstract_has_many &, cascade_type) {} From 75653d1192151c6b833a2a7500b3a259bc88dd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 6 Jan 2020 17:08:09 +0100 Subject: [PATCH 18/18] added test concerning database_error on statements --- include/matador/sql/database_error.hpp | 2 ++ src/db/postgresql/postgresql_exception.cpp | 2 +- test/sql/QueryTestUnit.cpp | 32 ++++++++++++++++++++++ test/sql/QueryTestUnit.hpp | 2 ++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/matador/sql/database_error.hpp b/include/matador/sql/database_error.hpp index d1add3e1f..614b670d0 100644 --- a/include/matador/sql/database_error.hpp +++ b/include/matador/sql/database_error.hpp @@ -88,6 +88,8 @@ class OOS_SQL_API database_error : public std::runtime_error * provided by the database backend. It is a 5 char long * string representing a sql error code. * + * SQL States + * * @return SQL State */ const char* sql_state() const noexcept; diff --git a/src/db/postgresql/postgresql_exception.cpp b/src/db/postgresql/postgresql_exception.cpp index 813f0cb20..6b406b94e 100644 --- a/src/db/postgresql/postgresql_exception.cpp +++ b/src/db/postgresql/postgresql_exception.cpp @@ -15,7 +15,7 @@ void throw_database_error(PGresult *res, PGconn *db, const std::string &source, if (res == nullptr || (PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK)) { - database_error(PQerrorMessage(db), source, PQresultErrorField(res, PG_DIAG_SQLSTATE), sql); + throw database_error(PQerrorMessage(db), source, PQresultErrorField(res, PG_DIAG_SQLSTATE), sql); } } diff --git a/test/sql/QueryTestUnit.cpp b/test/sql/QueryTestUnit.cpp index c7285911f..347919085 100644 --- a/test/sql/QueryTestUnit.cpp +++ b/test/sql/QueryTestUnit.cpp @@ -9,6 +9,7 @@ #include "matador/sql/query.hpp" #include "matador/sql/types.hpp" +#include "matador/sql/database_error.hpp" #include "matador/utils/date.hpp" #include "matador/utils/time.hpp" @@ -23,6 +24,7 @@ using namespace matador; QueryTestUnit::QueryTestUnit(const std::string &prefix, std::string db, matador::time timeval) : unit_test(prefix + "_query", prefix + " query test unit") , db_(std::move(db)) + , db_vendor_(prefix) , time_val_(timeval) { add_test("info", std::bind(&QueryTestUnit::print_datatypes, this), "print datatypes info"); @@ -33,6 +35,7 @@ QueryTestUnit::QueryTestUnit(const std::string &prefix, std::string db, matador: add_test("quoted_literals", std::bind(&QueryTestUnit::test_quoted_literals, this), "test quoted literals"); add_test("bind_tablename", std::bind(&QueryTestUnit::test_bind_tablename, this), "test bind tablenames"); add_test("describe", std::bind(&QueryTestUnit::test_describe, this), "test describe table"); + add_test("unknown_table", std::bind(&QueryTestUnit::test_unknown_table, this), "test unknown table"); add_test("identifier", std::bind(&QueryTestUnit::test_identifier, this), "test sql identifier"); add_test("identifier_prepared", std::bind(&QueryTestUnit::test_identifier_prepared, this), "test sql prepared identifier"); add_test("update", std::bind(&QueryTestUnit::test_update, this), "test direct sql update statement"); @@ -354,6 +357,35 @@ void QueryTestUnit::test_describe() q.drop().execute(connection_); } +void QueryTestUnit::test_unknown_table() +{ + connection_.connect(); + + matador::query q("person"); + + bool caught_exception = false; + + try { + q.select().execute(connection_); + } catch (database_error &ex) { + caught_exception = true; + if (db_vendor_ == "postgresql") { + UNIT_EXPECT_EQUAL("42P01", ex.sql_state()); + } else if (db_vendor_ == "mysql") { + UNIT_EXPECT_EQUAL("42S02", ex.sql_state()); + } else if (db_vendor_ == "mssql") { + UNIT_EXPECT_EQUAL("42S02", ex.sql_state()); + } else if (db_vendor_ == "sqlite") { + UNIT_EXPECT_EQUAL(1L, ex.error_code()); + } else { + UNIT_FAIL("invalid database vendor string: " << db_vendor_); + } + } catch (...) { + UNIT_FAIL("caught from exception"); + } + UNIT_ASSERT_TRUE(caught_exception); +} + class pktest { public: diff --git a/test/sql/QueryTestUnit.hpp b/test/sql/QueryTestUnit.hpp index fff6df660..a506eaf10 100644 --- a/test/sql/QueryTestUnit.hpp +++ b/test/sql/QueryTestUnit.hpp @@ -32,6 +32,7 @@ class QueryTestUnit : public matador::unit_test void test_quoted_literals(); void test_bind_tablename(); void test_describe(); + void test_unknown_table(); void test_identifier(); void test_identifier_prepared(); void test_create(); @@ -64,6 +65,7 @@ class QueryTestUnit : public matador::unit_test private: std::string db_; + std::string db_vendor_; matador::connection connection_; matador::time time_val_; };