From 7a22b4cbea61ea15e36bd9968e19753e7b227866 Mon Sep 17 00:00:00 2001 From: Eelke Klein Date: Sat, 4 Feb 2017 11:52:42 +0100 Subject: [PATCH] Added Params class for passing query parameters seperatly from the query string. --- PgsqlConn.cpp | 95 +++++++++++++++++++++++++++++++++++++ PgsqlConn.h | 129 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 195 insertions(+), 29 deletions(-) diff --git a/PgsqlConn.cpp b/PgsqlConn.cpp index 411033f..75fa1a9 100644 --- a/PgsqlConn.cpp +++ b/PgsqlConn.cpp @@ -47,6 +47,77 @@ ErrorDetails ErrorDetails::createErrorDetailsFromPGresult(const PGresult *result } +Params::Params() +{} + +Params::Params(const Params& rhs) + : m_paramTypes(rhs.m_paramTypes) + , m_paramLengths(rhs.m_paramLengths) + , m_paramFormats(rhs.m_paramFormats) +{ + //std::vector m_paramValues; + copyValues(rhs.m_paramValues); +} + +Params& Params::operator=(const Params& rhs) +{ + if (&rhs != this) { + m_paramTypes = rhs.m_paramTypes; + m_paramLengths = rhs.m_paramLengths; + m_paramFormats = rhs.m_paramFormats; + copyValues(rhs.m_paramValues); + } + return *this; +} + +Params::Params(const Params&& rhs) + : m_paramTypes(std::move(rhs.m_paramTypes)) + , m_paramValues(std::move(rhs.m_paramValues)) + , m_paramLengths(std::move(rhs.m_paramLengths)) + , m_paramFormats(std::move(rhs.m_paramFormats)) +{} + +Params::~Params() +{ + deleteValues(); +} + +void Params::addText(const char *data, Oid oid) +{ + m_paramTypes.push_back(oid); + m_paramValues.push_back(data); + m_paramLengths.push_back(data ? strlen(data) + 1 : 0); + m_paramFormats.push_back(0); +} + +void Params::add(const QString &s, Oid oid) +{ + auto ba = s.toUtf8(); + const int len = ba.size(); + char * p = new char[len]; + std::memcpy(p, ba.data(), len); + addText(p, oid_varchar); +} + +void Params::addBinary(const char *data, int length, Oid oid) +{ + m_paramTypes.push_back(oid); + m_paramValues.push_back(data); + m_paramLengths.push_back(length); + m_paramFormats.push_back(1); +} + +void Params::clear() +{ + m_paramTypes.clear(); + deleteValues(); + m_paramValues.clear(); + m_paramLengths.clear(); + m_paramFormats.clear(); +} + + + bool Row::next() { if (m_row < m_result.getRows()) { @@ -56,6 +127,19 @@ bool Row::next() return false; } + +void Params::copyValues(const t_paramValues &r) +{ + const int n = m_paramTypes.size(); + m_paramValues.reserve(n); + for (int i = 0; i < n; ++i) { + const int len = m_paramLengths[i]; + char * p = new char[len]; + std::memcpy(p, r[i], len); + m_paramValues.push_back(p); + } +} + Value Row::get(int col) const { return m_result.get(col, m_row); @@ -289,6 +373,17 @@ bool Connection::connect(const char *params) return result; } +bool Connection::connect(const char *const * keywords, const char* const * values, int expand_dbname) +{ + bool result = false; + conn = PQconnectdbParams(keywords, values, expand_dbname); + if (conn) { + ConnStatusType status = PQstatus(conn); + result = (status == CONNECTION_OK); + } + return result; +} + bool Connection::connectStart(const char* params) { conn = PQconnectStart(params); diff --git a/PgsqlConn.h b/PgsqlConn.h index 2161fd6..f8ef26b 100644 --- a/PgsqlConn.h +++ b/PgsqlConn.h @@ -6,9 +6,12 @@ #include #include +#include #include #include +#include + namespace Pgsql { const Oid oid_bool = 16; @@ -19,8 +22,58 @@ namespace Pgsql { const Oid oid_float8 = 701; const Oid oid_numeric = 1700; const Oid oid_oid = 26; + const Oid oid_varchar = 1043; + + class Params { + public: + Params(); + Params(const Params& rhs); + Params& operator=(const Params& rhs); + Params(const Params&& rhs); + ~Params(); + +// template +// Params& add(const T& val, Oid oid = InvalidOid) +// { + +// fmt::FormatInt( +// int idx = i-1; +// m_strings[idx] = value_to_dbstring(val); +// m_paramValues[idx] = m_strings[idx].c_str(); + +// return *this; +// } + + + /** \brief Add a parameter to the list. + * + * The class takes ownership of data and will try to delete[] it. + */ + void addText(const char *data, Oid oid); + void add(const QString &s, Oid oid); + void addBinary(const char *data, int length, Oid oid); + void clear(); + + private: + using t_paramValues = std::vector; + + void deleteValues() + { + for (auto e : m_paramValues) + delete[] e; + } + + /* Assumes other lists already have been copied */ + void copyValues(const t_paramValues &r); + + std::vector m_paramTypes; + t_paramValues m_paramValues; + std::vector m_paramLengths; ///< postgresql ignores lengths for text parameters but we will it anyway for efficient copying + std::vector m_paramFormats; + }; + class Connection; /* This library has multiple layers. @@ -67,6 +120,8 @@ namespace Pgsql { std::string sourceFunction; }; + /** \brief Class that is returned as value of a cell to facilitate auto conversion. + */ class Value { public: Value(const char *val, Oid typ) @@ -122,6 +177,11 @@ namespace Pgsql { class Result; + /** \brief A reference to a specific row from a result. + * + * As it is a reference its contents won't be valid after its associated result has + * been destroyed. + */ class Row { public: Row(const Result &result, int row) @@ -144,7 +204,11 @@ namespace Pgsql { int m_row; }; - /** Non-copyable but movable wrapper for a postgresql result. */ + /** \brief Non-copyable but movable wrapper for a postgresql result. + * + * This class makes sure the result is removed from memory. It also supplies an iterator for the + * rows from the result facilitating also the use of the cpp for each. + */ class Result { public: class const_iterator { @@ -241,6 +305,8 @@ namespace Pgsql { }; + /** \brief Wrapper for a cancel object from libpq. + */ class Canceller { public: Canceller() = default; @@ -256,7 +322,11 @@ namespace Pgsql { PGcancel *m_cancel = nullptr; }; - + /** \brief Class for connecting to the database. + * + * The class isolates the programmer from the worst C style parts + * of the libpq API but is mostly a very thin wrapper. + */ class Connection { public: Connection(); @@ -274,6 +344,7 @@ namespace Pgsql { { return connect(params.toUtf8().data()); } + bool connect(const char *const * keywords, const char* const * values, int expand_dbname); bool connectStart(const char *params); @@ -330,44 +401,44 @@ namespace Pgsql { - class Field { - public: +// class Field { +// public: - std::string getName() const; +// std::string getName() const; - private: - //Tuples tuples; - int field; - // +// private: +// //Tuples tuples; +// int field; +// // - }; +// }; - class Tuples { - public: - int getRowCount() const; - int getColCount() const; +// class Tuples { +// public: +// int getRowCount() const; +// int getColCount() const; - Field getField(const std::string &fname); - Field getField(const int idx); +// Field getField(const std::string &fname); +// Field getField(const int idx); - class const_iterator { - public: - const_iterator& operator++(); - }; +// class const_iterator { +// public: +// const_iterator& operator++(); +// }; - void rewind(); +// void rewind(); - }; +// }; - class OkResult: public Result { - public: - /** If the result is a data result then returns an interface for processing this data. +// class OkResult: public Result { +// public: +// /** If the result is a data result then returns an interface for processing this data. - The returned interface remains valid as long as this OkResult exists. - */ - Tuples* hasTuples(); - }; +// The returned interface remains valid as long as this OkResult exists. +// */ +// Tuples* hasTuples(); +// }; // class ErrorResult: public Result { //