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
This commit is contained in:
omerbrandis 2023-10-20 18:44:04 +03:00 committed by GitHub
parent 542b814f27
commit 3793c0a515
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 77 additions and 7 deletions

View File

@ -36,6 +36,11 @@ public:
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 @@ public:
/// 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

View File

@ -13,7 +13,7 @@
#include "Poco/Data/PostgreSQL/PostgreSQLException.h"
#include <cstring>
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

View File

@ -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;

View File

@ -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);

View File

@ -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 @@ public:
void testReconnect();
void testSqlState();
void setUp();
void tearDown();