pgLab/pgsql/Pgsql_Connection.cpp
eelke 0cef509771 Correct tablespace names are now shown in the list of tables.
Slightly more complex then you may expect because the tablespace specified by the tables tends to be oid 0
which means the default tablespace is used. However this does not mean pg_default, it means the tablespace
as defined as standard in the database definition. So we need to know what the current dbname is retrieve
it's details from the catalog and retrieve that tablespace to know what to show for an oid of 0.
2018-08-27 21:14:57 +02:00

270 lines
5.3 KiB
C++

#include "Pgsql_Connection.h"
#include "Pgsql_declare.h"
#include "Pgsql_Params.h"
#include <memory>
#include <stdexcept>
using namespace Pgsql;
Canceller::Canceller(PGcancel *c)
: m_cancel(c)
{}
Canceller::Canceller(Canceller&& rhs)
: m_cancel(rhs.m_cancel)
{
rhs.m_cancel = nullptr;
}
Canceller& Canceller::operator=(Canceller&& rhs)
{
if (m_cancel) {
PQfreeCancel(m_cancel);
}
m_cancel = rhs.m_cancel;
rhs.m_cancel = nullptr;
return *this;
}
Canceller::~Canceller()
{
if (m_cancel) {
PQfreeCancel(m_cancel);
}
}
bool Canceller::cancel(std::string *error)
{
const int errbuf_size = 256;
char errbuf[errbuf_size];
bool res = PQcancel(m_cancel, errbuf, errbuf_size);
if (!res && error) {
*error = errbuf;
}
return res;
}
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;
}
bool Connection::connect(const char *params)
{
bool result = false;
conn = PQconnectdb(params);
if (conn) {
ConnStatusType status = PQstatus(conn);
result = (status == CONNECTION_OK);
}
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);
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);
return Result(result);
}
Result Connection::queryParam(const char * command, const Params &params)
{
PGresult *result = PQexecParams(conn, command, params.size(), params.types(),
params.values(), params.lengths(), params.formats(), 0);
return Result(result);
}
Result Connection::queryParam(const QString &command, const Params &params)
{
return queryParam(command.toUtf8().data(), params);
}
bool Connection::sendQuery(const char *query)
{
int res = PQsendQuery(conn, query);
return res == 1;
}
bool Connection::sendQueryParams(const char * command, const Params &params)
{
int res = PQsendQueryParams(conn, command, params.size(), params.types(),
params.values(), params.lengths(), params.formats(),
0); // text format
return res == 1;
}
std::shared_ptr<Result> Connection::getResult()
{
PGresult *r = PQgetResult(conn);
if (r) {
return std::make_shared<Result>(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<void(const PGresult *)> callback)
{
notifyReceiver = callback;
PQsetNoticeReceiver(conn,
Connection::notifyReceiveFunc
, reinterpret_cast<void*>(this));
}
std::string Connection::escapeLiteral(const std::string_view &literal)
{
std::unique_ptr<char, void(*)(char*)> 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<char, void(*)(char*)> 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<char, void(*)(char*)> 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<char, void(*)(char*)> 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<Connection *>(arg);
c->notifyReceiver(result);
}
QString Connection::getDBName() const
{
return QString::fromUtf8(PQdb(conn));
}