PgAttribute loading + ColummnTableModel

Required enchancement to PgContainer to make multifield key work.
This commit is contained in:
eelke 2017-12-12 20:13:53 +01:00
parent f9caadb59e
commit e9d72d391d
32 changed files with 698 additions and 99 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ build/*
*.kdev4 *.kdev4
.kdev4/* .kdev4/*
DIST/

149
pglab/ColumnTableModel.cpp Normal file
View file

@ -0,0 +1,149 @@
#include "ColumnTableModel.h"
#include "PgDatabaseCatalog.h"
#include "PgAttribute.h"
#include "PgAttributeContainer.h"
#include "PgType.h"
#include "PgTypeContainer.h"
#include "ScopeGuard.h"
#include <QBrush>
void ColumnTableModel::setData(std::shared_ptr<const PgDatabaseCatalog> cat, Oid table_oid)
{
beginResetModel();
SCOPE_EXIT { endResetModel(); };
m_catalog = cat;
m_columns = cat->attributes()->getColumnsForRelation(table_oid);
// hide system columns
m_columns.erase(std::remove_if(m_columns.begin(), m_columns.end(),
[](auto &e) { return e.num <= 0; } ),
m_columns.end());
// sort remaining columns by order in table
std::sort(m_columns.begin(), m_columns.end(),
[] (auto &l, auto &r) -> bool { return l.num < r.num; });
}
QVariant ColumnTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant v;
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
QString c;
switch (section) {
case NameCol:
c = tr("Name");
break;
case TypeCol:
c = tr("Type");
break;
case NullCol:
c = tr("Nullable");
break;
case DefaultCol:
c = tr("Default");
break;
case CollationCol:
c = tr("Collation");
break;
}
v = c;
}
}
return v;
}
int ColumnTableModel::rowCount(const QModelIndex &parent) const
{
return m_columns.size();
}
int ColumnTableModel::columnCount(const QModelIndex &parent) const
{
return colCount;
}
Oid ColumnTableModel::getType(int column) const
{
Oid oid = Pgsql::VARCHAROID;
// switch (column) {
// case TypeCol:
// case NameCol:
// case NullCol:
// case DefaultCol:
// case CollationCol:
// oid = VARCHAROID;
// break;
// c = tr("Collation");
// break;
// }
return oid;
}
QVariant ColumnTableModel::getData(const QModelIndex &index) const
{
QVariant v;
const auto &t = m_columns[index.row()];
QString s;
switch (index.column()) {
case NameCol:
s = t.name;
break;
case TypeCol:
s = getTypeDisplayString(*m_catalog, t.typid);
break;
case NullCol:
s = t.notnull ? "NOT NULL" : "";
break;
case DefaultCol:
s = "";
break;
case CollationCol:
s = ""; //t.collation;
break;
}
v = s;
return v;
}
QVariant ColumnTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::ForegroundRole && index.column() == TypeCol) {
QVariant v;
const auto &t = m_columns[index.row()];
auto c = m_catalog->types()->getByKey(t.typid);
switch (c.category) {
case TypCategory::Boolean:
v = QBrush(Qt::darkGreen);
break;
case TypCategory::Numeric:
v = QBrush(Qt::darkBlue);
break;
case TypCategory::DateTime:
case TypCategory::Timespan:
v = QBrush(Qt::darkMagenta);
break;
case TypCategory::String:
v = QBrush(Qt::darkYellow);
break;
case TypCategory::Array:
case TypCategory::Composite:
case TypCategory::Enum:
case TypCategory::Geometric:
case TypCategory::NetworkAddress:
case TypCategory::Pseudo:
case TypCategory::Range:
case TypCategory::UserDefined:
case TypCategory::BitString:
case TypCategory::Unknown:
default:
v = QBrush(Qt::black);
}
return v;
}
return BaseTableModel::data(index, role);
}

44
pglab/ColumnTableModel.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef COLUMNTABLEMODEL_H
#define COLUMNTABLEMODEL_H
#include "BaseTableModel.h"
#include <memory>
class PgDatabaseCatalog;
class PgAttribute;
class ColumnTableModel: public BaseTableModel {
public:
enum e_Columns : int {
NameCol, ///
TypeCol,
NullCol,
DefaultCol,
CollationCol,
colCount };
using BaseTableModel::BaseTableModel;
void setData(std::shared_ptr<const PgDatabaseCatalog> cat, Oid table_oid);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
// Basic functionality:
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
protected:
virtual Oid getType(int column) const override;
virtual QVariant getData(const QModelIndex &index) const override;
using t_Columns = std::vector<PgAttribute>;
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
t_Columns m_columns;
};
#endif // COLUMNTABLEMODEL_H

View file

@ -40,12 +40,6 @@ QueryTab* MainWindow::newSqlPage()
ui->tabWidget->addTab(qt, "Tab"); ui->tabWidget->addTab(qt, "Tab");
ui->tabWidget->setCurrentWidget(qt); ui->tabWidget->setCurrentWidget(qt);
qt->newdoc(); qt->newdoc();
auto tt = new TablesPage(this);
tt->setCatalog(m_database->catalogue());
ui->tabWidget->addTab(tt, "Tables");
ui->tabWidget->setCurrentWidget(tt);
return qt; return qt;
} }
@ -68,6 +62,12 @@ void MainWindow::setConfig(const ConnectionConfig &config)
QString title = "pglab - "; QString title = "pglab - ";
title += m_config.name().c_str(); title += m_config.name().c_str();
setWindowTitle(title); setWindowTitle(title);
auto tt = new TablesPage(this);
tt->setCatalog(m_database->catalogue());
ui->tabWidget->addTab(tt, "Tables");
ui->tabWidget->setCurrentWidget(tt);
newSqlPage(); newSqlPage();
} }

2
pglab/PgAttribute.cpp Normal file
View file

@ -0,0 +1,2 @@
#include "PgAttribute.h"

35
pglab/PgAttribute.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef PGATTRIBUTE_H
#define PGATTRIBUTE_H
#include "Pgsql_declare.h"
#include <QString>
#include <libpq-fe.h>
#include <tuple>
class PgAttribute {
public:
using Key = std::tuple<Oid, int16_t>;
// Oid oid = InvalidOid;
Oid relid = InvalidOid;
QString name;
Oid typid = InvalidOid;
int32_t stattarget = 0;
int16_t num = 0;
int32_t ndims = 0; // array dimensions
int32_t typmod = -1;
bool notnull = false;
bool hasdef = false;
Oid collation = InvalidOid;
QString acl;
QString options;
bool operator==(Key _k) const { return relid == std::get<0>(_k) && num == std::get<1>(_k); }
bool operator==(const QString &n) const { return name == n; }
bool operator<(Key _k) const { return relid < std::get<0>(_k) || (relid == std::get<0>(_k) && num < std::get<1>(_k)); }
bool operator<(const PgAttribute &rhs) const { return relid < rhs.relid || (relid == rhs.relid && num < rhs.num); }
};
#endif // PGATTRIBUTE_H

View file

@ -0,0 +1,30 @@
#include "PgAttributeContainer.h"
#include "Pgsql_Col.h"
std::string PgAttributeContainer::getLoadQuery() const
{
return
"SELECT attrelid, attname, atttypid, attstattarget, \n"
" attnum, attndims, atttypmod, attnotnull, atthasdef, \n"
" attcollation, attacl, attoptions \n"
" FROM pg_catalog.pg_attribute";
}
PgAttribute PgAttributeContainer::loadElem(const Pgsql::Row &row)
{
Pgsql::Col col(row);
PgAttribute v;
col >> v.relid >> v.name >> v.typid >> v.stattarget
>> v.num >> v.ndims >> v.typmod >> v.notnull >> v.hasdef
>> v.collation >> v.acl >> v.options;
return v;
}
std::vector<PgAttribute> PgAttributeContainer::getColumnsForRelation(Oid oid) const
{
std::vector<PgAttribute> result;
for (const auto &e : m_container)
if (e.relid == oid)
result.push_back(e);
return result;
}

View file

@ -0,0 +1,20 @@
#ifndef PGATTRIBUTECONTAINER_H
#define PGATTRIBUTECONTAINER_H
#include "PgContainer.h"
#include "PgAttribute.h"
#include "Pgsql_declare.h"
#include <vector>
class PgAttributeContainer : public PgContainer<PgAttribute, PgAttribute::Key> {
public:
using PgContainer<PgAttribute, PgAttribute::Key>::PgContainer;
virtual std::string getLoadQuery() const override;
std::vector<PgAttribute> getColumnsForRelation(Oid oid) const;
protected:
PgAttribute loadElem(const Pgsql::Row &row) override;
};
#endif // PGATTRIBUTECONTAINER_H

View file

@ -12,22 +12,14 @@ std::string PgClassContainer::getLoadQuery() const
"FROM pg_catalog.pg_class"; "FROM pg_catalog.pg_class";
} }
void PgClassContainer::load(const Pgsql::Result &res) PgClass PgClassContainer::loadElem(const Pgsql::Row &row)
{ {
const int n_rows = res.rows(); Pgsql::Col col(row);
m_container.clear(); PgClass v;
m_container.reserve(n_rows); col >> v.oid >> v.name >> v.relnamespace >> v.type >> v.oftype
for (auto row : res) { >> v.owner >> v.am >> v.filenode >> v.tablespace >> v.pages_est
Pgsql::Col col(row); >> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence
PgClass v; >> v.kind >> v.hasoids >> v.ispopulated >> v.frozenxid >> v.minmxid
col >> v.oid >> v.name >> v.relnamespace >> v.type >> v.oftype >> v.acl >> v.options;
>> v.owner >> v.am >> v.filenode >> v.tablespace >> v.pages_est return v;
>> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence
>> v.kind >> v.hasoids >> v.ispopulated >> v.frozenxid >> v.minmxid
>> v.acl >> v.options;
m_container.push_back(v);
}
std::sort(m_container.begin(), m_container.end());
} }

View file

@ -16,8 +16,8 @@ public:
using PgContainer<PgClass>::PgContainer; using PgContainer<PgClass>::PgContainer;
virtual std::string getLoadQuery() const override; virtual std::string getLoadQuery() const override;
virtual void load(const Pgsql::Result &res) override; protected:
PgClass loadElem(const Pgsql::Row &row) override;
private: private:
}; };

2
pglab/PgContainer.cpp Normal file
View file

@ -0,0 +1,2 @@
#include "PgContainer.h"

View file

@ -2,6 +2,7 @@
#define PGCONTAINER_H #define PGCONTAINER_H
#include "Pgsql_declare.h" #include "Pgsql_declare.h"
#include "Pgsql_Result.h"
#include <QString> #include <QString>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -18,7 +19,7 @@ public:
virtual void load(const Pgsql::Result &res) = 0; virtual void load(const Pgsql::Result &res) = 0;
}; };
template<typename T> template<typename T, typename K=Oid>
class PgContainer: public IPgContainter { class PgContainer: public IPgContainter {
public: public:
using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access
@ -48,10 +49,10 @@ public:
return (int)m_container.size(); return (int)m_container.size();
} }
const T& getByOid(Oid oid) const const T& getByKey(const K &key) const
{ {
auto lb_result = std::lower_bound(m_container.begin(), m_container.end(), oid); auto lb_result = std::lower_bound(m_container.begin(), m_container.end(), key);
if (lb_result != m_container.end() && lb_result->oid == oid) if (lb_result != m_container.end() && *lb_result == key)
return *lb_result; return *lb_result;
return m_invalidInstance; return m_invalidInstance;
@ -71,9 +72,30 @@ public:
{ {
return m_container.at(idx); return m_container.at(idx);
} }
/** Override to implement complete loading logic.
*
* Do not override this function if you only want to implement
* the loading of a single element. Override loadElem instead.
*/
virtual void load(const Pgsql::Result &res) override
{
m_container.clear();
m_container.reserve(res.rows());
for (auto row : res)
m_container.push_back(loadElem(row));
std::sort(m_container.begin(), m_container.end());
}
protected: protected:
std::weak_ptr<PgDatabaseCatalog> m_catalogue; std::weak_ptr<PgDatabaseCatalog> m_catalogue;
t_Container m_container; t_Container m_container;
/** Override the implementation for this function to implement loading of single row.
*
* When overriding this function there is no need to override load.
*/
virtual T loadElem(const Pgsql::Row &) { return T(); }
private: private:
T m_invalidInstance; T m_invalidInstance;

