Added Params class for passing query parameters seperatly from the query string.

This commit is contained in:
Eelke Klein 2017-02-04 11:52:42 +01:00
parent 468779ba38
commit 7a22b4cbea
2 changed files with 195 additions and 29 deletions

View file

@ -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<const char *> 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);

View file

@ -6,9 +6,12 @@
#include <cassert>
#include <QString>
#include <vector>
#include <codecvt>
#include <memory>
#include <fmt/format.h>
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 <typename T>
// 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<const char *>;
void deleteValues()
{
for (auto e : m_paramValues)
delete[] e;
}
/* Assumes other lists already have been copied */
void copyValues(const t_paramValues &r);
std::vector<Oid> m_paramTypes;
t_paramValues m_paramValues;
std::vector<int> m_paramLengths; ///< postgresql ignores lengths for text parameters but we will it anyway for efficient copying
std::vector<int> 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 {
//