From 3793c0a515a0b7e70ee29a2d9c637d5d9e506f5b Mon Sep 17 00:00:00 2001 From: omerbrandis Date: Fri, 20 Oct 2023 18:44:04 +0300 Subject: [PATCH] added new memeber SqlState to PostgreSQLException and made use of it. (#4099) * added new memeber SqlState to PostgreSQLException and made use of it in StatementExecutor * Added test case testSqlState * fixed nameing convention errors. fixed bug in PostgreSQLException::PostgreSQLException regarding null termination of _sqlState data member --- .../Data/PostgreSQL/PostgreSQLException.h | 23 +++++++++++++++++++ Data/PostgreSQL/src/PostgreSQLException.cpp | 22 +++++++++++++++++- Data/PostgreSQL/src/StatementExecutor.cpp | 18 +++++++++++---- .../testsuite/src/PostgreSQLTest.cpp | 15 ++++++++++++ .../PostgreSQL/testsuite/src/PostgreSQLTest.h | 6 +++-- 5 files changed, 77 insertions(+), 7 deletions(-) diff --git a/Data/PostgreSQL/include/Poco/Data/PostgreSQL/PostgreSQLException.h b/Data/PostgreSQL/include/Poco/Data/PostgreSQL/PostgreSQLException.h index 4a7216ba26..d8194be809 100644 --- a/Data/PostgreSQL/include/Poco/Data/PostgreSQL/PostgreSQLException.h +++ b/Data/PostgreSQL/include/Poco/Data/PostgreSQL/PostgreSQLException.h @@ -36,6 +36,11 @@ class PostgreSQL_API PostgreSQLException: public Poco::Data::DataException explicit PostgreSQLException(const std::string& aMessage); /// Creates PostgreSQLException. + + explicit PostgreSQLException(const std::string& aMessage,const char * pAnSqlState); + /// Creates PostgreSQLException. + + PostgreSQLException(const PostgreSQLException& exc); /// Creates PostgreSQLException. @@ -63,6 +68,13 @@ class PostgreSQL_API PostgreSQLException: public Poco::Data::DataException /// This is useful for temporarily storing a /// copy of an exception (see clone()), then /// throwing it again. + + const char* sqlState() const noexcept; + /// Returns the SqlState + + +private: + char _sqlState[6]; }; @@ -90,6 +102,10 @@ class StatementException: public PostgreSQLException public: StatementException(const std::string& aMessage); /// Creates StatementException from string. + + StatementException(const std::string& aMessage,const char* pAnSqlState); + /// Creates StatementException from string with support for sqlState. + }; @@ -129,6 +145,13 @@ inline void PostgreSQLException::rethrow() const } +inline const char* PostgreSQLException::sqlState() const noexcept +{ + return _sqlState; +} + + + } } } // namespace Poco::Data::PostgreSQL diff --git a/Data/PostgreSQL/src/PostgreSQLException.cpp b/Data/PostgreSQL/src/PostgreSQLException.cpp index fcef61d5d2..e542c9059b 100644 --- a/Data/PostgreSQL/src/PostgreSQLException.cpp +++ b/Data/PostgreSQL/src/PostgreSQLException.cpp @@ -13,7 +13,7 @@ #include "Poco/Data/PostgreSQL/PostgreSQLException.h" - +#include namespace Poco { namespace Data { @@ -25,6 +25,19 @@ PostgreSQLException::PostgreSQLException(const std::string& aMessage): { } +PostgreSQLException::PostgreSQLException(const std::string& aMessage,const char* pAnSqlState): + Poco::Data::DataException(std::string("[PostgreSQL]: ") + aMessage) +{ + // handle anSqlState + if (pAnSqlState == nullptr) _sqlState[0] = '\0'; + else + { + strncpy(_sqlState,pAnSqlState,5); + _sqlState[5] = '\0'; + } + +} + PostgreSQLException::PostgreSQLException(const PostgreSQLException& anException): Poco::Data::DataException(anException) @@ -68,5 +81,12 @@ StatementException::StatementException(const std::string& aMessage): { } +StatementException::StatementException(const std::string& aMessage,const char* pAnSqlState): + PostgreSQLException(aMessage,pAnSqlState) +{ +} + + + } } } // namespace Poco::Data::PostgreSQL diff --git a/Data/PostgreSQL/src/StatementExecutor.cpp b/Data/PostgreSQL/src/StatementExecutor.cpp index 7d9d3f7b0c..cdf09ef2a0 100644 --- a/Data/PostgreSQL/src/StatementExecutor.cpp +++ b/Data/PostgreSQL/src/StatementExecutor.cpp @@ -143,13 +143,18 @@ void StatementExecutor::prepare(const std::string& aSQLStatement) } { + // get the sqlState + const char* pSQLState = PQresultErrorField(ptrPGResult, PG_DIAG_SQLSTATE); + // setup to clear the result from PQprepare PQResultClear resultClearer(ptrPGResult); - if (!ptrPGResult || PQresultStatus(ptrPGResult) != PGRES_COMMAND_OK) + // + if (!ptrPGResult || PQresultStatus(ptrPGResult) != PGRES_COMMAND_OK ) { - throw StatementException(std::string("postgresql_stmt_prepare error: ") + PQresultErrorMessage (ptrPGResult) + " " + aSQLStatement); + throw StatementException(std::string("postgresql_stmt_prepare error: ") + PQresultErrorMessage (ptrPGResult) + " " + aSQLStatement,pSQLState); } + } // Determine what the structure of a statement result will look like @@ -159,11 +164,15 @@ void StatementExecutor::prepare(const std::string& aSQLStatement) } { + // get the sqlState + const char* pSQLState = PQresultErrorField(ptrPGResult, PG_DIAG_SQLSTATE); + PQResultClear resultClearer(ptrPGResult); + if (!ptrPGResult || PQresultStatus(ptrPGResult) != PGRES_COMMAND_OK) { throw StatementException(std::string("postgresql_stmt_describe error: ") + - PQresultErrorMessage (ptrPGResult) + " " + aSQLStatement); + PQresultErrorMessage (ptrPGResult) + " " + aSQLStatement,pSQLState); } // remember the structure of the statement result @@ -270,13 +279,14 @@ void StatementExecutor::execute() const char* pHint = PQresultErrorField(ptrPGResult, PG_DIAG_MESSAGE_HINT); const char* pConstraint = PQresultErrorField(ptrPGResult, PG_DIAG_CONSTRAINT_NAME); + throw StatementException(std::string("postgresql_stmt_execute error: ") + PQresultErrorMessage (ptrPGResult) + " Severity: " + (pSeverity ? pSeverity : "N/A") + " State: " + (pSQLState ? pSQLState : "N/A") + " Detail: " + (pDetail ? pDetail : "N/A") + " Hint: " + (pHint ? pHint : "N/A") - + " Constraint: " + (pConstraint ? pConstraint : "N/A")); + + " Constraint: " + (pConstraint ? pConstraint : "N/A"),pSQLState); } _pResultHandle = ptrPGResult; diff --git a/Data/PostgreSQL/testsuite/src/PostgreSQLTest.cpp b/Data/PostgreSQL/testsuite/src/PostgreSQLTest.cpp index 4e788a018e..cb17b84632 100644 --- a/Data/PostgreSQL/testsuite/src/PostgreSQLTest.cpp +++ b/Data/PostgreSQL/testsuite/src/PostgreSQLTest.cpp @@ -765,6 +765,20 @@ void PostgreSQLTest::testReconnect() } +void PostgreSQLTest::testSqlState() +{ + if (!_pSession) fail ("Test not available."); + + try + { + *_pSession << "syntax error", now; + } + catch (const Poco::Data::PostgreSQL::PostgreSQLException & exception) + { + assertTrue(exception.sqlState() == std::string("42601")); + } +} + void PostgreSQLTest::testNullableInt() { if (!_pSession) fail ("Test not available."); @@ -1271,6 +1285,7 @@ CppUnit::Test* PostgreSQLTest::suite() CppUnit_addTest(pSuite, PostgreSQLTest, testNullableInt); CppUnit_addTest(pSuite, PostgreSQLTest, testNullableString); CppUnit_addTest(pSuite, PostgreSQLTest, testTupleWithNullable); + CppUnit_addTest(pSuite, PostgreSQLTest, testSqlState); CppUnit_addTest(pSuite, PostgreSQLTest, testBinarySimpleAccess); CppUnit_addTest(pSuite, PostgreSQLTest, testBinaryComplexType); diff --git a/Data/PostgreSQL/testsuite/src/PostgreSQLTest.h b/Data/PostgreSQL/testsuite/src/PostgreSQLTest.h index a7c3d9d004..9f2158830d 100644 --- a/Data/PostgreSQL/testsuite/src/PostgreSQLTest.h +++ b/Data/PostgreSQL/testsuite/src/PostgreSQLTest.h @@ -27,8 +27,8 @@ class PostgreSQLTest: public CppUnit::TestCase /// /// Driver | DB | OS /// ----------------+---------------------------+------------------------------------------ - /// 03.51.12.00 | PostgreSQL 9.3.1.0(18) | Mac OSX 10.9.1 - /// + /// 03.51.12.00 | PostgreSQL 9.3.1.0(18) | Mac OSX 10.9.1 + /// | PostgreSQL 15.3 | Ubuntu 16.04 { public: @@ -113,6 +113,8 @@ class PostgreSQLTest: public CppUnit::TestCase void testReconnect(); + void testSqlState(); + void setUp(); void tearDown();