View file

@ -1,8 +1,11 @@
#include "PgDatabaseCatalog.h" #include "PgDatabaseCatalog.h"
#include "PgTypeContainer.h"
#include "PgDatabaseContainer.h" #include "PgAttributeContainer.h"
#include "PgAuthIdContainer.h" #include "PgAuthIdContainer.h"
#include "PgClassContainer.h" #include "PgClassContainer.h"
#include "PgDatabaseContainer.h"
#include "PgNamespaceContainer.h"
#include "PgTypeContainer.h"
#include "Pgsql_Connection.h" #include "Pgsql_Connection.h"
@ -11,7 +14,7 @@ QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid)
QString name; QString name;
auto auth_ids = cat.authIds(); auto auth_ids = cat.authIds();
if (auth_ids) { if (auth_ids) {
const PgAuthId& auth_id = auth_ids->getByOid(oid); const PgAuthId& auth_id = auth_ids->getByKey(oid);
if (auth_id.valid()) { if (auth_id.valid()) {
name = auth_id.name; name = auth_id.name;
} }
@ -22,13 +25,15 @@ QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid)
QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid) QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid)
{ {
QString name = getRoleNameFromOid(cat, oid); QString name = getRoleNameFromOid(cat, oid);
return QString("%1 (%2)").arg(name).arg(oid); return name;
// return QString("%1 (%2)").arg(name).arg(oid);
} }
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid) QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
{ {
//QString name; //QString name;
// auto c = cat.(); auto nss = cat.namespaces();
auto ns = nss->getByKey(oid);
// if (auth_ids) { // if (auth_ids) {
// const PgAuthId& auth_id = auth_ids->getByOid(oid); // const PgAuthId& auth_id = auth_ids->getByOid(oid);
// if (auth_id.valid()) { // if (auth_id.valid()) {
@ -37,7 +42,7 @@ QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
// } // }
//return name; //return name;
// TODO load list and lookup name // TODO load list and lookup name
return QString("ns %1").arg(oid); return ns.name; //QString("ns %1").arg(oid);
} }
@ -47,6 +52,13 @@ QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
return QString("ts %1").arg(oid); return QString("ts %1").arg(oid);
} }
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid)
{
auto tc = cat.types();
auto t = tc->getByKey(oid);
return t.name;
}
PgDatabaseCatalog::PgDatabaseCatalog() PgDatabaseCatalog::PgDatabaseCatalog()
{ {
@ -59,10 +71,13 @@ PgDatabaseCatalog::~PgDatabaseCatalog()
void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn) void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn)
{ {
loadInfo(conn); loadInfo(conn);
loadTypes(conn);
loadDatabases(conn); loadAttributes(conn);
loadAuthIds(conn); loadAuthIds(conn);
loadClasses(conn); loadClasses(conn);
loadDatabases(conn);
loadNamespaces(conn);
loadTypes(conn);
} }
void PgDatabaseCatalog::loadInfo(Pgsql::Connection &conn) void PgDatabaseCatalog::loadInfo(Pgsql::Connection &conn)
@ -89,20 +104,12 @@ void load(Pgsql::Connection &conn, IPgContainter &pg_cont)
} }
void PgDatabaseCatalog::loadTypes(Pgsql::Connection &conn) void PgDatabaseCatalog::loadAttributes(Pgsql::Connection &conn)
{ {
if (!m_types) if (!m_attributes)
m_types = std::make_shared<PgTypeContainer>(shared_from_this()); m_attributes = std::make_shared<PgAttributeContainer>(shared_from_this());
load(conn, *m_types); load(conn, *m_attributes);
}
void PgDatabaseCatalog::loadDatabases(Pgsql::Connection &conn)
{
if (!m_databases)
m_databases = std::make_shared<PgDatabaseContainer>(shared_from_this());
load(conn, *m_databases);
} }
void PgDatabaseCatalog::loadAuthIds(Pgsql::Connection &conn) void PgDatabaseCatalog::loadAuthIds(Pgsql::Connection &conn)
@ -121,6 +128,31 @@ void PgDatabaseCatalog::loadClasses(Pgsql::Connection &conn)
load(conn, *m_classes); load(conn, *m_classes);
} }
void PgDatabaseCatalog::loadDatabases(Pgsql::Connection &conn)
{
if (!m_databases)
m_databases = std::make_shared<PgDatabaseContainer>(shared_from_this());
load(conn, *m_databases);
}
void PgDatabaseCatalog::loadNamespaces(Pgsql::Connection &conn)
{
if (!m_namespaces)
m_namespaces = std::make_shared<PgNamespaceContainer>(shared_from_this());
load(conn, *m_namespaces);
}
void PgDatabaseCatalog::loadTypes(Pgsql::Connection &conn)
{
if (!m_types)
m_types = std::make_shared<PgTypeContainer>(shared_from_this());
load(conn, *m_types);
}
const QString& PgDatabaseCatalog::serverVersionString() const const QString& PgDatabaseCatalog::serverVersionString() const
{ {
return m_serverVersionString; return m_serverVersionString;
@ -131,14 +163,9 @@ int PgDatabaseCatalog::serverVersion() const
return m_serverVersion; return m_serverVersion;
} }
std::shared_ptr<const PgTypeContainer> PgDatabaseCatalog::types() const std::shared_ptr<const PgAttributeContainer> PgDatabaseCatalog::attributes() const
{ {
return m_types; return m_attributes;
}
std::shared_ptr<const PgDatabaseContainer> PgDatabaseCatalog::databases() const
{
return m_databases;
} }
std::shared_ptr<const PgAuthIdContainer> PgDatabaseCatalog::authIds() const std::shared_ptr<const PgAuthIdContainer> PgDatabaseCatalog::authIds() const
@ -150,3 +177,19 @@ std::shared_ptr<const PgClassContainer> PgDatabaseCatalog::classes() const
{ {
return m_classes; return m_classes;
} }
std::shared_ptr<const PgDatabaseContainer> PgDatabaseCatalog::databases() const
{
return m_databases;
}
std::shared_ptr<const PgNamespaceContainer> PgDatabaseCatalog::namespaces() const
{
return m_namespaces;
}
std::shared_ptr<const PgTypeContainer> PgDatabaseCatalog::types() const
{
return m_types;
}

