Query window has now buttons with icons made in the designer for better looks. Depending on received responses from the database the tabcontrol with the message, data and explain tab now switches to the appropriate tab.
321 lines
7.6 KiB
C++
321 lines
7.6 KiB
C++
#include "PgsqlConn.h"
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
using namespace Pgsql;
|
|
|
|
namespace {
|
|
|
|
void set_stdstring_with_charptr(std::string &s, const char *p)
|
|
{
|
|
if (p) {
|
|
s = p;
|
|
}
|
|
else {
|
|
s.clear();
|
|
}
|
|
}
|
|
|
|
} // einde unnamed namespace
|
|
|
|
ErrorDetails ErrorDetails::createErrorDetailsFromPGresult(const PGresult *result)
|
|
{
|
|
ErrorDetails r;
|
|
set_stdstring_with_charptr(r.state, PQresultErrorField(result, PG_DIAG_SQLSTATE)); ///< PG_DIAG_SQLSTATE Error code as listed in https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html
|
|
set_stdstring_with_charptr(r.severity, PQresultErrorField(result, PG_DIAG_SEVERITY));
|
|
set_stdstring_with_charptr(r.messagePrimary, PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY));
|
|
set_stdstring_with_charptr(r.messageDetail, PQresultErrorField(result, PG_DIAG_MESSAGE_DETAIL));
|
|
set_stdstring_with_charptr(r.messageHint, PQresultErrorField(result, PG_DIAG_MESSAGE_HINT));
|
|
const char * p = PQresultErrorField(result, PG_DIAG_STATEMENT_POSITION);
|
|
r.statementPosition = p != nullptr ? atoi(p) : -1; ///< First character is one, measured in characters not bytes!
|
|
p = PQresultErrorField(result, PG_DIAG_INTERNAL_POSITION);
|
|
r.internalPosition = p != nullptr ? atoi(p) : -1;
|
|
set_stdstring_with_charptr(r.internalQuery, PQresultErrorField(result, PG_DIAG_INTERNAL_QUERY));
|
|
set_stdstring_with_charptr(r.context, PQresultErrorField(result, PG_DIAG_CONTEXT));
|
|
set_stdstring_with_charptr(r.schemaName, PQresultErrorField(result, PG_DIAG_SCHEMA_NAME));
|
|
set_stdstring_with_charptr(r.tableName, PQresultErrorField(result, PG_DIAG_TABLE_NAME));
|
|
set_stdstring_with_charptr(r.columnName, PQresultErrorField(result, PG_DIAG_COLUMN_NAME));
|
|
set_stdstring_with_charptr(r.datatypeName, PQresultErrorField(result, PG_DIAG_DATATYPE_NAME));
|
|
set_stdstring_with_charptr(r.constraintName, PQresultErrorField(result, PG_DIAG_CONSTRAINT_NAME));
|
|
set_stdstring_with_charptr(r.sourceFile, PQresultErrorField(result, PG_DIAG_SOURCE_FILE));
|
|
set_stdstring_with_charptr(r.sourceLine, PQresultErrorField(result, PG_DIAG_SOURCE_LINE));
|
|
set_stdstring_with_charptr(r.sourceFunction, PQresultErrorField(result, PG_DIAG_SOURCE_FUNCTION));
|
|
return r;
|
|
}
|
|
|
|
Result::Result(PGresult *res)
|
|
: result(res)
|
|
{
|
|
if (res == nullptr) {
|
|
throw std::runtime_error("Passing nullptr to Result::Result is not allowed");
|
|
}
|
|
}
|
|
|
|
Result::~Result()
|
|
{
|
|
PQclear(result);
|
|
}
|
|
|
|
|
|
Result::Result(Result &&rhs)
|
|
: result(rhs.result)
|
|
{
|
|
rhs.result = nullptr;
|
|
}
|
|
|
|
Result& Result::operator=(Result &&rhs)
|
|
{
|
|
if (result) {
|
|
PQclear(result);
|
|
}
|
|
result = rhs.result;
|
|
rhs.result = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
Result::operator bool() const
|
|
{
|
|
return result != nullptr;
|
|
}
|
|
|
|
ExecStatusType Result::resultStatus()
|
|
{
|
|
return PQresultStatus(result);
|
|
}
|
|
|
|
std::string Result::getResStatus()
|
|
{
|
|
// return PQresStatus(result);
|
|
return "";
|
|
}
|
|
|
|
std::string Result::diagSqlState()
|
|
{
|
|
std::string s(PQresultErrorField(result, PG_DIAG_SQLSTATE));
|
|
return s;
|
|
}
|
|
|
|
|
|
ErrorDetails Result::diagDetails()
|
|
{
|
|
// ErrorDetails r;
|
|
// r.state = PQresultErrorField(result, PG_DIAG_SQLSTATE); ///< PG_DIAG_SQLSTATE Error code as listed in https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html
|
|
// r.severity = PQresultErrorField(result, PG_DIAG_SEVERITY);
|
|
// r.messagePrimary = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
|
|
// r.messageDetail = PQresultErrorField(result, PG_DIAG_MESSAGE_DETAIL);
|
|
// r.messageHint = PQresultErrorField(result, PG_DIAG_MESSAGE_HINT);
|
|
// r.statementPosition = atoi(PQresultErrorField(result, PG_DIAG_STATEMENT_POSITION)); ///< First character is one, measured in characters not bytes!
|
|
// r.internalPosition = atoi(PQresultErrorField(result, PG_DIAG_INTERNAL_POSITION));
|
|
// r.internalQuery = PQresultErrorField(result, PG_DIAG_INTERNAL_QUERY);
|
|
// r.context = PQresultErrorField(result, PG_DIAG_CONTEXT);
|
|
// r.schemaName = PQresultErrorField(result, PG_DIAG_SCHEMA_NAME);
|
|
// r.tableName = PQresultErrorField(result, PG_DIAG_TABLE_NAME);
|
|
// r.columnName = PQresultErrorField(result, PG_DIAG_COLUMN_NAME);
|
|
// r.datatypeName = PQresultErrorField(result, PG_DIAG_DATATYPE_NAME);
|
|
// r.constraintName = PQresultErrorField(result, PG_DIAG_CONSTRAINT_NAME);
|
|
// r.sourceFile = PQresultErrorField(result, PG_DIAG_SOURCE_FILE);
|
|
// r.sourceLine = PQresultErrorField(result, PG_DIAG_SOURCE_LINE);
|
|
// r.sourceFunction = PQresultErrorField(result, PG_DIAG_SOURCE_FUNCTION);
|
|
|
|
// return r;
|
|
return ErrorDetails::createErrorDetailsFromPGresult(result);
|
|
}
|
|
|
|
|
|
int Result::getRows() const
|
|
{
|
|
return PQntuples(result);
|
|
}
|
|
|
|
int Result::getCols() const
|
|
{
|
|
return PQnfields(result);
|
|
}
|
|
|
|
const char* const Result::getColName(int idx) const
|
|
{
|
|
return PQfname(result, idx);
|
|
}
|
|
|
|
const char * Result::getVal(int col, int row) const
|
|
{
|
|
return PQgetvalue(result, row, col);
|
|
}
|
|
|
|
|
|
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::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);
|
|
}
|
|
|
|
|
|
bool Connection::sendQuery(const char *query)
|
|
{
|
|
int res = PQsendQuery(conn, query);
|
|
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));
|
|
}
|
|
|
|
void Connection::notifyReceiveFunc(void *arg, const PGresult *result)
|
|
{
|
|
Connection *c = reinterpret_cast<Connection *>(arg);
|
|
c->notifyReceiver(result);
|
|
}
|