From 78d8eeadcf6642eb52b3b178d6da620b0bb34289 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 8 Oct 2023 16:58:13 +0100 Subject: Use unique_ptr for execution results --- libpqpp/pq-bulkselectcommand.cpp | 13 +++++-------- libpqpp/pq-bulkselectcommand.h | 3 --- libpqpp/pq-column.cpp | 10 ++++++---- libpqpp/pq-connection.cpp | 26 ++++++++------------------ libpqpp/pq-connection.h | 4 ++-- libpqpp/pq-cursorselectcommand.cpp | 17 +++++++---------- libpqpp/pq-helpers.h | 5 +++++ libpqpp/pq-modifycommand.cpp | 9 ++++----- libpqpp/pq-prepared.cpp | 4 ++-- libpqpp/pq-selectbase.cpp | 14 +++----------- libpqpp/pq-selectbase.h | 5 ++--- 11 files changed, 44 insertions(+), 66 deletions(-) diff --git a/libpqpp/pq-bulkselectcommand.cpp b/libpqpp/pq-bulkselectcommand.cpp index 298261e..303ed53 100644 --- a/libpqpp/pq-bulkselectcommand.cpp +++ b/libpqpp/pq-bulkselectcommand.cpp @@ -10,21 +10,20 @@ PQ::BulkSelectCommand::BulkSelectCommand(Connection * conn, const std::string & sql, const PQ::CommandOptionsCPtr & pqco, const DB::CommandOptionsCPtr & opts) : DB::Command(sql), - PQ::SelectBase(sql, pqco), PQ::PreparedStatement(conn, sql, opts), executed(false) + PQ::SelectBase(sql, pqco), PQ::PreparedStatement(conn, sql, opts) { } void PQ::BulkSelectCommand::execute() { - if (!executed) { + if (!execRes) { execRes = c->checkResult(PQexecPrepared(c->conn, prepare(), static_cast(values.size()), values.data(), lengths.data(), formats.data(), binary), PGRES_TUPLES_OK); - nTuples = static_cast(PQntuples(execRes)); + nTuples = static_cast(PQntuples(execRes.get())); tuple = static_cast(-1); - createColumns(execRes); - executed = true; + createColumns(); } } @@ -36,9 +35,7 @@ PQ::BulkSelectCommand::fetch() return true; } else { - PQclear(execRes); - execRes = nullptr; - executed = false; + execRes.reset(); return false; } } diff --git a/libpqpp/pq-bulkselectcommand.h b/libpqpp/pq-bulkselectcommand.h index 6e186a1..10d4fbf 100644 --- a/libpqpp/pq-bulkselectcommand.h +++ b/libpqpp/pq-bulkselectcommand.h @@ -17,9 +17,6 @@ namespace PQ { bool fetch() override; void execute() override; - - private: - mutable bool executed; }; } diff --git a/libpqpp/pq-column.cpp b/libpqpp/pq-column.cpp index f78863c..3ed8e20 100644 --- a/libpqpp/pq-column.cpp +++ b/libpqpp/pq-column.cpp @@ -12,26 +12,28 @@ #include PQ::Column::Column(const SelectBase * s, unsigned int i) : - DB::Column(PQfname(s->execRes, static_cast(i)), i), sc(s), oid(PQftype(sc->execRes, static_cast(colNo))) + DB::Column(PQfname(s->execRes.get(), static_cast(i)), i), sc(s), + oid(PQftype(sc->execRes.get(), static_cast(colNo))) { } bool PQ::Column::isNull() const { - return PQgetisnull(sc->execRes, static_cast(sc->tuple), static_cast(colNo)); + return PQgetisnull(sc->execRes.get(), static_cast(sc->tuple), static_cast(colNo)); } std::size_t PQ::Column::length() const { - return static_cast(PQgetlength(sc->execRes, static_cast(sc->tuple), static_cast(colNo))); + return static_cast( + PQgetlength(sc->execRes.get(), static_cast(sc->tuple), static_cast(colNo))); } const char * PQ::Column::value() const { - return PQgetvalue(sc->execRes, static_cast(sc->tuple), static_cast(colNo)); + return PQgetvalue(sc->execRes.get(), static_cast(sc->tuple), static_cast(colNo)); } void diff --git a/libpqpp/pq-connection.cpp b/libpqpp/pq-connection.cpp index a65d88b..dc3cf13 100644 --- a/libpqpp/pq-connection.cpp +++ b/libpqpp/pq-connection.cpp @@ -55,25 +55,25 @@ PQ::Connection::~Connection() void PQ::Connection::beginTxInt() { - checkResultFree(PQexec(conn, "BEGIN"), PGRES_COMMAND_OK); + checkResult(PQexec(conn, "BEGIN"), PGRES_COMMAND_OK); } void PQ::Connection::commitTxInt() { - checkResultFree(PQexec(conn, "COMMIT"), PGRES_COMMAND_OK); + checkResult(PQexec(conn, "COMMIT"), PGRES_COMMAND_OK); } void PQ::Connection::rollbackTxInt() { - checkResultFree(PQexec(conn, "ROLLBACK"), PGRES_COMMAND_OK); + checkResult(PQexec(conn, "ROLLBACK"), PGRES_COMMAND_OK); } void PQ::Connection::execute(const std::string & sql, const DB::CommandOptionsCPtr &) { - checkResultFree(PQexec(conn, sql.c_str()), PGRES_COMMAND_OK, PGRES_TUPLES_OK); + checkResult(PQexec(conn, sql.c_str()), PGRES_COMMAND_OK, PGRES_TUPLES_OK); } DB::BulkDeleteStyle @@ -130,24 +130,14 @@ PQ::Connection::checkResultInt(PGresult * res, int expected, int alt) return (PQresultStatus(res) == expected) || (alt != -1 && (PQresultStatus(res) == alt)); } -PGresult * +PQ::ResultPtr PQ::Connection::checkResult(PGresult * res, int expected, int alt) const { if (!checkResultInt(res, expected, alt)) { PQclear(res); throw Error(conn); } - return res; -} - -void -PQ::Connection::checkResultFree(PGresult * res, int expected, int alt) const -{ - if (!checkResultInt(res, expected, alt)) { - PQclear(res); - throw Error(conn); - } - PQclear(res); + return ResultPtr {res}; } AdHocFormatter(PQConnectionCopyFrom, "COPY %? FROM STDIN %?"); @@ -155,7 +145,7 @@ AdHocFormatter(PQConnectionCopyFrom, "COPY %? FROM STDIN %?"); void PQ::Connection::beginBulkUpload(const char * table, const char * extra) { - checkResultFree(PQexec(conn, PQConnectionCopyFrom::get(table, extra).c_str()), PGRES_COPY_IN); + checkResult(PQexec(conn, PQConnectionCopyFrom::get(table, extra).c_str()), PGRES_COPY_IN); } void @@ -168,7 +158,7 @@ PQ::Connection::endBulkUpload(const char * msg) if (rc != 1) { throw Error(conn); } - checkResultFree(PQgetResult(conn), PGRES_COMMAND_OK); + checkResult(PQgetResult(conn), PGRES_COMMAND_OK); } size_t diff --git a/libpqpp/pq-connection.h b/libpqpp/pq-connection.h index 83da2d4..af013ab 100644 --- a/libpqpp/pq-connection.h +++ b/libpqpp/pq-connection.h @@ -3,6 +3,7 @@ #include "command_fwd.h" #include "pq-error.h" +#include "pq-helpers.h" #include #include #include @@ -46,8 +47,7 @@ namespace PQ { void endBulkUpload(const char *) override; size_t bulkUploadData(const char *, size_t) const override; - PGresult * checkResult(PGresult * res, int expected, int alternative = -1) const; - void checkResultFree(PGresult * res, int expected, int alternative = -1) const; + ResultPtr checkResult(PGresult * res, int expected, int alternative = -1) const; PGconn * conn; mutable PreparedStatements preparedStatements; diff --git a/libpqpp/pq-cursorselectcommand.cpp b/libpqpp/pq-cursorselectcommand.cpp index 8d3a7bf..bfb69d4 100644 --- a/libpqpp/pq-cursorselectcommand.cpp +++ b/libpqpp/pq-cursorselectcommand.cpp @@ -5,7 +5,6 @@ #include "pq-selectbase.h" #include #include -#include #include #include #include @@ -25,7 +24,7 @@ PQ::CursorSelectCommand::CursorSelectCommand(Connection * conn, const std::strin PQ::CursorSelectCommand::~CursorSelectCommand() { if (executed && PQtransactionStatus(c->conn) != PQTRANS_INERROR) { - c->checkResultFree((PQexec(c->conn, s_close.c_str())), PGRES_COMMAND_OK); + c->checkResult(PQexec(c->conn, s_close.c_str()), PGRES_COMMAND_OK); } } @@ -45,11 +44,11 @@ PQ::CursorSelectCommand::execute() if (s_declare.empty()) { s_declare = mkdeclare(); } - c->checkResultFree(PQexecParams(c->conn, s_declare.c_str(), static_cast(values.size()), nullptr, - values.data(), lengths.data(), formats.data(), binary), + c->checkResult(PQexecParams(c->conn, s_declare.c_str(), static_cast(values.size()), nullptr, values.data(), + lengths.data(), formats.data(), binary), PGRES_COMMAND_OK); fetchTuples(); - createColumns(execRes); + createColumns(); executed = true; } } @@ -59,7 +58,7 @@ PQ::CursorSelectCommand::fetchTuples() { execRes = c->checkResult( PQexecParams(c->conn, s_fetch.c_str(), 0, nullptr, nullptr, nullptr, nullptr, binary), PGRES_TUPLES_OK); - nTuples = static_cast(PQntuples(execRes)); + nTuples = static_cast(PQntuples(execRes.get())); tuple = static_cast(-1); } @@ -69,8 +68,7 @@ PQ::CursorSelectCommand::fetch() execute(); if ((tuple + 1 >= nTuples) && (nTuples == fTuples)) { // Delete the previous result set - PQclear(execRes); - execRes = nullptr; + execRes.reset(); fetchTuples(); } if (++tuple < nTuples) { @@ -78,8 +76,7 @@ PQ::CursorSelectCommand::fetch() } else { PQclear(PQexec(c->conn, s_close.c_str())); - PQclear(execRes); - execRes = nullptr; + execRes.reset(); executed = false; return false; } diff --git a/libpqpp/pq-helpers.h b/libpqpp/pq-helpers.h index 76e5057..7861d57 100644 --- a/libpqpp/pq-helpers.h +++ b/libpqpp/pq-helpers.h @@ -1,6 +1,9 @@ #ifndef PQ_HELPERS_H #define PQ_HELPERS_H +#include "libpq-fe.h" +#include + namespace PQ { template struct pq_deleter { void @@ -9,6 +12,8 @@ namespace PQ { func(p); } }; + + using ResultPtr = std::unique_ptr>; } #endif diff --git a/libpqpp/pq-modifycommand.cpp b/libpqpp/pq-modifycommand.cpp index b29fda7..53c3231 100644 --- a/libpqpp/pq-modifycommand.cpp +++ b/libpqpp/pq-modifycommand.cpp @@ -15,11 +15,10 @@ PQ::ModifyCommand::ModifyCommand(Connection * conn, const std::string & sql, con unsigned int PQ::ModifyCommand::execute(bool anc) { - PGresult * res = PQexecPrepared( - c->conn, prepare(), static_cast(values.size()), values.data(), lengths.data(), formats.data(), 0); - c->checkResult(res, PGRES_COMMAND_OK, PGRES_TUPLES_OK); - auto rows = atoi(PQcmdTuples(res)); - PQclear(res); + const auto res = c->checkResult(PQexecPrepared(c->conn, prepare(), static_cast(values.size()), values.data(), + lengths.data(), formats.data(), 0), + PGRES_COMMAND_OK, PGRES_TUPLES_OK); + auto rows = atoi(PQcmdTuples(res.get())); if (rows == 0 && !anc) { throw DB::NoRowsAffected(); } diff --git a/libpqpp/pq-prepared.cpp b/libpqpp/pq-prepared.cpp index bf8bd08..8678c11 100644 --- a/libpqpp/pq-prepared.cpp +++ b/libpqpp/pq-prepared.cpp @@ -26,8 +26,8 @@ PQ::PreparedStatement::prepare() const } std::stringstream psql; prepareSql(psql, sql); - c->checkResultFree(PQprepare(c->conn, stmntName.c_str(), std::move(psql).str().c_str(), - static_cast(values.size()), nullptr), + c->checkResult(PQprepare(c->conn, stmntName.c_str(), std::move(psql).str().c_str(), static_cast(values.size()), + nullptr), PGRES_COMMAND_OK); return (pstmt = c->preparedStatements.insert({hash, stmntName}).first->second.c_str()); } diff --git a/libpqpp/pq-selectbase.cpp b/libpqpp/pq-selectbase.cpp index d884d06..00abdb9 100644 --- a/libpqpp/pq-selectbase.cpp +++ b/libpqpp/pq-selectbase.cpp @@ -9,22 +9,14 @@ #include PQ::SelectBase::SelectBase(const std::string & sql, const PQ::CommandOptionsCPtr & pqco) : - DB::Command(sql), DB::SelectCommand(sql), nTuples(0), tuple(0), execRes(nullptr), - binary(pqco ? pqco->fetchBinary : false) + DB::Command(sql), DB::SelectCommand(sql), nTuples(0), tuple(0), binary(pqco ? pqco->fetchBinary : false) { } -PQ::SelectBase::~SelectBase() -{ - if (execRes) { - PQclear(execRes); - } -} - void -PQ::SelectBase::createColumns(PGresult * execRes) +PQ::SelectBase::createColumns() { - auto nFields = PQnfields(execRes); + auto nFields = PQnfields(execRes.get()); for (decltype(nFields) f = 0; f < nFields; f += 1) { if (binary) { insertColumn(std::make_unique(this, f)); diff --git a/libpqpp/pq-selectbase.h b/libpqpp/pq-selectbase.h index 19bef7a..9d4ff57 100644 --- a/libpqpp/pq-selectbase.h +++ b/libpqpp/pq-selectbase.h @@ -12,12 +12,11 @@ namespace PQ { protected: SelectBase(const std::string & sql, const PQ::CommandOptionsCPtr & pqco); - ~SelectBase(); - void createColumns(PGresult *); + void createColumns(); unsigned int nTuples, tuple; - PGresult * execRes; + ResultPtr execRes; bool binary; }; } -- cgit v1.2.3