View file

@ -12,9 +12,11 @@ namespace Pgsql {
} }
class PgAttributeContainer;
class PgAuthIdContainer; class PgAuthIdContainer;
class PgClassContainer; class PgClassContainer;
class PgDatabaseContainer; class PgDatabaseContainer;
class PgNamespaceContainer;
class PgTypeContainer; class PgTypeContainer;
class PgDatabaseCatalog: public std::enable_shared_from_this<PgDatabaseCatalog> { class PgDatabaseCatalog: public std::enable_shared_from_this<PgDatabaseCatalog> {
@ -27,32 +29,41 @@ public:
void loadAll(Pgsql::Connection &conn); void loadAll(Pgsql::Connection &conn);
void loadInfo(Pgsql::Connection &conn);
void loadTypes(Pgsql::Connection &conn); void loadAttributes(Pgsql::Connection &conn);
void loadDatabases(Pgsql::Connection &conn);
void loadAuthIds(Pgsql::Connection &conn); void loadAuthIds(Pgsql::Connection &conn);
void loadClasses(Pgsql::Connection &conn); void loadClasses(Pgsql::Connection &conn);
void loadDatabases(Pgsql::Connection &conn);
void loadInfo(Pgsql::Connection &conn);
void loadNamespaces(Pgsql::Connection &conn);
void loadTypes(Pgsql::Connection &conn);
const QString& serverVersionString() const; const QString& serverVersionString() const;
int serverVersion() const; int serverVersion() const;
std::shared_ptr<const PgTypeContainer> types() const; std::shared_ptr<const PgAttributeContainer> attributes() const;
std::shared_ptr<const PgDatabaseContainer> databases() const;
std::shared_ptr<const PgAuthIdContainer> authIds() const; std::shared_ptr<const PgAuthIdContainer> authIds() const;
std::shared_ptr<const PgClassContainer> classes() const; std::shared_ptr<const PgClassContainer> classes() const;
std::shared_ptr<const PgDatabaseContainer> databases() const;
std::shared_ptr<const PgNamespaceContainer> namespaces() const;
std::shared_ptr<const PgTypeContainer> types() const;
private: private:
QString m_serverVersionString; QString m_serverVersionString;
int m_serverVersion; int m_serverVersion;
std::shared_ptr<PgTypeContainer> m_types;
std::shared_ptr<PgDatabaseContainer> m_databases; std::shared_ptr<PgAttributeContainer> m_attributes;
std::shared_ptr<PgAuthIdContainer> m_authIds; std::shared_ptr<PgAuthIdContainer> m_authIds;
std::shared_ptr<PgClassContainer> m_classes; std::shared_ptr<PgClassContainer> m_classes;
std::shared_ptr<PgDatabaseContainer> m_databases;
std::shared_ptr<PgNamespaceContainer> m_namespaces;
std::shared_ptr<PgTypeContainer> m_types;
}; };
QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid); QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid);
QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid); QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid);
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid); QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid); QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid);
#endif // PGSQLDATABASECATALOGUE_H #endif // PGSQLDATABASECATALOGUE_H

