diff --git a/rdbms/StmtTest.cpp b/rdbms/StmtTest.cpp index c48a794dbf3c1be48978f6624e266289f8b1ed23..8cdb54c947edd2b1c20a45ed2316eea181bc4b02 100644 --- a/rdbms/StmtTest.cpp +++ b/rdbms/StmtTest.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "common/exception/DatabaseConstraintError.hpp" #include "common/exception/Exception.hpp" #include "common/make_unique.hpp" #include "common/utils/utils.hpp" @@ -60,11 +61,12 @@ std::string cta_rdbms_StmtTest::getCreateStmtTestTableSql() { try { std::string sql = - "CREATE TABLE STMT_TEST(" - "DOUBLE_COL FLOAT," - "UINT64_COL UINT64TYPE," - "STRING_COL VARCHAR(100)," - "BOOL_COL CHAR(1)" + "CREATE TABLE STMT_TEST(" "\n" + " DOUBLE_COL FLOAT," "\n" + " UINT64_COL UINT64TYPE," "\n" + " STRING_COL VARCHAR(100)," "\n" + " BOOL_COL CHAR(1) DEFAULT '0'," "\n" + " CONSTRAINT BOOL_COL_BOOL_CK CHECK(BOOL_COL IN ('0', '1'))" "\n" ")"; switch(m_login.dbType) { @@ -383,4 +385,22 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindBool_false) { } } +TEST_P(cta_rdbms_StmtTest, insert_with_bindString_invalid_bool_value) { + using namespace cta::rdbms; + + const std::string insertValue = "2"; // null, "0" and "1" are valid values + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" + "BOOL_COL) " + "VALUES(" + ":BOOL_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindString(":BOOL_COL", insertValue); + ASSERT_THROW(stmt.executeNonQuery(), cta::exception::DatabaseConstraintError); + } +} + } // namespace unitTests diff --git a/rdbms/wrapper/MysqlStmt.cpp b/rdbms/wrapper/MysqlStmt.cpp index 31c713947f302d15762664792cc3199e2df0ab7f..ab94691190be9f87b41f5a15bc84f42b003421ad 100644 --- a/rdbms/wrapper/MysqlStmt.cpp +++ b/rdbms/wrapper/MysqlStmt.cpp @@ -382,6 +382,9 @@ void MysqlStmt::executeNonQuery() { case ER_DUP_ENTRY: throw exception::DatabasePrimaryKeyError(std::string(__FUNCTION__) + " " + msg); break; + case 4025: // Newer MariaDB versions have ER_CONSTRAINT_FAILED = 4025 + throw exception::DatabaseConstraintError(std::string(__FUNCTION__) + " " + msg); + break; } throw exception::Exception(std::string(__FUNCTION__) + " " + msg); diff --git a/rdbms/wrapper/OcciStmt.cpp b/rdbms/wrapper/OcciStmt.cpp index 44451197d3bb020166e1053b3bcc1217fc393f99..b9155cba9ae7787f2b279879264bed7d76a7c651 100644 --- a/rdbms/wrapper/OcciStmt.cpp +++ b/rdbms/wrapper/OcciStmt.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "common/exception/DatabaseConstraintError.hpp" #include "common/exception/Exception.hpp" #include "common/exception/LostDatabaseConnection.hpp" #include "common/make_unique.hpp" @@ -267,7 +268,11 @@ void OcciStmt::executeNonQuery() { } throw exception::LostDatabaseConnection(msg.str()); } - throw exception::Exception(msg.str()); + if(2290 == ex.getErrorCode()) { + throw exception::DatabaseConstraintError(msg.str()); + } else { + throw exception::Exception(msg.str()); + } } } diff --git a/rdbms/wrapper/Postgres.hpp b/rdbms/wrapper/Postgres.hpp index b630cbfe8c6f082cc5cd2c65a08ba0153fa45ae5..52c2698be665f1027f811a9d7c69d4527d9deb29 100644 --- a/rdbms/wrapper/Postgres.hpp +++ b/rdbms/wrapper/Postgres.hpp @@ -18,11 +18,14 @@ #pragma once +#include "common/exception/DatabaseConstraintError.hpp" #include "common/exception/Exception.hpp" #include "common/exception/LostDatabaseConnection.hpp" + +#include <algorithm> +#include <cstring> #include <libpq-fe.h> #include <string> -#include <algorithm> namespace cta { namespace rdbms { @@ -47,10 +50,12 @@ public: pgstr.erase(std::remove(pgstr.begin(), pgstr.end(), '\n'), pgstr.end()); } std::string resstr; + bool checkViolation = false; if (nullptr != res) { resstr = "DB Result Status:" + std::to_string(PQresultStatus(res)); const char *const e = PQresultErrorField(res, PG_DIAG_SQLSTATE); if (nullptr != e && '\0' != *e) { + checkViolation = 0 == std::strcmp("23514", e); resstr += " SQLState:" + std::string(e); } } @@ -85,6 +90,9 @@ public: if (badconn) { throw exception::LostDatabaseConnection(dbmsg); } + if (checkViolation) { + throw exception::DatabaseConstraintError(dbmsg); + } throw exception::Exception(dbmsg); } diff --git a/rdbms/wrapper/PostgresStmt.cpp b/rdbms/wrapper/PostgresStmt.cpp index a39c012bfa6bf5e10e47e6108e6d8975b70a0bbd..0cb1a8f8389bd731f7c6c799ee1814f3fb5c9080 100644 --- a/rdbms/wrapper/PostgresStmt.cpp +++ b/rdbms/wrapper/PostgresStmt.cpp @@ -28,10 +28,11 @@ #include "rdbms/wrapper/PostgresRset.hpp" #include "rdbms/wrapper/PostgresStmt.hpp" +#include <algorithm> #include <exception> +#include <pgsql/server/utils/errcodes.h> #include <sstream> #include <utility> -#include <algorithm> namespace cta { namespace rdbms { @@ -355,8 +356,9 @@ void PostgresStmt::executeNonQuery() { throw exception::LostDatabaseConnection(std::string(__FUNCTION__) + " detected lost connection for SQL statement " + getSqlForException() + ": " + ex.getMessage().str()); } catch(exception::Exception &ex) { - throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + - getSqlForException() + ": " + ex.getMessage().str()); + ex.getMessage().str(std::string(__FUNCTION__) + " failed for SQL statement " + getSqlForException() + ": " + + ex.getMessage().str()); + throw; } } diff --git a/rdbms/wrapper/PostgresStmt.hpp b/rdbms/wrapper/PostgresStmt.hpp index c1a6bc47f2afbf5ec42ac0d22ad5b398282b69cf..8b018d0b9a2c7b725c1f5710100ae6d85808e6eb 100644 --- a/rdbms/wrapper/PostgresStmt.hpp +++ b/rdbms/wrapper/PostgresStmt.hpp @@ -25,10 +25,10 @@ #include "rdbms/wrapper/PostgresConn.hpp" #include "rdbms/wrapper/PostgresColumn.hpp" -#include <vector> -#include <string> -#include <memory> #include <cstdint> +#include <memory> +#include <string> +#include <vector> namespace cta { namespace rdbms {