From a6be6d86457a0b5dc982a0d4c7128a510313506d Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 25 Feb 2016 22:24:53 +0000 Subject: Reuse prepared statements --- libpqpp/pq-connection.h | 5 +++++ libpqpp/pq-modifycommand.cpp | 23 ++++++++++++----------- libpqpp/pq-modifycommand.h | 6 +++--- libpqpp/unittests/testpq.cpp | 16 ++++++++++++++++ 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/libpqpp/pq-connection.h b/libpqpp/pq-connection.h index 59b200c..1e9f265 100644 --- a/libpqpp/pq-connection.h +++ b/libpqpp/pq-connection.h @@ -2,6 +2,7 @@ #define PQ_CONNECTION_H #include +#include #include #include #include "pq-error.h" @@ -14,6 +15,9 @@ namespace PQ { class DLL_PUBLIC Connection : public DB::Connection { public: + typedef std::hash::result_type StatementHash; + typedef std::map PreparedStatements; + Connection(const std::string & info); ~Connection(); @@ -38,6 +42,7 @@ namespace PQ { void checkResultFree(PGresult * res, int expected, int alternative = -1) const; PGconn * conn; + PreparedStatements preparedStatements; private: static bool checkResultInt(PGresult * res, int expected, int alternative); diff --git a/libpqpp/pq-modifycommand.cpp b/libpqpp/pq-modifycommand.cpp index 4c4ca0c..e59908e 100644 --- a/libpqpp/pq-modifycommand.cpp +++ b/libpqpp/pq-modifycommand.cpp @@ -7,7 +7,7 @@ PQ::ModifyCommand::ModifyCommand(Connection * conn, const std::string & sql, uns DB::Command(sql), DB::ModifyCommand(sql), PQ::Command(conn, sql, no), - prepared(false) + hash(std::hash()(sql)) { } @@ -15,24 +15,25 @@ PQ::ModifyCommand::~ModifyCommand() { } -void +PQ::Connection::PreparedStatements::const_iterator PQ::ModifyCommand::prepare() const { - if (!prepared) { - std::string psql; - psql.reserve(sql.length() + 20); - prepareSql(psql, sql); - c->checkResultFree(PQprepare( - c->conn, stmntName.c_str(), psql.c_str(), values.size(), NULL), PGRES_COMMAND_OK); - prepared = true; + auto i = c->preparedStatements.find(hash); + if (i != c->preparedStatements.end()) { + return i; } + std::string psql; + psql.reserve(sql.length() + 20); + prepareSql(psql, sql); + c->checkResultFree(PQprepare( + c->conn, stmntName.c_str(), psql.c_str(), values.size(), NULL), PGRES_COMMAND_OK); + return c->preparedStatements.insert({hash, stmntName}).first; } unsigned int PQ::ModifyCommand::execute(bool anc) { - prepare(); - PGresult * res = PQexecPrepared(c->conn, stmntName.c_str(), values.size(), &values.front(), &lengths.front(), NULL, 0); + PGresult * res = PQexecPrepared(c->conn, prepare()->second.c_str(), values.size(), &values.front(), &lengths.front(), NULL, 0); c->checkResult(res, PGRES_COMMAND_OK, PGRES_TUPLES_OK); unsigned int rows = atoi(PQcmdTuples(res)); PQclear(res); diff --git a/libpqpp/pq-modifycommand.h b/libpqpp/pq-modifycommand.h index 5f48074..33fd333 100644 --- a/libpqpp/pq-modifycommand.h +++ b/libpqpp/pq-modifycommand.h @@ -3,9 +3,9 @@ #include #include "pq-command.h" +#include "pq-connection.h" namespace PQ { - class Connection; class ModifyCommand : public DB::ModifyCommand, public Command { public: ModifyCommand(Connection *, const std::string & sql, unsigned int no); @@ -14,8 +14,8 @@ namespace PQ { unsigned int execute(bool) override; private: - void prepare() const; - mutable bool prepared; + Connection::PreparedStatements::const_iterator prepare() const; + const Connection::StatementHash hash; }; } diff --git a/libpqpp/unittests/testpq.cpp b/libpqpp/unittests/testpq.cpp index 80757db..3d8c804 100644 --- a/libpqpp/unittests/testpq.cpp +++ b/libpqpp/unittests/testpq.cpp @@ -262,6 +262,22 @@ BOOST_AUTO_TEST_CASE( reconnectInTx ) delete rok; } +BOOST_AUTO_TEST_CASE( statementReuse ) +{ + auto ro = DB::MockDatabase::openConnectionTo("pqmock"); + auto pqconn = dynamic_cast(ro); + BOOST_REQUIRE_EQUAL(pqconn->preparedStatements.size(), 0); + for (int y = 0; y < 4; y += 1) { + auto m1 = ro->modify("INSERT INTO test(id) VALUES(?)"); + for (int x = 0; x < 4; x += 1) { + m1->bindParamI(0, x); + m1->execute(); + } + } + BOOST_REQUIRE_EQUAL(pqconn->preparedStatements.size(), 1); + delete ro; +} + BOOST_AUTO_TEST_SUITE_END(); BOOST_AUTO_TEST_CASE( connfail ) -- cgit v1.2.3