View file

@ -2,3 +2,8 @@
PgNamespace::PgNamespace() = default; PgNamespace::PgNamespace() = default;
bool PgNamespace::isSystemCatalog() const
{
return name == "pg_catalog"
|| name == "information_schema";
}

View file

@ -4,14 +4,21 @@
#include <QString> #include <QString>
#include <libpq-fe.h> #include <libpq-fe.h>
class PgNamespace class PgNamespace {
{
public: public:
PgNamespace(); PgNamespace();
Oid oid = InvalidOid;
QString name; QString name;
Oid owner = InvalidOid; Oid owner = InvalidOid;
QString acl; QString acl;
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 PgNamespace &rhs) const { return oid < rhs.oid; }
bool isSystemCatalog() const;
}; };
#endif // PGNAMESPACE_H #endif // PGNAMESPACE_H

View file

@ -0,0 +1,23 @@
#include "PgNamespaceContainer.h"
#include "Pgsql_Col.h"
#include "Pgsql_Result.h"
#include "Pgsql_Value.h"
std::string PgNamespaceContainer::getLoadQuery() const
{
return "SELECT oid, nspname, nspowner, nspacl FROM pg_catalog.pg_namespace";
}
void PgNamespaceContainer::load(const Pgsql::Result &res)
{
const int n_rows = res.rows();
m_container.clear();
m_container.reserve(n_rows);
for (auto row : res) {
Pgsql::Col col(row);
PgNamespace v;
col >> v.oid >> v.name >> v.owner >> v.acl;
m_container.push_back(v);
}
std::sort(m_container.begin(), m_container.end());
}

