From de0ed498d4f3113ac30af8389f8946247824b652 Mon Sep 17 00:00:00 2001 From: Mateusz Loskot Date: Fri, 1 Mar 2013 01:13:05 +0000 Subject: [PATCH] Release PGresult when an exception is thrown Fix involves: * Call PQclear in throw_postgresql_soci_error * Change throw_postgresql_soci_error to take pointer by reference to effectively reset result * PostgreSQL tests pass * Close #86 Rename res to result for consistency. (std::unique_ptr would be bless for correct and simple RAII across SOCI) --- src/backends/postgresql/error.cpp | 14 +++++++++----- src/backends/postgresql/error.h | 4 ++-- src/backends/postgresql/session.cpp | 2 +- src/backends/postgresql/statement.cpp | 16 ++++++++-------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/backends/postgresql/error.cpp b/src/backends/postgresql/error.cpp index 667b14ca6..a5ce98906 100644 --- a/src/backends/postgresql/error.cpp +++ b/src/backends/postgresql/error.cpp @@ -28,11 +28,13 @@ std::string postgresql_soci_error::sqlstate() const return std::string(sqlstate_, 5); } -void soci::details::postgresql::get_error_details(PGresult *res, +void soci::details::postgresql::get_error_details(PGresult *result, std::string &msg, std::string &sqlstate) { - msg = PQresultErrorMessage(res); - const char *sqlst = PQresultErrorField(res, PG_DIAG_SQLSTATE); + assert(result); + + msg = PQresultErrorMessage(result); + const char *sqlst = PQresultErrorField(result, PG_DIAG_SQLSTATE); const char* blank_sql_state = " "; if (!sqlst) { @@ -42,11 +44,13 @@ void soci::details::postgresql::get_error_details(PGresult *res, sqlstate.assign(sqlst, 5); } -void soci::details::postgresql::throw_postgresql_soci_error(PGresult *res) +void soci::details::postgresql::throw_postgresql_soci_error(PGresult*& result) { std::string msg; std::string sqlstate; - get_error_details(res, msg, sqlstate); + get_error_details(result, msg, sqlstate); + PQclear(result); + result = NULL; throw postgresql_soci_error(msg, sqlstate.c_str()); } diff --git a/src/backends/postgresql/error.h b/src/backends/postgresql/error.h index 22e8394d5..9daf56209 100644 --- a/src/backends/postgresql/error.h +++ b/src/backends/postgresql/error.h @@ -19,9 +19,9 @@ namespace details namespace postgresql { -void throw_postgresql_soci_error(PGresult *res); +void throw_postgresql_soci_error(PGresult*& res); -void get_error_details(PGresult *res, std::string &msg, std::string &sqlstate); +void get_error_details(PGresult* res, std::string &msg, std::string &sqlstate); } // namespace postgresql diff --git a/src/backends/postgresql/session.cpp b/src/backends/postgresql/session.cpp index f0118325e..e66fd0b23 100644 --- a/src/backends/postgresql/session.cpp +++ b/src/backends/postgresql/session.cpp @@ -59,7 +59,6 @@ namespace // unnamed void hard_exec(PGconn * conn, char const * query, char const * errMsg) { PGresult* result = PQexec(conn, query); - if (0 == result) { throw soci_error(errMsg); @@ -68,6 +67,7 @@ void hard_exec(PGconn * conn, char const * query, char const * errMsg) ExecStatusType const status = PQresultStatus(result); if (PGRES_COMMAND_OK != status) { + // releases result with PQclear throw_postgresql_soci_error(result); } diff --git a/src/backends/postgresql/statement.cpp b/src/backends/postgresql/statement.cpp index 8157aa465..31b6e4723 100644 --- a/src/backends/postgresql/statement.cpp +++ b/src/backends/postgresql/statement.cpp @@ -162,18 +162,19 @@ void postgresql_statement_backend::prepare(std::string const & query, { statementName_ = session_.get_next_statement_name(); - PGresult * res = PQprepare(session_.conn_, statementName_.c_str(), + PGresult* result = PQprepare(session_.conn_, statementName_.c_str(), query_.c_str(), static_cast(names_.size()), NULL); - if (res == NULL) + if (result == NULL) { throw soci_error("Cannot prepare statement."); } - ExecStatusType status = PQresultStatus(res); + ExecStatusType status = PQresultStatus(result); if (status != PGRES_COMMAND_OK) { - throw_postgresql_soci_error(res); + // releases result with PQclear + throw_postgresql_soci_error(result); } - PQclear(res); + PQclear(result); } stType_ = stType; @@ -280,9 +281,7 @@ postgresql_statement_backend::execute(int number) result_ = PQexecParams(session_.conn_, query_.c_str(), static_cast(paramValues.size()), NULL, ¶mValues[0], NULL, NULL, 0); - #else - if (stType_ == st_repeatable_query) { // this query was separately prepared @@ -318,6 +317,7 @@ postgresql_statement_backend::execute(int number) ExecStatusType status = PQresultStatus(result_); if (status != PGRES_COMMAND_OK) { + // releases result_ with PQclear throw_postgresql_soci_error(result_); } PQclear(result_); @@ -342,7 +342,6 @@ postgresql_statement_backend::execute(int number) result_ = PQexec(session_.conn_, query_.c_str()); #else - if (stType_ == st_repeatable_query) { // this query was separately prepared @@ -404,6 +403,7 @@ postgresql_statement_backend::execute(int number) } else { + // releases result_ with PQclear throw_postgresql_soci_error(result_); // dummy, never reach