#include "Pgsql_Connection.h" #include "Pgsql_declare.h" #include "Pgsql_PgException.h" #include "Pgsql_Params.h" #include #include using namespace Pgsql; Connection::Connection() = default; Connection::~Connection() { close(); } Connection::Connection(Connection &&rhs) : conn(rhs.conn) { rhs.conn = nullptr; } Connection& Connection::operator=(Connection &&rhs) { close(); conn = rhs.conn; rhs.conn = nullptr; return *this; } void Connection::close() { if (conn) { PQfinish(conn); conn = nullptr; } } Canceller Connection::getCancel() { Canceller c(PQgetCancel(conn)); return c; } void Connection::connect(const char *params) { conn = PQconnectdb(params); testForConnectionError(conn); } void Connection::connect(const char *const * keywords, const char* const * values, int expand_dbname) { conn = PQconnectdbParams(keywords, values, expand_dbname); testForConnectionError(conn); } bool Connection::connectStart(const char* params) { conn = PQconnectStart(params); return conn != nullptr; } bool Connection::connectStart(const char * const *keywords, const char * const *values) { conn = PQconnectStartParams(keywords, values, 0); return conn != nullptr; } PostgresPollingStatusType Connection::connectPoll() { return PQconnectPoll(conn); } ConnStatusType Connection::status() { return PQstatus(conn); } int Connection::socket() { return PQsocket(conn); } std::string Connection::getErrorMessage() const { std::string result; if (conn) result = PQerrorMessage(conn); else result = "no connection"; return result; } Result Connection::query(const char * command) { PGresult *result = PQexec(conn, command); throwError(result); return Result(result); } Result Connection::queryParam(const char * command, const Params ¶ms) { PGresult *result = PQexecParams(conn, command, params.size(), params.types(), params.values(), params.lengths(), params.formats(), 0); throwError(result); return Result(result); } Result Connection::queryParam(const QString &command, const Params ¶ms) { return queryParam(command.toUtf8().data(), params); } void Connection::sendQuery(const char *query) { int res = PQsendQuery(conn, query); if (res == 0) throw PgConnectionError(PQerrorMessage(conn)); } void Connection::sendQueryParams(const char * command, const Params ¶ms) { int res = PQsendQueryParams(conn, command, params.size(), params.types(), params.values(), params.lengths(), params.formats(), 0); // text format if (res == 0) throw PgConnectionError(PQerrorMessage(conn)); } std::shared_ptr Connection::getResult() { PGresult *r = PQgetResult(conn); if (r) { throwError(r); return std::make_shared(r); } else return nullptr; } std::shared_ptr Connection::getResultNoThrow() { PGresult *r = PQgetResult(conn); if (r) return std::make_shared(r); else return nullptr; } bool Connection::consumeInput() { int res = PQconsumeInput(conn); return res == 1; } bool Connection::isBusy() { int res = PQisBusy(conn); return res == 1; } void Connection::setNoticeReceiver(std::function callback) { notifyReceiver = callback; PQsetNoticeReceiver(conn, Connection::notifyReceiveFunc , reinterpret_cast(this)); } std::string Connection::escapeLiteral(const std::string_view &literal) { std::unique_ptr result( PQescapeLiteral(conn, literal.data(), literal.length()), [](char*p) { if (p) PQfreemem(p); }); if (result) return std::string(result.get()); throw std::runtime_error("escapeLiteral(string_view) failed"); } QString Connection::escapeLiteral(const QString &literal) { auto u8 = literal.toUtf8(); std::unique_ptr result( PQescapeLiteral(conn, u8.data(), u8.length()), [](char*p) { if (p) PQfreemem(p); }); if (result) return QString::fromUtf8(result.get()); throw std::runtime_error("escapeLiteral(QString) failed"); } std::string Connection::escapeIdentifier(const std::string_view &ident) { std::unique_ptr result( PQescapeIdentifier(conn, ident.data(), ident.length()), [](char*p) { if (p) PQfreemem(p); }); if (result) return std::string(result.get()); throw std::runtime_error("escapeIdentifier failed"); } QString Connection::escapeIdentifier(const QString &ident) { auto u8 = ident.toUtf8(); std::unique_ptr result( PQescapeIdentifier(conn, u8.data(), u8.length()), [](char*p) { if (p) PQfreemem(p); }); if (result) return QString::fromUtf8(result.get()); throw std::runtime_error("escapeIdentifier(QString) failed"); } void Connection::notifyReceiveFunc(void *arg, const PGresult *result) { Connection *c = reinterpret_cast(arg); c->notifyReceiver(result); } QString Connection::getDBName() const { return QString::fromUtf8(PQdb(conn)); } void Connection::testForConnectionError(PGconn *conn) { std::string error_msg; if (conn) { ConnStatusType status = PQstatus(conn); if (status == CONNECTION_OK) return; error_msg = PQerrorMessage(conn); } else error_msg = "Unknown connection failure (maybe out of memory?)"; throw PgConnectionError(error_msg); } void Connection::throwError(PGresult *result) const { auto state = PQresultStatus(result); if (state == PGRES_BAD_RESPONSE) ; // communication problem else if (state == PGRES_FATAL_ERROR) { auto details = Pgsql::ErrorDetails::createErrorDetailsFromPGresult(result); throw PgResultError(details); } }