View file

@ -0,0 +1,24 @@
#ifndef PGNAMESPACECONTAINER_H
#define PGNAMESPACECONTAINER_H
#include "PgNamespace.h"
#include "PgContainer.h"
namespace Pgsql {
class Result;
}
class PgNamespaceContainer: public PgContainer<PgNamespace> {
public:
using PgContainer<PgNamespace>::PgContainer;
virtual std::string getLoadQuery() const override;
virtual void load(const Pgsql::Result &res) override;
private:
};
#endif // PGNAMESPACECONTAINER_H

View file

@ -1,5 +1,56 @@
#include "PgType.h" #include "PgType.h"
#include "Pgsql_Connection.h" #include "Pgsql_Connection.h"
void operator<<(TypCategory &s, const Pgsql::Value &v)
{
//s = static_cast<T>(v);
const char *c = v.c_str();
switch (*c) {
case 'A':
s = TypCategory::Array;
break;
case 'B':
s = TypCategory::Boolean;
break;
case 'D':
s = TypCategory::DateTime;
break;
case 'E':
s = TypCategory::Enum;
break;
case 'G':
s = TypCategory::Geometric;
break;
case 'I':
s = TypCategory::NetworkAddress;
break;
case 'N':
s = TypCategory::Numeric;
break;
case 'P':
s = TypCategory::Pseudo;
break;
case 'R':
s = TypCategory::Range;
break;
case 'S':
s = TypCategory::String;
break;
case 'T':
s = TypCategory::Timespan;
break;
case 'U':
s = TypCategory::UserDefined;
break;
case 'V':
s = TypCategory::BitString;
break;
case 'X':
s = TypCategory::Unknown;
break;
}
}
PgType::PgType() = default; PgType::PgType() = default;

View file

