From 9758d7cdc98f0d948581fb5630c33e98e4b52855 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 6 Jan 2017 02:11:57 +0000 Subject: Use SQL hash for prepared statement names, increases reuse and avoids random reuse --- libpqpp/pq-bulkselectcommand.cpp | 4 ++-- libpqpp/pq-bulkselectcommand.h | 2 +- libpqpp/pq-command.cpp | 7 ++++--- libpqpp/pq-command.h | 4 +++- libpqpp/pq-connection.cpp | 13 +++++++------ libpqpp/pq-connection.h | 2 -- libpqpp/pq-cursorselectcommand.cpp | 4 ++-- libpqpp/pq-cursorselectcommand.h | 2 +- libpqpp/pq-modifycommand.cpp | 4 ++-- libpqpp/pq-modifycommand.h | 2 +- libpqpp/pq-prepared.cpp | 5 ++--- libpqpp/pq-prepared.h | 4 +--- 12 files changed, 26 insertions(+), 27 deletions(-) diff --git a/libpqpp/pq-bulkselectcommand.cpp b/libpqpp/pq-bulkselectcommand.cpp index d745e64..503d535 100644 --- a/libpqpp/pq-bulkselectcommand.cpp +++ b/libpqpp/pq-bulkselectcommand.cpp @@ -3,10 +3,10 @@ #include "pq-column.h" #include "pq-error.h" -PQ::BulkSelectCommand::BulkSelectCommand(Connection * conn, const std::string & sql, unsigned int no, const DB::CommandOptions * opts) : +PQ::BulkSelectCommand::BulkSelectCommand(Connection * conn, const std::string & sql, const DB::CommandOptions * opts) : DB::Command(sql), PQ::SelectBase(sql), - PQ::PreparedStatement(conn, sql, no, opts), + PQ::PreparedStatement(conn, sql, opts), executed(false) { } diff --git a/libpqpp/pq-bulkselectcommand.h b/libpqpp/pq-bulkselectcommand.h index a54a5a4..9b76c4d 100644 --- a/libpqpp/pq-bulkselectcommand.h +++ b/libpqpp/pq-bulkselectcommand.h @@ -11,7 +11,7 @@ namespace PQ { class Column; class BulkSelectCommand : public SelectBase, public PreparedStatement { public: - BulkSelectCommand(Connection *, const std::string & sql, unsigned int no, const DB::CommandOptions *); + BulkSelectCommand(Connection *, const std::string & sql, const DB::CommandOptions *); bool fetch() override; void execute() override; diff --git a/libpqpp/pq-command.cpp b/libpqpp/pq-command.cpp index a6259df..5ff83f0 100644 --- a/libpqpp/pq-command.cpp +++ b/libpqpp/pq-command.cpp @@ -5,10 +5,11 @@ #include #include -AdHocFormatter(PQCommondStatement, "pStatement_%?_%?"); -PQ::Command::Command(Connection * conn, const std::string & sql, unsigned int no) : +AdHocFormatter(PQCommondStatement, "pStatement_id%?"); +PQ::Command::Command(Connection * conn, const std::string & sql, const DB::CommandOptions * opts) : DB::Command(sql), - stmntName(PQCommondStatement::get(no, this)), + hash(opts && opts->hash ? *opts->hash : std::hash()(sql)), + stmntName(PQCommondStatement::get(hash)), c(conn) { } diff --git a/libpqpp/pq-command.h b/libpqpp/pq-command.h index 056706e..e054da8 100644 --- a/libpqpp/pq-command.h +++ b/libpqpp/pq-command.h @@ -5,6 +5,7 @@ #include #include #include +#include "pq-connection.h" namespace PQ { class Connection; @@ -21,7 +22,7 @@ namespace PQ { class Command : public virtual DB::Command { public: - Command(Connection *, const std::string & sql, unsigned int no); + Command(Connection *, const std::string & sql, const DB::CommandOptions *); virtual ~Command() = 0; void bindParamI(unsigned int, int) override; @@ -44,6 +45,7 @@ namespace PQ { void bindNull(unsigned int) override; protected: void prepareSql(std::stringstream & psql, const std::string & sql) const; + Connection::StatementHash hash; const std::string stmntName; Connection * const c; diff --git a/libpqpp/pq-connection.cpp b/libpqpp/pq-connection.cpp index 547923f..643e021 100644 --- a/libpqpp/pq-connection.cpp +++ b/libpqpp/pq-connection.cpp @@ -28,8 +28,7 @@ PQ::ConnectionError::ConnectionError(const PGconn * conn) : } PQ::Connection::Connection(const std::string & info) : - conn(PQconnectdb(info.c_str())), - pstmntNo(0) + conn(PQconnectdb(info.c_str())) { if (PQstatus(conn) != CONNECTION_OK) { ConnectionError ce(conn); @@ -102,15 +101,15 @@ PQ::Connection::newSelectCommand(const std::string & sql, const DB::CommandOptio { auto pqco = dynamic_cast(opts); if (pqco && !pqco->useCursor) { - return new BulkSelectCommand(this, sql, pstmntNo++, opts); + return new BulkSelectCommand(this, sql, opts); } - return new CursorSelectCommand(this, sql, pstmntNo++, pqco); + return new CursorSelectCommand(this, sql, pqco, opts); } DB::ModifyCommand * PQ::Connection::newModifyCommand(const std::string & sql, const DB::CommandOptions * opts) { - return new ModifyCommand(this, sql, pstmntNo++, opts); + return new ModifyCommand(this, sql, opts); } bool @@ -176,10 +175,12 @@ PQ::Connection::bulkUploadData(const char * data, size_t len) const } } +static const std::string selectLastVal("SELECT lastval()"); +static const DB::CommandOptions selectLastValOpts(std::hash()(selectLastVal)); int64_t PQ::Connection::insertId() { - BulkSelectCommand getId(this, "SELECT lastval()", pstmntNo++, NULL); + BulkSelectCommand getId(this, selectLastVal, &selectLastValOpts); int64_t id = -1; while (getId.fetch()) { getId[0] >> id; diff --git a/libpqpp/pq-connection.h b/libpqpp/pq-connection.h index 1659c13..bb102df 100644 --- a/libpqpp/pq-connection.h +++ b/libpqpp/pq-connection.h @@ -47,8 +47,6 @@ namespace PQ { private: static bool checkResultInt(PGresult * res, int expected, int alternative); - - mutable unsigned int pstmntNo; }; typedef boost::shared_ptr ConnectionPtr; } diff --git a/libpqpp/pq-cursorselectcommand.cpp b/libpqpp/pq-cursorselectcommand.cpp index d130b89..d754680 100644 --- a/libpqpp/pq-cursorselectcommand.cpp +++ b/libpqpp/pq-cursorselectcommand.cpp @@ -7,10 +7,10 @@ AdHocFormatter(PQCursorSelectDeclare, "DECLARE %? CURSOR FOR "); AdHocFormatter(PQCursorSelectFetch, "FETCH %? IN %?"); AdHocFormatter(PQCursorSelectClose, "CLOSE %?"); -PQ::CursorSelectCommand::CursorSelectCommand(Connection * conn, const std::string & sql, unsigned int no, const PQ::CommandOptions * pqco) : +PQ::CursorSelectCommand::CursorSelectCommand(Connection * conn, const std::string & sql, const PQ::CommandOptions * pqco, const DB::CommandOptions * opts) : DB::Command(sql), PQ::SelectBase(sql), - PQ::Command(conn, sql, no), + PQ::Command(conn, sql, opts), executed(false), txOpened(false), fTuples(pqco ? pqco->fetchTuples : 35), diff --git a/libpqpp/pq-cursorselectcommand.h b/libpqpp/pq-cursorselectcommand.h index 417cff9..8182210 100644 --- a/libpqpp/pq-cursorselectcommand.h +++ b/libpqpp/pq-cursorselectcommand.h @@ -11,7 +11,7 @@ namespace PQ { class Column; class CursorSelectCommand : public SelectBase, public Command { public: - CursorSelectCommand(Connection *, const std::string & sql, unsigned int no, const PQ::CommandOptions *); + CursorSelectCommand(Connection *, const std::string & sql, const PQ::CommandOptions *, const DB::CommandOptions *); virtual ~CursorSelectCommand(); bool fetch() override; diff --git a/libpqpp/pq-modifycommand.cpp b/libpqpp/pq-modifycommand.cpp index f8e4d63..7629f00 100644 --- a/libpqpp/pq-modifycommand.cpp +++ b/libpqpp/pq-modifycommand.cpp @@ -3,10 +3,10 @@ #include #include "pq-connection.h" -PQ::ModifyCommand::ModifyCommand(Connection * conn, const std::string & sql, unsigned int no, const DB::CommandOptions * opts) : +PQ::ModifyCommand::ModifyCommand(Connection * conn, const std::string & sql, const DB::CommandOptions * opts) : DB::Command(sql), DB::ModifyCommand(sql), - PQ::PreparedStatement(conn, sql, no, opts) + PQ::PreparedStatement(conn, sql, opts) { } diff --git a/libpqpp/pq-modifycommand.h b/libpqpp/pq-modifycommand.h index 4f0a481..18f5a8b 100644 --- a/libpqpp/pq-modifycommand.h +++ b/libpqpp/pq-modifycommand.h @@ -8,7 +8,7 @@ namespace PQ { class ModifyCommand : public DB::ModifyCommand, public PreparedStatement { public: - ModifyCommand(Connection *, const std::string & sql, unsigned int no, const DB::CommandOptions *); + ModifyCommand(Connection *, const std::string & sql, const DB::CommandOptions *); virtual ~ModifyCommand(); unsigned int execute(bool) override; diff --git a/libpqpp/pq-prepared.cpp b/libpqpp/pq-prepared.cpp index 8e6cea5..63a1cb5 100644 --- a/libpqpp/pq-prepared.cpp +++ b/libpqpp/pq-prepared.cpp @@ -1,10 +1,9 @@ #include "pq-prepared.h" #include "pq-connection.h" -PQ::PreparedStatement::PreparedStatement(Connection * c, const std::string & sql, unsigned int no, const DB::CommandOptions * opts) : +PQ::PreparedStatement::PreparedStatement(Connection * c, const std::string & sql, const DB::CommandOptions * opts) : DB::Command(sql), - Command(c, sql, no), - hash(opts && opts->hash ? *opts->hash : std::hash()(sql)), + Command(c, sql, opts), pstmt(nullptr) { } diff --git a/libpqpp/pq-prepared.h b/libpqpp/pq-prepared.h index 0f745c9..d70a388 100644 --- a/libpqpp/pq-prepared.h +++ b/libpqpp/pq-prepared.h @@ -2,16 +2,14 @@ #define stuff #include "pq-command.h" -#include "pq-connection.h" namespace PQ { class PreparedStatement : public Command { protected: - PreparedStatement(Connection *, const std::string &, unsigned int, const DB::CommandOptions *); + PreparedStatement(Connection *, const std::string &, const DB::CommandOptions *); virtual ~PreparedStatement() = default; const char * prepare() const; - Connection::StatementHash hash; mutable const char * pstmt; }; } -- cgit v1.2.3