pgLab/pglablib/PgDatabaseCatalog.cpp
eelke 8cb1d6eab3 Permission denied errors are now being ignored while reading the system catalog.
Other parts of the program will have to cope with the fact that not all data will
be available.

Close #4
2018-04-21 10:50:04 +02:00

242 lines
5.4 KiB
C++

#include "PgDatabaseCatalog.h"
#include "ASyncDBConnection.h"
#include "PgAttributeContainer.h"
#include "PgAuthIdContainer.h"
#include "PgClassContainer.h"
#include "PgConstraintContainer.h"
#include "PgDatabaseContainer.h"
#include "PgIndexContainer.h"
#include "PgNamespaceContainer.h"
#include "PgTypeContainer.h"
#include "Pgsql_Connection.h"
#include "Pgsql_oids.h"
#include <QThread>
#include <boost/timer/timer.hpp>
#include <boost/chrono/system_clocks.hpp>
using namespace Pgsql;
QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid)
{
QString name;
auto auth_ids = cat.authIds();
if (auth_ids) {
const PgAuthId& auth_id = auth_ids->getByKey(oid);
if (auth_id.valid()) {
name = auth_id.name;
}
}
return name;
}
QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid)
{
QString name = getRoleNameFromOid(cat, oid);
return name;
// return QString("%1 (%2)").arg(name).arg(oid);
}
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
{
QString result;
auto nss = cat.namespaces();
auto ns = nss->getByKey(oid);
result = ns.name; //QString("ns %1").arg(oid);
return result;
}
QString getClassDisplayString(const PgDatabaseCatalog &cat, Oid oid)
{
QString result;
auto l = cat.classes();
auto e = l->getByKey(oid);
result = e.name;
return result;
}
QString getIndexDisplayString(const PgDatabaseCatalog &cat, Oid oid)
{
QString result;
// auto l = cat.indexes();
// auto e = l->getByKey(oid);
// if (e)
result = getClassDisplayString(cat, oid);
return result;
}
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
{
// TODO load list and lookup name
return QString("ts %1").arg(oid);
}
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid, int32_t typmod)
{
if (oid == 0) {
return QString();
}
auto tc = cat.types();
auto t = tc->getByKey(oid);
if (t.oid == InvalidOid) {
return "(invalid/unknown)";
}
QString s;
if (t.category == TypCategory::Array) {
// auto et = tc->getByKey(t.elem);
// s = et.name;
s = getTypeDisplayString(cat, t.elem, typmod);
s += "[]";
}
else {
s = t.name;
switch (oid) {
case varchar_oid:
case char_oid:
case text_oid:
if (typmod > 4)
s += QString::asprintf("(%d)", typmod-4);
break;
case numeric_oid:
if (typmod > 4) {
int prec = (typmod - 4) / 65536;
int scale = (typmod - 4) % 65536;
if (scale > 0)
s += QString::asprintf("(%d,%d)", prec, scale);
else
s += QString::asprintf("(%d)", prec);
}
break;
}
}
return s;
}
PgDatabaseCatalog::PgDatabaseCatalog()
{
}
PgDatabaseCatalog::~PgDatabaseCatalog()
{
}
void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn,
std::function<bool(int, int)> progress_callback)
{
loadInfo(conn);
int n = 0;
if (progress_callback && !progress_callback(++n, 9))
return;
load2(m_namespaces, conn);
if (progress_callback && !progress_callback(++n, 9))
return;
load2(m_classes, conn); // needs namespaces
if (progress_callback && !progress_callback(++n, 9))
return;
load2(m_attributes, conn);
if (progress_callback && !progress_callback(++n, 9))
return;
load2(m_authIds, conn);
if (progress_callback && !progress_callback(++n, 9))
return;
load2(m_constraints, conn);
if (progress_callback && !progress_callback(++n, 9))
return;
load2(m_databases, conn);
if (progress_callback && !progress_callback(++n, 9))
return;
load2(m_indexes, conn);
if (progress_callback && !progress_callback(++n, 9))
return;
load2(m_types, conn);
progress_callback && progress_callback(++n, 9);
}
void PgDatabaseCatalog::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).asQString();
}
void load(Pgsql::Connection &conn, IPgContainter &pg_cont)
{
//QThread::msleep(400);
std::string q = pg_cont.getLoadQuery();
Pgsql::Result result = conn.query(q.c_str());
if (result && result.resultStatus() == PGRES_TUPLES_OK) {
//boost::timer::auto_cpu_timer t;
pg_cont.load(result);
}
else {
auto details = result.diagDetails();
if (details.state == "42501") { // permission denied
// ignore this for now
}
else {
throw std::runtime_error("Query failed\n" + details.errorMessage);
}
}
}
const QString& PgDatabaseCatalog::serverVersionString() const
{
return m_serverVersionString;
}
int PgDatabaseCatalog::serverVersion() const
{
return m_serverVersion;
}
std::shared_ptr<const PgAttributeContainer> PgDatabaseCatalog::attributes() const
{
return m_attributes;
}
std::shared_ptr<const PgAuthIdContainer> PgDatabaseCatalog::authIds() const
{
return m_authIds;
}
std::shared_ptr<const PgClassContainer> PgDatabaseCatalog::classes() const
{
return m_classes;
}
std::shared_ptr<const PgConstraintContainer> PgDatabaseCatalog::constraints() const
{
return m_constraints;
}
std::shared_ptr<const PgDatabaseContainer> PgDatabaseCatalog::databases() const
{
return m_databases;
}
std::shared_ptr<const PgIndexContainer> PgDatabaseCatalog::indexes() const
{
return m_indexes;
}
std::shared_ptr<const PgNamespaceContainer> PgDatabaseCatalog::namespaces() const
{
return m_namespaces;
}
std::shared_ptr<const PgTypeContainer> PgDatabaseCatalog::types() const
{
return m_types;
}