@ -3,19 +3,41 @@
#include <QString> #include <QString>
#include <libpq-fe.h> #include <libpq-fe.h>
#include "Pgsql_Value.h"
enum class TypCategory {
Array,
Boolean,
Composite,
DateTime,
Enum,
Geometric,
NetworkAddress,
Numeric,
Pseudo,
Range,
String,
Timespan,
UserDefined,
BitString,
Unknown
};
void operator<<(TypCategory &s, const Pgsql::Value &v);
class PgType { class PgType {
public: public:
PgType(); PgType();
Oid oid = InvalidOid; Oid oid = InvalidOid;
QString typname;//"name";"NO" QString name;//"name";"NO"
Oid typnamespace = InvalidOid;//"oid";"NO" Oid typnamespace = InvalidOid;//"oid";"NO"
Oid typowner = InvalidOid;//"oid";"NO" Oid owner = InvalidOid;//"oid";"NO"
short typlen = -1;//"smallint";"NO" short len = -1;//"smallint";"NO"
bool typbyval = false;//"boolean";"NO" bool byval = false;//"boolean";"NO"
QString typtype;//""char"";"NO" QString type;//""char"";"NO"
QString typcategory;//""char"";"NO" TypCategory category;//""char"";"NO"
bool typispreferred = false;//"boolean";"NO" bool typispreferred = false;//"boolean";"NO"
bool typisdefined = false;//"boolean";"NO" bool typisdefined = false;//"boolean";"NO"
QString typdelim;//""char"";"NO" QString typdelim;//""char"";"NO"
@ -41,7 +63,7 @@ public:
QString typacl;//"ARRAY";"YES" QString typacl;//"ARRAY";"YES"
bool operator==(Oid _oid) const { return oid == _oid; } bool operator==(Oid _oid) const { return oid == _oid; }
bool operator==(const QString &n) const { return typname == n; } bool operator==(const QString &n) const { return name == n; }
bool operator<(Oid _oid) const { return oid < _oid; } bool operator<(Oid _oid) const { return oid < _oid; }
bool operator<(const PgType &rhs) const { return oid < rhs.oid; } bool operator<(const PgType &rhs) const { return oid < rhs.oid; }
}; };

View file

@ -44,13 +44,13 @@ void PgTypeContainer::load(const Pgsql::Result &res)
for (auto row : res) { for (auto row : res) {
PgType v; PgType v;
v.oid << row.get(0); // InvalidOid; v.oid << row.get(0); // InvalidOid;
v.typname << row.get(1); //. operator QString(); // "name";"NO" v.name << row.get(1); //. operator QString(); // "name";"NO"
v.typnamespace << row.get(2); // InvalidOid;//"oid";"NO" v.typnamespace << row.get(2); // InvalidOid;//"oid";"NO"
v.typowner << row.get(3); // InvalidOid;//"oid";"NO" v.owner << row.get(3); // InvalidOid;//"oid";"NO"
v.typlen << row.get(4); // -1;//"smallint";"NO" v.len << row.get(4); // -1;//"smallint";"NO"
v.typbyval << row.get(5); // false;//"boolean";"NO" v.byval << row.get(5); // false;//"boolean";"NO"
v.typtype << row.get(6);//""char"";"NO" v.type << row.get(6);//""char"";"NO"
v.typcategory << row.get(7);//""char"";"NO" v.category << row.get(7);//""char"";"NO"
v.typispreferred << row.get(8); //false;//"boolean";"NO" v.typispreferred << row.get(8); //false;//"boolean";"NO"
v.typisdefined << row.get(9); //false;//"boolean";"NO" v.typisdefined << row.get(9); //false;//"boolean";"NO"
v.typdelim << row.get(10); //""char"";"NO" v.typdelim << row.get(10); //""char"";"NO"

View file

@ -3,7 +3,6 @@
#include "PgType.h" #include "PgType.h"
#include "PgContainer.h" #include "PgContainer.h"
#include <vector>
namespace Pgsql { namespace Pgsql {

View file

@ -1,4 +1,6 @@
#include "ResultTableModelUtil.h" #include "ResultTableModelUtil.h"
#include <QTableView>
#include <QHeaderView>
using namespace Pgsql; using namespace Pgsql;
@ -55,3 +57,36 @@ QString FormatBoolForDisplay(bool v)
return v ? "TRUE" : "FALSE"; return v ? "TRUE" : "FALSE";
} }
//<widget class="QTableView" name="ResultView">
// <property name="font">
// <font>
// <family>Source Sans Pro</family>
// <pointsize>10</pointsize>
// </font>
// </property>
// <property name="editTriggers">
// <set>QAbstractItemView::NoEditTriggers</set>
// </property>
// <property name="verticalScrollMode">
// <enum>QAbstractItemView::ScrollPerPixel</enum>
// </property>
// <property name="horizontalScrollMode">
// <enum>QAbstractItemView::ScrollPerPixel</enum>
// </property>
// <property name="wordWrap">
// <bool>false</bool>
// </property>
// <attribute name="verticalHeaderDefaultSectionSize">
// <number>20</number>
// </attribute>
// <attribute name="verticalHeaderMinimumSectionSize">
// <number>16</number>
// </attribute>
//</widget>
void SetTableViewDefault(QTableView *tv)
{
tv->setAlternatingRowColors(true);
tv->verticalHeader()->setMinimumSectionSize(16);
tv->verticalHeader()->setDefaultSectionSize(20);
}

View file

@ -21,3 +21,5 @@ inline QColor GetDefaultNumericColor() { return Qt::darkGreen; }
QString FormatBoolForDisplay(bool v); QString FormatBoolForDisplay(bool v);
class QTableView;
void SetTableViewDefault(QTableView *tv);

View file

@ -130,7 +130,7 @@ void SqlSyntaxHighlighter::setTypes(const PgTypeContainer& types)
{ {
m_typeNames.clear(); m_typeNames.clear();
for (auto &e : types) { for (auto &e : types) {
m_typeNames.insert(e.typname); m_typeNames.insert(e.name);
} }
} }

View file

@ -1,7 +1,10 @@
#include "TablesPage.h" #include "TablesPage.h"
#include "ui_TablesPage.h" #include "ui_TablesPage.h"
#include "PgAttribute.h"
#include "TablesTableModel.h" #include "TablesTableModel.h"
#include "ResultTableModelUtil.h"
#include "ColumnTableModel.h"
TablesPage::TablesPage(QWidget *parent) : TablesPage::TablesPage(QWidget *parent) :
QWidget(parent), QWidget(parent),
@ -9,9 +12,22 @@ TablesPage::TablesPage(QWidget *parent) :
{ {
ui->setupUi(this); ui->setupUi(this);
SetTableViewDefault(ui->tableListTable);
m_tablesModel = new TablesTableModel(this); m_tablesModel = new TablesTableModel(this);
ui->tableListTable->setModel(m_tablesModel); ui->tableListTable->setModel(m_tablesModel);
SetTableViewDefault(ui->columnsTable);
m_columnsModel = new ColumnTableModel(this);
ui->columnsTable->setModel(m_columnsModel);
connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&TablesPage::on_tableListTable_currentRowChanged);
}
TablesPage::~TablesPage()
{
delete ui;
} }
void TablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat) void TablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
@ -20,7 +36,10 @@ void TablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
m_tablesModel->setCatalog(cat); m_tablesModel->setCatalog(cat);
} }
TablesPage::~TablesPage() void TablesPage::on_tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{ {
delete ui; if (current.row() != previous.row()) {
Oid table_oid = m_tablesModel->getTableOid(current.row());
m_columnsModel->setData(m_catalog, table_oid);
}
} }

View file

@ -9,6 +9,7 @@ class TablesPage;
} }
class TablesTableModel; class TablesTableModel;
class ColumnTableModel;
class PgDatabaseCatalog; class PgDatabaseCatalog;
class TablesPage : public QWidget class TablesPage : public QWidget
@ -24,6 +25,11 @@ private:
Ui::TablesPage *ui; Ui::TablesPage *ui;
std::shared_ptr<PgDatabaseCatalog> m_catalog; std::shared_ptr<PgDatabaseCatalog> m_catalog;
TablesTableModel* m_tablesModel = nullptr; TablesTableModel* m_tablesModel = nullptr;
ColumnTableModel* m_columnsModel = nullptr;
private slots:
void on_tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
}; };
#endif // TABLESPAGE_H #endif // TABLESPAGE_H

View file

@ -2,7 +2,10 @@
#include "PgDatabaseCatalog.h" #include "PgDatabaseCatalog.h"
#include "PgClass.h" #include "PgClass.h"
#include "PgClassContainer.h" #include "PgClassContainer.h"
#include "PgNamespace.h"
#include "PgNamespaceContainer.h"
#include "Pgsql_declare.h" #include "Pgsql_declare.h"
#include <QBrush>
TablesTableModel::TablesTableModel(QObject *parent) TablesTableModel::TablesTableModel(QObject *parent)
: BaseTableModel(parent) : BaseTableModel(parent)
@ -44,6 +47,9 @@ QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation,
case NameCol: case NameCol:
v = tr("Name"); v = tr("Name");
break; break;
case NamespaceCol:
v = tr("Schema");
break;
case OwnerCol: case OwnerCol:
v = tr("Owner"); v = tr("Owner");
break; break;
@ -80,6 +86,7 @@ Oid TablesTableModel::getType(int column) const
case TablespaceCol: case TablespaceCol:
case OwnerCol: case OwnerCol:
case NameCol: case NameCol:
case NamespaceCol:
case OptionsCol: case OptionsCol:
case AclCol: case AclCol:
default: default:
@ -94,7 +101,10 @@ QVariant TablesTableModel::getData(const QModelIndex &index) const
const auto &t = m_tables[index.row()]; const auto &t = m_tables[index.row()];
switch (index.column()) { switch (index.column()) {
case NameCol: case NameCol:
v = formatTableName(t); v = t.name; //formatTableName(t);
break;
case NamespaceCol:
v = getNamespaceDisplayString(*m_catalog, t.relnamespace);
break; break;
case OwnerCol: case OwnerCol:
v = getRoleDisplayString(*m_catalog, t.owner); v = getRoleDisplayString(*m_catalog, t.owner);
@ -113,9 +123,33 @@ QVariant TablesTableModel::getData(const QModelIndex &index) const
return v; return v;
} }
Oid TablesTableModel::getTableOid(int row) const
{
return m_tables[row].oid;
}
QString TablesTableModel::formatTableName(const PgClass &cls) const QString TablesTableModel::formatTableName(const PgClass &cls) const
{ {
const char * format = "%2 (%1)"; const char * format = "%2 (%1)";
QString ns_name = getNamespaceDisplayString(*m_catalog, cls.relnamespace); QString ns_name = getNamespaceDisplayString(*m_catalog, cls.relnamespace);
return QString(format).arg(ns_name).arg(cls.name); return QString(format).arg(ns_name).arg(cls.name);
} }
QVariant TablesTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::ForegroundRole) {
const auto &t = m_tables[index.row()];
auto ns = m_catalog->namespaces()->getByKey(t.relnamespace);
if (ns.isSystemCatalog()) {
switch (index.column()) {
case NameCol:
case NamespaceCol:
return QBrush(Qt::blue);
break;
}
}
}
return BaseTableModel::data(index, role);
}

View file

@ -13,6 +13,7 @@ class TablesTableModel: public BaseTableModel
public: public:
enum e_Columns : int { enum e_Columns : int {
NameCol, ///< either table, ns.table or table (ns) depending on settings/filters NameCol, ///< either table, ns.table or table (ns) depending on settings/filters
NamespaceCol,
OwnerCol, OwnerCol,
TablespaceCol, TablespaceCol,
OptionsCol, OptionsCol,
@ -30,6 +31,8 @@ public:
int rowCount(const QModelIndex &parent) const override; int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override;
virtual QVariant data(const QModelIndex &index, int role) const override;
Oid getTableOid(int row) const;
protected: protected:
virtual Oid getType(int column) const override; virtual Oid getType(int column) const override;
virtual QVariant getData(const QModelIndex &index) const override; virtual QVariant getData(const QModelIndex &index) const override;

View file

@ -61,8 +61,8 @@ void TypeSelectionItemModel::setTypeList(std::shared_ptr<const PgTypeContainer>
beginResetModel(); beginResetModel();
m_types.clear(); m_types.clear();
for (const auto &e : *types) { for (const auto &e : *types) {
if (e.typcategory != "A" && e.typtype != "c") { if (e.category != TypCategory::Array && e.type != "c") {
m_types.push_back(e.typname); m_types.push_back(e.name);
} }
} }
std::sort(m_types.begin(), m_types.end()); std::sort(m_types.begin(), m_types.end());

View file

@ -71,7 +71,12 @@ SOURCES += main.cpp\
TablesPage.cpp \ TablesPage.cpp \
PgClassContainer.cpp \ PgClassContainer.cpp \
TablesTableModel.cpp \ TablesTableModel.cpp \
PgDatabaseCatalog.cpp PgDatabaseCatalog.cpp \
PgNamespaceContainer.cpp \
ColumnTableModel.cpp \
PgAttribute.cpp \
PgContainer.cpp \
PgAttributeContainer.cpp
HEADERS += \ HEADERS += \
QueryResultModel.h \ QueryResultModel.h \
@ -117,7 +122,11 @@ HEADERS += \
TablesPage.h \ TablesPage.h \
PgClassContainer.h \ PgClassContainer.h \
TablesTableModel.h \ TablesTableModel.h \
PgDatabaseCatalog.h PgDatabaseCatalog.h \
PgNamespaceContainer.h \
ColumnTableModel.h \
PgAttribute.h \
PgAttributeContainer.h
FORMS += mainwindow.ui \ FORMS += mainwindow.ui \
DatabaseWindow.ui \ DatabaseWindow.ui \
@ -136,12 +145,27 @@ RESOURCES += \
QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01 QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../core/release/ -lcore win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../core/release/ -lcore
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../core/debug/ -L$$OUT_PWD/../pgsql/debug/ -lcore -lpgsql else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../core/debug/ -lcore
INCLUDEPATH += $$PWD/../core $$PWD/../pgsql INCLUDEPATH += $$PWD/../core
DEPENDPATH += $$PWD/../core $$PWD/../pgsql DEPENDPATH += $$PWD/../core
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/libcore.a win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/libcore.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/libcore.a else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/libcore.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/core.lib else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/core.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/core.lib $$OUT_PWD/../pgsql/debug/pgsql.lib else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/core.lib
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../pgsql/release/ -lpgsql
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../pgsql/debug/ -lpgsql
else:unix:!macx: LIBS += -L$$OUT_PWD/../pgsql/ -lpgsql
INCLUDEPATH += $$PWD/../pgsql
DEPENDPATH += $$PWD/../pgsql
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/release/libpgsql.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/debug/libpgsql.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/release/pgsql.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/debug/pgsql.lib
else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../pgsql/libpgsql.a

View file

@ -7,7 +7,7 @@ namespace Pgsql {
class Col { class Col {
public: public:
explicit Col(Pgsql::Row &r) explicit Col(const Pgsql::Row &r)
: row(r) : row(r)
{} {}
@ -17,16 +17,10 @@ namespace Pgsql {
return row.get(++col); return row.get(++col);
} }
private: private:
Pgsql::Row &row; const Pgsql::Row &row;
int col = -1; int col = -1;
}; };
// template <typename T>
// void operator<<(T &s, Col &c)
// {
// s << c.nextValue();
// }
template <typename T> template <typename T>
Col& operator>>(Col &c, T &s) Col& operator>>(Col &c, T &s)
{ {