Added list of databases and roles.
Roles works for atleast 9.3 and up. Reorganizing code for communicating with database.
This commit is contained in:
parent
8c077b3d5f
commit
2d962334da
28 changed files with 881 additions and 428 deletions
|
|
@ -138,6 +138,7 @@ public:
|
|||
float planningTime = 0.f;
|
||||
// Triggers???
|
||||
float executionTime = 0.f;
|
||||
float totalRuntime = 0.f;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
3
src/PgAuthId.cpp
Normal file
3
src/PgAuthId.cpp
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include "PgAuthId.h"
|
||||
|
||||
PgAuthId::PgAuthId() = default;
|
||||
32
src/PgAuthId.h
Normal file
32
src/PgAuthId.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef PGAUTHID_H
|
||||
#define PGAUTHID_H
|
||||
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
class PgAuthId {
|
||||
public:
|
||||
PgAuthId();
|
||||
|
||||
Oid oid = InvalidOid;
|
||||
QString name;
|
||||
bool super;
|
||||
bool inherit;
|
||||
bool createRole;
|
||||
bool createDB;
|
||||
bool canlogin;
|
||||
bool replication;
|
||||
bool bypassRls;
|
||||
int connLimit;
|
||||
QDateTime validUntil;
|
||||
|
||||
bool valid() const { return oid != InvalidOid; }
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgAuthId &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGAUTHID_H
|
||||
45
src/PgAuthIdContainer.cpp
Normal file
45
src/PgAuthIdContainer.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "PgAuthIdContainer.h"
|
||||
#include "PgsqlConn.h"
|
||||
#include "PgsqlDatabaseCatalogue.h"
|
||||
|
||||
PgAuthIdContainer::PgAuthIdContainer(PgsqlDatabaseCatalogue *cat)
|
||||
: PgContainer<PgAuthId>(cat)
|
||||
{}
|
||||
|
||||
std::string PgAuthIdContainer::getLoadQuery() const
|
||||
{
|
||||
std::string result =
|
||||
"SELECT oid, rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, "
|
||||
" rolcanlogin, rolreplication, rolconnlimit, rolvaliduntil";
|
||||
if (m_catalogue->serverVersion() >= 90500)
|
||||
result += ", rolbypassrls";
|
||||
result += "\n"
|
||||
"FROM pg_authid";
|
||||
return result;
|
||||
}
|
||||
|
||||
void PgAuthIdContainer::load(const Pgsql::Result &res)
|
||||
{
|
||||
const int n_rows = res.rows();
|
||||
m_container.clear();
|
||||
m_container.reserve(n_rows);
|
||||
bool with_rls = (m_catalogue->serverVersion() >= 90500);
|
||||
for (auto row : res) {
|
||||
PgAuthId v;
|
||||
v.oid = row.get(0); // InvalidOid;
|
||||
v.name = row.get(1);
|
||||
v.super = row.get(2);
|
||||
v.inherit = row.get(3);
|
||||
v.createRole = row.get(4);
|
||||
v.createDB = row.get(5);
|
||||
v.canlogin = row.get(6);
|
||||
v.replication = row.get(7);
|
||||
v.connLimit = row.get(8);
|
||||
v.validUntil = row.get(9);
|
||||
v.bypassRls = with_rls ? (bool)row.get(10) : false;
|
||||
// QDateTime
|
||||
m_container.push_back(v);
|
||||
}
|
||||
std::sort(m_container.begin(), m_container.end());
|
||||
}
|
||||
|
||||
26
src/PgAuthIdContainer.h
Normal file
26
src/PgAuthIdContainer.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef PGAUTHIDCONTAINER_H
|
||||
#define PGAUTHIDCONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
#include "PgContainer.h"
|
||||
#include "PgAuthId.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgAuthIdContainer: public PgContainer<PgAuthId> {
|
||||
public:
|
||||
explicit PgAuthIdContainer(PgsqlDatabaseCatalogue *cat);
|
||||
|
||||
std::string getLoadQuery() const;
|
||||
void load(const Pgsql::Result &res);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGAUTHIDCONTAINER_H
|
||||
|
|
@ -5,11 +5,17 @@
|
|||
#include <vector>
|
||||
#include <pgsql/libpq-fe.h>
|
||||
|
||||
class PgsqlDatabaseCatalogue;
|
||||
|
||||
template<typename T>
|
||||
class PgContainer {
|
||||
public:
|
||||
using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access
|
||||
|
||||
explicit PgContainer(PgsqlDatabaseCatalogue *cat)
|
||||
: m_catalogue(cat)
|
||||
{}
|
||||
|
||||
typename t_Container::const_iterator begin() const
|
||||
{
|
||||
return m_container.begin();
|
||||
|
|
@ -54,6 +60,7 @@ public:
|
|||
return m_container.at(idx);
|
||||
}
|
||||
protected:
|
||||
PgsqlDatabaseCatalogue *m_catalogue;
|
||||
t_Container m_container;
|
||||
private:
|
||||
T m_invalidInstance;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#include "PgDatabaseContainer.h"
|
||||
#include "PgsqlConn.h"
|
||||
|
||||
PgDatabaseContainer::PgDatabaseContainer()
|
||||
PgDatabaseContainer::PgDatabaseContainer(PgsqlDatabaseCatalogue *cat)
|
||||
: PgContainer<PgDatabase>(cat)
|
||||
{}
|
||||
|
||||
std::string PgDatabaseContainer::getLoadQuery() const
|
||||
|
|
@ -12,7 +13,7 @@ std::string PgDatabaseContainer::getLoadQuery() const
|
|||
|
||||
void PgDatabaseContainer::load(const Pgsql::Result &res)
|
||||
{
|
||||
const int n_rows = res.getRows();
|
||||
const int n_rows = res.rows();
|
||||
m_container.clear();
|
||||
m_container.reserve(n_rows);
|
||||
for (auto row : res) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Pgsql {
|
|||
|
||||
class PgDatabaseContainer: public PgContainer<PgDatabase> {
|
||||
public:
|
||||
PgDatabaseContainer();
|
||||
explicit PgDatabaseContainer(PgsqlDatabaseCatalogue *cat);
|
||||
|
||||
std::string getLoadQuery() const;
|
||||
void load(const Pgsql::Result &res);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
#include "PgsqlConn.h"
|
||||
#include <algorithm>
|
||||
|
||||
PgTypeContainer::PgTypeContainer() = default;
|
||||
PgTypeContainer::PgTypeContainer(PgsqlDatabaseCatalogue *cat)
|
||||
: PgContainer<PgType>(cat)
|
||||
{}
|
||||
|
||||
|
||||
//const PgType& PgTypeContainer::getTypeByOid(Oid oid) const
|
||||
|
|
@ -41,7 +43,7 @@ std::string PgTypeContainer::getLoadQuery()
|
|||
|
||||
void PgTypeContainer::load(const Pgsql::Result &res)
|
||||
{
|
||||
const int n_rows = res.getRows();
|
||||
const int n_rows = res.rows();
|
||||
m_container.clear();
|
||||
m_container.reserve(n_rows);
|
||||
for (auto row : res) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class PgTypeContainer: public PgContainer<PgType> {
|
|||
public:
|
||||
// using t_Types = std::vector<PgType>; ///< Do not assume it will stay a vector only expect bidirectional access
|
||||
|
||||
PgTypeContainer();
|
||||
explicit PgTypeContainer(PgsqlDatabaseCatalogue *cat);
|
||||
|
||||
// t_Types::const_iterator begin() const { return m_types.begin(); }
|
||||
// t_Types::const_iterator end() const { return m_types.end(); }
|
||||
|
|
|
|||
|
|
@ -5,205 +5,9 @@
|
|||
|
||||
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.errorMessage, PQresultErrorMessage(result));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Row::next()
|
||||
{
|
||||
if (m_row < m_result.getRows()) {
|
||||
++m_row;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Value Row::get(int col) const
|
||||
{
|
||||
return m_result.get(col, m_row);
|
||||
}
|
||||
|
||||
//Value Row::get(const char *colname) const
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
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::tuplesAffected() const
|
||||
{
|
||||
int i;
|
||||
char * res = PQcmdTuples(result);
|
||||
if (res) {
|
||||
try {
|
||||
i = std::stoi(res);
|
||||
}
|
||||
catch (std::invalid_argument& ) {
|
||||
i = -1;
|
||||
}
|
||||
catch (std::out_of_range& ) {
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Value Result::get(int col, int row) const
|
||||
{
|
||||
return Value(
|
||||
PQgetvalue(result, row, col),
|
||||
PQftype(result, col)
|
||||
);
|
||||
}
|
||||
|
||||
Oid Result::type(int col) const
|
||||
{
|
||||
return PQftype(result, col);
|
||||
}
|
||||
|
||||
bool Result::null(int col, int row) const
|
||||
{
|
||||
return PQgetisnull(result, row, col);
|
||||
}
|
||||
|
||||
Canceller::Canceller(PGcancel *c)
|
||||
: m_cancel(c)
|
||||
{}
|
||||
|
|
|
|||
203
src/PgsqlConn.h
203
src/PgsqlConn.h
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "Pgsql_Result.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Connection;
|
||||
|
|
@ -36,213 +38,12 @@ namespace Pgsql {
|
|||
|
||||
// };
|
||||
|
||||
class ErrorDetails {
|
||||
public:
|
||||
static ErrorDetails createErrorDetailsFromPGresult(const PGresult *res);
|
||||
|
||||
std::string errorMessage;
|
||||
std::string state; ///< PG_DIAG_SQLSTATE Error code as listed in https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html
|
||||
std::string severity;
|
||||
std::string messagePrimary;
|
||||
std::string messageDetail;
|
||||
std::string messageHint;
|
||||
int statementPosition; ///< First character is one, measured in characters not bytes!
|
||||
int internalPosition;
|
||||
std::string internalQuery;
|
||||
std::string context;
|
||||
std::string schemaName;
|
||||
std::string tableName;
|
||||
std::string columnName;
|
||||
std::string datatypeName;
|
||||
std::string constraintName;
|
||||
std::string sourceFile;
|
||||
std::string sourceLine;
|
||||
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)
|
||||
: m_val(val), m_typ(typ)
|
||||
{}
|
||||
|
||||
QString asQString() const
|
||||
{
|
||||
return QString::fromUtf8(m_val);
|
||||
}
|
||||
|
||||
operator QString() const
|
||||
{
|
||||
return QString::fromUtf8(m_val);
|
||||
}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return m_val;
|
||||
}
|
||||
|
||||
operator short() const
|
||||
{
|
||||
return (short)std::atoi(m_val);
|
||||
}
|
||||
|
||||
operator int() const
|
||||
{
|
||||
return std::atoi(m_val);
|
||||
}
|
||||
|
||||
operator Oid() const
|
||||
{
|
||||
return operator int();
|
||||
}
|
||||
|
||||
operator __int64() const
|
||||
{
|
||||
return strtoull(m_val, nullptr, 10);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return strcmp(m_val, "t") == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const char *m_val;
|
||||
Oid m_typ;
|
||||
|
||||
};
|
||||
|
||||
|
||||
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)
|
||||
: m_result(result)
|
||||
, m_row(row)
|
||||
{}
|
||||
|
||||
bool next();
|
||||
bool operator==(const Row& rhs)
|
||||
{
|
||||
return &m_result == &rhs.m_result
|
||||
&& m_row == rhs.m_row;
|
||||
}
|
||||
|
||||
Value get(int col) const;
|
||||
//Value get(const char *colname) const;
|
||||
//bool get(int col, QString &s);
|
||||
private:
|
||||
const Result& m_result;
|
||||
int m_row;
|
||||
};
|
||||
|
||||
/** \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 {
|
||||
public:
|
||||
const_iterator(const Result &r, int rw)
|
||||
: m_row(r, rw)
|
||||
{}
|
||||
|
||||
const_iterator operator++()
|
||||
{
|
||||
const_iterator t(*this);
|
||||
m_row.next();
|
||||
return t;
|
||||
}
|
||||
|
||||
const_iterator& operator++(int)
|
||||
{
|
||||
m_row.next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const const_iterator &rhs)
|
||||
{
|
||||
return m_row == rhs.m_row;
|
||||
}
|
||||
|
||||
bool operator!=(const const_iterator &rhs)
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
const Row& operator*()
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
const Row& operator->()
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
private:
|
||||
Row m_row;
|
||||
};
|
||||
|
||||
Result() = default;
|
||||
Result(PGresult *result);
|
||||
~Result();
|
||||
|
||||
Result(const Result &rhs) = delete;
|
||||
Result& operator=(const Result &rhs) = delete;
|
||||
|
||||
Result(Result &&rhs);
|
||||
Result& operator=(Result &&rhs);
|
||||
|
||||
operator bool() const;
|
||||
|
||||
ExecStatusType resultStatus();
|
||||
|
||||
std::string getResStatus();
|
||||
|
||||
/** Use this to retrieve an error code when this is an error result
|
||||
*
|
||||
* The possible code are listed in https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html
|
||||
*/
|
||||
std::string diagSqlState();
|
||||
/** Retrieves all the error fields. */
|
||||
ErrorDetails diagDetails();
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(*this, 0);
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(*this, getRows());
|
||||
}
|
||||
|
||||
int tuplesAffected() const;
|
||||
int getRows() const;
|
||||
int getCols() const;
|
||||
|
||||
const char* const getColName(int idx) const;
|
||||
|
||||
const char * getVal(int col, int row) const;
|
||||
Value get(int col, int row) const;
|
||||
Oid type(int col) const;
|
||||
bool null(int col, int row) const;
|
||||
|
||||
|
||||
// iterator begin();
|
||||
private:
|
||||
PGresult *result = nullptr;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Wrapper for a cancel object from libpq.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,23 @@
|
|||
#include "PgsqlDatabaseCatalogue.h"
|
||||
#include "PgTypeContainer.h"
|
||||
#include "PgDatabaseContainer.h"
|
||||
#include "PgAuthIdContainer.h"
|
||||
#include "PgsqlConn.h"
|
||||
|
||||
|
||||
QString getRoleNameFromOid(const PgsqlDatabaseCatalogue *cat, Oid oid)
|
||||
{
|
||||
QString name;
|
||||
const PgAuthIdContainer *auth_ids = cat->authIds();
|
||||
if (auth_ids) {
|
||||
const PgAuthId& auth_id = auth_ids->getByOid(oid);
|
||||
if (auth_id.valid()) {
|
||||
name = auth_id.name;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
PgsqlDatabaseCatalogue::PgsqlDatabaseCatalogue()
|
||||
{
|
||||
}
|
||||
|
|
@ -16,28 +31,71 @@ void PgsqlDatabaseCatalogue::loadAll(Pgsql::Connection &conn)
|
|||
{
|
||||
loadTypes(conn);
|
||||
loadDatabases(conn);
|
||||
loadAuthIds(conn);
|
||||
}
|
||||
|
||||
void PgsqlDatabaseCatalogue::loadInfo(Pgsql::Connection &conn)
|
||||
{
|
||||
Pgsql::Result r = conn.query("SHOW server_version_num");
|
||||
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
||||
if (r.rows() == 1)
|
||||
m_serverVersion = r.get(0, 0);
|
||||
|
||||
r = conn.query("SELECT version()");
|
||||
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
||||
if (r.rows() == 1)
|
||||
m_serverVersionString = r.get(0, 0);
|
||||
}
|
||||
|
||||
void PgsqlDatabaseCatalogue::loadTypes(Pgsql::Connection &conn)
|
||||
{
|
||||
if (m_types == nullptr) {
|
||||
m_types = new PgTypeContainer;
|
||||
}
|
||||
if (m_types == nullptr)
|
||||
m_types = new PgTypeContainer(this);
|
||||
|
||||
std::string q = m_types->getLoadQuery();
|
||||
Pgsql::Result result = conn.query(q.c_str());
|
||||
m_types->load(result);
|
||||
if (result && result.resultStatus() == PGRES_TUPLES_OK)
|
||||
m_types->load(result);
|
||||
else
|
||||
throw std::runtime_error("Query failed");
|
||||
|
||||
}
|
||||
|
||||
void PgsqlDatabaseCatalogue::loadDatabases(Pgsql::Connection &conn)
|
||||
{
|
||||
if (m_databases == nullptr) {
|
||||
m_databases = new PgDatabaseContainer;
|
||||
}
|
||||
if (m_databases == nullptr)
|
||||
m_databases = new PgDatabaseContainer(this);
|
||||
|
||||
|
||||
std::string q = m_databases->getLoadQuery();
|
||||
Pgsql::Result result = conn.query(q.c_str());
|
||||
m_databases->load(result);
|
||||
if (result && result.resultStatus() == PGRES_TUPLES_OK)
|
||||
m_databases->load(result);
|
||||
else
|
||||
throw std::runtime_error("Query failed");
|
||||
}
|
||||
|
||||
void PgsqlDatabaseCatalogue::loadAuthIds(Pgsql::Connection &conn)
|
||||
{
|
||||
if (m_authIds == nullptr)
|
||||
m_authIds = new PgAuthIdContainer(this);
|
||||
|
||||
std::string q = m_authIds->getLoadQuery();
|
||||
Pgsql::Result result = conn.query(q.c_str());
|
||||
if (result && result.resultStatus() == PGRES_TUPLES_OK)
|
||||
m_authIds->load(result);
|
||||
else
|
||||
throw std::runtime_error("Query failed");
|
||||
}
|
||||
|
||||
const QString& PgsqlDatabaseCatalogue::serverVersionString() const
|
||||
{
|
||||
return m_serverVersionString;
|
||||
}
|
||||
|
||||
int PgsqlDatabaseCatalogue::serverVersion() const
|
||||
{
|
||||
return m_serverVersion;
|
||||
}
|
||||
|
||||
const PgTypeContainer* PgsqlDatabaseCatalogue::types() const
|
||||
|
|
@ -49,3 +107,8 @@ const PgDatabaseContainer *PgsqlDatabaseCatalogue::databases() const
|
|||
{
|
||||
return m_databases;
|
||||
}
|
||||
|
||||
const PgAuthIdContainer *PgsqlDatabaseCatalogue::authIds() const
|
||||
{
|
||||
return m_authIds;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef PGSQLDATABASECATALOGUE_H
|
||||
#define PGSQLDATABASECATALOGUE_H
|
||||
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
namespace Pgsql {
|
||||
|
|
@ -11,6 +13,7 @@ namespace Pgsql {
|
|||
|
||||
class PgTypeContainer;
|
||||
class PgDatabaseContainer;
|
||||
class PgAuthIdContainer;
|
||||
|
||||
class PgsqlDatabaseCatalogue {
|
||||
public:
|
||||
|
|
@ -22,14 +25,25 @@ public:
|
|||
|
||||
|
||||
void loadAll(Pgsql::Connection &conn);
|
||||
void loadInfo(Pgsql::Connection &conn);
|
||||
void loadTypes(Pgsql::Connection &conn);
|
||||
void loadDatabases(Pgsql::Connection &conn);
|
||||
void loadAuthIds(Pgsql::Connection &conn);
|
||||
|
||||
const QString& serverVersionString() const;
|
||||
int serverVersion() const;
|
||||
|
||||
const PgTypeContainer* types() const;
|
||||
const PgDatabaseContainer *databases() const;
|
||||
const PgAuthIdContainer *authIds() const;
|
||||
private:
|
||||
QString m_serverVersionString;
|
||||
int m_serverVersion;
|
||||
PgTypeContainer *m_types = nullptr;
|
||||
PgDatabaseContainer *m_databases = nullptr;
|
||||
PgAuthIdContainer *m_authIds = nullptr;
|
||||
};
|
||||
|
||||
QString getRoleNameFromOid(const PgsqlDatabaseCatalogue *cat, Oid oid);
|
||||
|
||||
#endif // PGSQLDATABASECATALOGUE_H
|
||||
|
|
|
|||
182
src/Pgsql_Result.cpp
Normal file
182
src/Pgsql_Result.cpp
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
#include "Pgsql_Result.h"
|
||||
|
||||
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.errorMessage, PQresultErrorMessage(result));
|
||||
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::tuplesAffected() const
|
||||
{
|
||||
int i;
|
||||
char * res = PQcmdTuples(result);
|
||||
if (res) {
|
||||
try {
|
||||
i = std::stoi(res);
|
||||
}
|
||||
catch (std::invalid_argument& ) {
|
||||
i = -1;
|
||||
}
|
||||
catch (std::out_of_range& ) {
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int Result::rows() const
|
||||
{
|
||||
return PQntuples(result);
|
||||
}
|
||||
|
||||
int Result::cols() const
|
||||
{
|
||||
return PQnfields(result);
|
||||
}
|
||||
|
||||
const char* const Result::getColName(int idx) const
|
||||
{
|
||||
return PQfname(result, idx);
|
||||
}
|
||||
|
||||
const char * Result::val(int col, int row) const
|
||||
{
|
||||
return PQgetvalue(result, row, col);
|
||||
}
|
||||
|
||||
Value Result::get(int col, int row) const
|
||||
{
|
||||
return Value(
|
||||
PQgetvalue(result, row, col),
|
||||
PQftype(result, col)
|
||||
);
|
||||
}
|
||||
|
||||
Oid Result::type(int col) const
|
||||
{
|
||||
return PQftype(result, col);
|
||||
}
|
||||
|
||||
bool Result::null(int col, int row) const
|
||||
{
|
||||
return PQgetisnull(result, row, col);
|
||||
}
|
||||
135
src/Pgsql_Result.h
Normal file
135
src/Pgsql_Result.h
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#ifndef PGSQL_RESULT_H
|
||||
#define PGSQL_RESULT_H
|
||||
|
||||
#include "Pgsql_Row.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class ErrorDetails {
|
||||
public:
|
||||
static ErrorDetails createErrorDetailsFromPGresult(const PGresult *res);
|
||||
|
||||
std::string errorMessage;
|
||||
std::string state; ///< PG_DIAG_SQLSTATE Error code as listed in https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html
|
||||
std::string severity;
|
||||
std::string messagePrimary;
|
||||
std::string messageDetail;
|
||||
std::string messageHint;
|
||||
int statementPosition; ///< First character is one, measured in characters not bytes!
|
||||
int internalPosition;
|
||||
std::string internalQuery;
|
||||
std::string context;
|
||||
std::string schemaName;
|
||||
std::string tableName;
|
||||
std::string columnName;
|
||||
std::string datatypeName;
|
||||
std::string constraintName;
|
||||
std::string sourceFile;
|
||||
std::string sourceLine;
|
||||
std::string sourceFunction;
|
||||
};
|
||||
|
||||
/** \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 {
|
||||
public:
|
||||
const_iterator(const Result &r, int rw)
|
||||
: m_row(r, rw)
|
||||
{}
|
||||
|
||||
const_iterator operator++()
|
||||
{
|
||||
const_iterator t(*this);
|
||||
m_row.next();
|
||||
return t;
|
||||
}
|
||||
|
||||
const_iterator& operator++(int)
|
||||
{
|
||||
m_row.next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const const_iterator &rhs)
|
||||
{
|
||||
return m_row == rhs.m_row;
|
||||
}
|
||||
|
||||
bool operator!=(const const_iterator &rhs)
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
const Row& operator*()
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
const Row& operator->()
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
private:
|
||||
Row m_row;
|
||||
};
|
||||
|
||||
Result() = default;
|
||||
Result(PGresult *result);
|
||||
~Result();
|
||||
|
||||
Result(const Result &rhs) = delete;
|
||||
Result& operator=(const Result &rhs) = delete;
|
||||
|
||||
Result(Result &&rhs);
|
||||
Result& operator=(Result &&rhs);
|
||||
|
||||
operator bool() const;
|
||||
|
||||
ExecStatusType resultStatus();
|
||||
|
||||
std::string getResStatus();
|
||||
|
||||
/** Use this to retrieve an error code when this is an error result
|
||||
*
|
||||
* The possible code are listed in https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html
|
||||
*/
|
||||
std::string diagSqlState();
|
||||
/** Retrieves all the error fields. */
|
||||
ErrorDetails diagDetails();
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(*this, 0);
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(*this, rows());
|
||||
}
|
||||
|
||||
int tuplesAffected() const;
|
||||
int rows() const;
|
||||
int cols() const;
|
||||
|
||||
const char* const getColName(int idx) const;
|
||||
|
||||
const char * val(int col, int row) const;
|
||||
Value get(int col, int row) const;
|
||||
Oid type(int col) const;
|
||||
bool null(int col, int row) const;
|
||||
|
||||
|
||||
// iterator begin();
|
||||
private:
|
||||
PGresult *result = nullptr;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Pgsql
|
||||
|
||||
#endif // PGSQL_RESULT_H
|
||||
36
src/Pgsql_Row.cpp
Normal file
36
src/Pgsql_Row.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "Pgsql_Row.h"
|
||||
#include "Pgsql_Result.h"
|
||||
|
||||
using namespace Pgsql;
|
||||
|
||||
Row::Row(const Result &result, int row)
|
||||
: m_result(result)
|
||||
, m_row(row)
|
||||
{}
|
||||
|
||||
bool Row::next()
|
||||
{
|
||||
if (m_row < m_result.rows()) {
|
||||
++m_row;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Row::operator==(const Row& rhs) const
|
||||
{
|
||||
return &m_result == &rhs.m_result
|
||||
&& m_row == rhs.m_row;
|
||||
}
|
||||
|
||||
|
||||
Value Row::get(int col) const
|
||||
{
|
||||
return m_result.get(col, m_row);
|
||||
}
|
||||
|
||||
//Value Row::get(const char *colname) const
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
31
src/Pgsql_Row.h
Normal file
31
src/Pgsql_Row.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef PGSQL_ROW_H
|
||||
#define PGSQL_ROW_H
|
||||
|
||||
#include "Pgsql_Value.h"
|
||||
|
||||
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);
|
||||
bool next();
|
||||
|
||||
bool operator==(const Row& rhs) const;
|
||||
Value get(int col) const;
|
||||
//Value get(const char *colname) const;
|
||||
//bool get(int col, QString &s);
|
||||
private:
|
||||
const Result& m_result;
|
||||
int m_row;
|
||||
};
|
||||
|
||||
} // end namespace Pgsql
|
||||
|
||||
#endif // PGSQL_ROW_H
|
||||
56
src/Pgsql_Value.cpp
Normal file
56
src/Pgsql_Value.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include "Pgsql_Value.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
using namespace Pgsql;
|
||||
|
||||
Value::Value(const char *val, Oid typ)
|
||||
: m_val(val), m_typ(typ)
|
||||
{}
|
||||
|
||||
QString Value::asQString() const
|
||||
{
|
||||
return QString::fromUtf8(m_val);
|
||||
}
|
||||
|
||||
Value::operator QString() const
|
||||
{
|
||||
return QString::fromUtf8(m_val);
|
||||
}
|
||||
|
||||
Value::operator QDateTime() const
|
||||
{
|
||||
return QDateTime::fromString(asQString(),
|
||||
"yyyy-MM-dd hh:mm:ss");
|
||||
}
|
||||
|
||||
Value::operator std::string() const
|
||||
{
|
||||
return m_val;
|
||||
}
|
||||
|
||||
Value::operator short() const
|
||||
{
|
||||
return (short)std::atoi(m_val);
|
||||
}
|
||||
|
||||
Value::operator int() const
|
||||
{
|
||||
return std::atoi(m_val);
|
||||
}
|
||||
|
||||
Value::operator Oid() const
|
||||
{
|
||||
return operator int();
|
||||
}
|
||||
|
||||
Value::operator __int64() const
|
||||
{
|
||||
return std::strtoull(m_val, nullptr, 10);
|
||||
}
|
||||
|
||||
Value::operator bool() const
|
||||
{
|
||||
return std::strcmp(m_val, "t") == 0;
|
||||
}
|
||||
|
||||
33
src/Pgsql_Value.h
Normal file
33
src/Pgsql_Value.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef PGSQL_VALUE_H
|
||||
#define PGSQL_VALUE_H
|
||||
|
||||
#include "Pgsql_declare.h"
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
/** \brief Class that is returned as value of a cell to facilitate auto conversion.
|
||||
*/
|
||||
class Value {
|
||||
public:
|
||||
Value(const char *val, Oid typ);
|
||||
QString asQString() const;
|
||||
operator QString() const;
|
||||
operator QDateTime() const;
|
||||
operator std::string() const;
|
||||
operator short() const;
|
||||
operator int() const;
|
||||
operator Oid() const;
|
||||
operator __int64() const;
|
||||
operator bool() const;
|
||||
|
||||
private:
|
||||
const char *m_val;
|
||||
Oid m_typ;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Pgsql
|
||||
|
||||
#endif // PGSQL_VALUE_H
|
||||
|
|
@ -11,13 +11,13 @@ QueryResultModel::QueryResultModel(QObject *parent, std::shared_ptr<Pgsql::Resul
|
|||
|
||||
int QueryResultModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
int r = result->getRows();
|
||||
int r = result->rows();
|
||||
return r;
|
||||
}
|
||||
|
||||
int QueryResultModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
int r = result->getCols();
|
||||
int r = result->cols();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
|
|||
}
|
||||
else {
|
||||
Oid o = result->type(col);
|
||||
QString s(result->getVal(col, rij));
|
||||
QString s(result->val(col, rij));
|
||||
switch (o) {
|
||||
case oid_bool:
|
||||
s = (s == "t") ? "TRUE" : "FALSE";
|
||||
|
|
@ -88,7 +88,7 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
|
|||
r = QBrush(Qt::darkGreen);
|
||||
break;
|
||||
case oid_bool:
|
||||
if (strcmp(result->getVal(col, rij), "t") == 0) {
|
||||
if (strcmp(result->val(col, rij), "t") == 0) {
|
||||
r = QBrush(Qt::darkGreen);
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -212,8 +212,8 @@ void QueryTab::explain(bool analyze)
|
|||
std::thread([this,res]()
|
||||
{
|
||||
std::shared_ptr<ExplainRoot> explain;
|
||||
if (res->getCols() == 1 && res->getRows() == 1) {
|
||||
std::string s = res->getVal(0, 0);
|
||||
if (res->cols() == 1 && res->rows() == 1) {
|
||||
std::string s = res->val(0, 0);
|
||||
Json::Value root; // will contains the root value after parsing.
|
||||
Json::Reader reader;
|
||||
bool parsingSuccessful = reader.parse(s, root);
|
||||
|
|
|
|||
123
src/RolesTableModel.cpp
Normal file
123
src/RolesTableModel.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#include "RolesTableModel.h"
|
||||
#include "PgAuthIdContainer.h"
|
||||
|
||||
RolesTableModel::RolesTableModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void RolesTableModel::setRoleList(const PgAuthIdContainer* roles)
|
||||
{
|
||||
beginResetModel();
|
||||
m_roles = roles;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QVariant RolesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
QVariant v;
|
||||
if (orientation == Qt::Horizontal) {
|
||||
if (role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case NameCol:
|
||||
v = tr("Name");
|
||||
break;
|
||||
case SuperCol:
|
||||
v = tr("Super");
|
||||
break;
|
||||
case InheritCol:
|
||||
v = tr("Inherit");
|
||||
break;
|
||||
case CreateRoleCol:
|
||||
v = tr("Create role");
|
||||
break;
|
||||
case CreateDBCol:
|
||||
v = tr("Create DB");
|
||||
break;
|
||||
case CanLoginCol:
|
||||
v = tr("Can login");
|
||||
break;
|
||||
case ReplicationCol:
|
||||
v = tr("Replication");
|
||||
break;
|
||||
case BypassRlsCol:
|
||||
v = tr("Bypass RLS");
|
||||
break;
|
||||
case ConnlimitCol:
|
||||
v = tr("Connection limit");
|
||||
break;
|
||||
case ValidUntilCol:
|
||||
v = tr("Valid until");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
int RolesTableModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
int result = 0;
|
||||
if (m_roles) {
|
||||
result = m_roles->count();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int RolesTableModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
int result = 10;
|
||||
// if (parent.isValid())
|
||||
// return 10;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant RolesTableModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QVariant v;
|
||||
//if (!index.isValid())
|
||||
if (m_roles) {
|
||||
const PgAuthId &authid = m_roles->getByIdx(index.row());
|
||||
if (role == Qt::DisplayRole) {
|
||||
switch (index.column()) {
|
||||
case NameCol:
|
||||
v = authid.name;
|
||||
break;
|
||||
case SuperCol:
|
||||
// todo lookup role name
|
||||
v = authid.super;
|
||||
break;
|
||||
case InheritCol:
|
||||
// todo lookup encoding name
|
||||
v = authid.inherit;
|
||||
break;
|
||||
case CreateRoleCol:
|
||||
v = authid.createRole;
|
||||
break;
|
||||
case CreateDBCol:
|
||||
v = authid.createDB;
|
||||
break;
|
||||
case CanLoginCol:
|
||||
v = authid.canlogin;
|
||||
break;
|
||||
case ReplicationCol:
|
||||
v = authid.replication;
|
||||
break;
|
||||
case BypassRlsCol:
|
||||
v = authid.bypassRls;
|
||||
break;
|
||||
case ConnlimitCol:
|
||||
// todo lookup tablespace name
|
||||
v = authid.connLimit;
|
||||
break;
|
||||
case ValidUntilCol:
|
||||
v = authid.validUntil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
39
src/RolesTableModel.h
Normal file
39
src/RolesTableModel.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef ROLESTABLEMODEL_H
|
||||
#define ROLESTABLEMODEL_H
|
||||
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
class PgAuthIdContainer;
|
||||
|
||||
/** Class for displaying the list of roles of a server in a QTableView
|
||||
*
|
||||
*/
|
||||
class RolesTableModel : public QAbstractTableModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum e_Columns : int { NameCol, SuperCol, InheritCol, CreateRoleCol,
|
||||
CreateDBCol, CanLoginCol, ReplicationCol,
|
||||
BypassRlsCol, ConnlimitCol, ValidUntilCol };
|
||||
|
||||
|
||||
|
||||
explicit RolesTableModel(QObject *parent);
|
||||
|
||||
void setRoleList(const PgAuthIdContainer* roles);
|
||||
|
||||
// Header:
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
// Basic functionality:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
private:
|
||||
const PgAuthIdContainer *m_roles = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif // ROLESTABLEMODEL_H
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#include "ui_ServerWindow.h"
|
||||
#include "OpenDatabase.h"
|
||||
#include "DatabasesTableModel.h"
|
||||
#include "RolesTableModel.h"
|
||||
#include "PgsqlDatabaseCatalogue.h"
|
||||
|
||||
ServerWindow::ServerWindow(MasterController *master, QWidget *parent)
|
||||
|
|
@ -12,7 +13,10 @@ ServerWindow::ServerWindow(MasterController *master, QWidget *parent)
|
|||
ui->setupUi(this);
|
||||
|
||||
m_databasesModel = new DatabasesTableModel(this);
|
||||
ui->tableView->setModel(m_databasesModel);
|
||||
ui->databasesTableView->setModel(m_databasesModel);
|
||||
|
||||
m_rolesModel = new RolesTableModel(this);
|
||||
ui->rolesTableView->setModel(m_rolesModel);
|
||||
}
|
||||
|
||||
ServerWindow::~ServerWindow()
|
||||
|
|
@ -29,6 +33,7 @@ void ServerWindow::setConfig(const ConnectionConfig &config)
|
|||
auto cat = m_database->catalogue();
|
||||
if (cat) {
|
||||
m_databasesModel->setDatabaseList(cat->databases());
|
||||
m_rolesModel->setRoleList(cat->authIds());
|
||||
}
|
||||
}
|
||||
QString title = "pglab - ";
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class ServerWindow;
|
|||
class MasterController;
|
||||
class OpenDatabase;
|
||||
class DatabasesTableModel;
|
||||
class RolesTableModel;
|
||||
|
||||
class ServerWindow : public ASyncWindow {
|
||||
Q_OBJECT
|
||||
|
|
@ -22,10 +23,11 @@ public:
|
|||
private:
|
||||
Ui::ServerWindow *ui;
|
||||
|
||||
MasterController *m_masterController;
|
||||
MasterController *m_masterController = nullptr;
|
||||
ConnectionConfig m_config;
|
||||
OpenDatabase *m_database;
|
||||
DatabasesTableModel *m_databasesModel;
|
||||
OpenDatabase *m_database = nullptr;
|
||||
DatabasesTableModel *m_databasesModel = nullptr;
|
||||
RolesTableModel *m_rolesModel = nullptr;
|
||||
};
|
||||
|
||||
#endif // SERVERWINDOW_H
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="databasesTab">
|
||||
<attribute name="title">
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView">
|
||||
<widget class="QTableView" name="databasesTableView">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView_2">
|
||||
<widget class="QTableView" name="tablespacesTableView">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
|
@ -114,7 +114,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView_3">
|
||||
<widget class="QTableView" name="rolesTableView">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
|
|
|||
18
src/src.pro
18
src/src.pro
|
|
@ -59,7 +59,13 @@ SOURCES += main.cpp\
|
|||
DatabasesTableModel.cpp \
|
||||
PgDatabase.cpp \
|
||||
PgDatabaseContainer.cpp \
|
||||
Pgsql_Params.cpp
|
||||
Pgsql_Params.cpp \
|
||||
RolesTableModel.cpp \
|
||||
PgAuthId.cpp \
|
||||
PgAuthIdContainer.cpp \
|
||||
Pgsql_Result.cpp \
|
||||
Pgsql_Row.cpp \
|
||||
Pgsql_Value.cpp
|
||||
|
||||
HEADERS += \
|
||||
sqlparser.h \
|
||||
|
|
@ -105,7 +111,13 @@ HEADERS += \
|
|||
PgDatabaseContainer.h \
|
||||
PgContainer.h \
|
||||
Pgsql_Params.h \
|
||||
Pgsql_declare.h
|
||||
Pgsql_declare.h \
|
||||
RolesTableModel.h \
|
||||
PgAuthId.h \
|
||||
PgAuthIdContainer.h \
|
||||
Pgsql_Result.h \
|
||||
Pgsql_Row.h \
|
||||
Pgsql_Value.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
DatabaseWindow.ui \
|
||||
|
|
@ -119,4 +131,4 @@ FORMS += mainwindow.ui \
|
|||
RESOURCES += \
|
||||
resources.qrc
|
||||
|
||||
QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01
|
||||
#QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue