Retrieve tables sizes asynchronously when opening the catalog.
This commit is contained in:
parent
8fe5e05f7d
commit
39195153cd
8 changed files with 163 additions and 52 deletions
|
|
@ -18,7 +18,7 @@ CatalogInspector::CatalogInspector(std::shared_ptr<OpenDatabase> open_database,
|
||||||
{
|
{
|
||||||
m_tabWidget = new QTabWidget(this);
|
m_tabWidget = new QTabWidget(this);
|
||||||
// m_namespacePage = new CatalogNamespacePage(this);
|
// m_namespacePage = new CatalogNamespacePage(this);
|
||||||
m_tablesPage = new CatalogTablesPage(this);
|
m_tablesPage = new CatalogTablesPage(open_database, this);
|
||||||
m_functionsPage = new CatalogFunctionsPage(this);
|
m_functionsPage = new CatalogFunctionsPage(this);
|
||||||
m_sequencesPage = new CatalogSequencesPage(this);
|
m_sequencesPage = new CatalogSequencesPage(this);
|
||||||
m_typesPage = new CatalogTypesPage(this);
|
m_typesPage = new CatalogTypesPage(this);
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,22 @@ class PgDatabaseCatalog;
|
||||||
template <typename TableModel>
|
template <typename TableModel>
|
||||||
class PgLabTableViewHelper {
|
class PgLabTableViewHelper {
|
||||||
public:
|
public:
|
||||||
PgLabTableViewHelper(QWidget * parent)
|
|
||||||
|
PgLabTableViewHelper(QWidget * parent, TableModel *tableModel)
|
||||||
{
|
{
|
||||||
m_tableView = new PgLabTableView(parent);
|
m_tableView = new PgLabTableView(parent);
|
||||||
|
|
||||||
m_dataModel = new TableModel(parent);
|
m_dataModel = tableModel;
|
||||||
m_sortFilter = new QSortFilterProxyModel(parent);
|
m_sortFilter = new QSortFilterProxyModel(parent);
|
||||||
m_sortFilter->setSourceModel(m_dataModel);
|
m_sortFilter->setSourceModel(m_dataModel);
|
||||||
m_tableView->setModel(m_sortFilter);
|
m_tableView->setModel(m_sortFilter);
|
||||||
m_tableView->setSortingEnabled(true);
|
m_tableView->setSortingEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PgLabTableViewHelper(QWidget * parent)
|
||||||
|
: PgLabTableViewHelper(parent, new TableModel(parent))
|
||||||
|
{}
|
||||||
|
|
||||||
PgLabTableView *tableView() const
|
PgLabTableView *tableView() const
|
||||||
{
|
{
|
||||||
return m_tableView;
|
return m_tableView;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "TablesTableModel.h"
|
#include "TablesTableModel.h"
|
||||||
|
#include "OpenDatabase.h"
|
||||||
#include "ScopeGuard.h"
|
#include "ScopeGuard.h"
|
||||||
#include "catalog/PgDatabaseCatalog.h"
|
#include "catalog/PgDatabaseCatalog.h"
|
||||||
#include "catalog/PgClass.h"
|
#include "catalog/PgClass.h"
|
||||||
|
|
@ -8,9 +9,12 @@
|
||||||
#include "Pgsql_declare.h"
|
#include "Pgsql_declare.h"
|
||||||
#include "CustomDataRole.h"
|
#include "CustomDataRole.h"
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
|
#include <QtConcurrent>
|
||||||
|
#include "Pgsql_Connection.h"
|
||||||
|
|
||||||
TablesTableModel::TablesTableModel(QObject *parent)
|
TablesTableModel::TablesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent)
|
||||||
: QAbstractTableModel(parent)
|
: QAbstractTableModel(parent)
|
||||||
|
, openDatabase(opendatabase)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void TablesTableModel::setNamespaceFilter(NamespaceFilter nsf)
|
void TablesTableModel::setNamespaceFilter(NamespaceFilter nsf)
|
||||||
|
|
@ -40,6 +44,7 @@ void TablesTableModel::refresh()
|
||||||
// Later afscheiden naar filter functie
|
// Later afscheiden naar filter functie
|
||||||
auto classes = m_catalog->classes();
|
auto classes = m_catalog->classes();
|
||||||
|
|
||||||
|
std::map<Oid, int> oidIndex;
|
||||||
m_tables.clear();
|
m_tables.clear();
|
||||||
for (const auto &e : *classes) {
|
for (const auto &e : *classes) {
|
||||||
bool add = false;
|
bool add = false;
|
||||||
|
|
@ -57,9 +62,12 @@ void TablesTableModel::refresh()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (add)
|
if (add) {
|
||||||
m_tables.push_back(e);
|
m_tables.emplace_back(e);
|
||||||
|
oidIndex.emplace(e.oid(), m_tables.size() - 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
StartLoadTableSizes(std::move(oidIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
|
@ -75,10 +83,10 @@ QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation,
|
||||||
case OptionsCol: return tr("Options");
|
case OptionsCol: return tr("Options");
|
||||||
case AclCol: return tr("ACL");
|
case AclCol: return tr("ACL");
|
||||||
case CommentCol: return tr("Comment");
|
case CommentCol: return tr("Comment");
|
||||||
case TotalSize: return tr("Total size");
|
case TotalSizeCol: return tr("Total size");
|
||||||
case TableSize: return tr("Table size");
|
case TableSizeCol: return tr("Table size");
|
||||||
case IndexSize: return tr("Index size");
|
case IndexSizeCol: return tr("Index size");
|
||||||
case ToastSize: return tr("TOAST size");
|
case ToastSizeCol: return tr("TOAST size");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -99,10 +107,10 @@ Oid TablesTableModel::getType(int column) const
|
||||||
{
|
{
|
||||||
Oid oid;
|
Oid oid;
|
||||||
switch (column) {
|
switch (column) {
|
||||||
case TotalSize:
|
case TotalSizeCol:
|
||||||
case TableSize:
|
case TableSizeCol:
|
||||||
case IndexSize:
|
case IndexSizeCol:
|
||||||
case ToastSize:
|
case ToastSizeCol:
|
||||||
oid = Pgsql::int8_oid;
|
oid = Pgsql::int8_oid;
|
||||||
break;
|
break;
|
||||||
case TablespaceCol:
|
case TablespaceCol:
|
||||||
|
|
@ -121,7 +129,9 @@ Oid TablesTableModel::getType(int column) const
|
||||||
|
|
||||||
QVariant TablesTableModel::getData(const QModelIndex &index) const
|
QVariant TablesTableModel::getData(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
const auto &t = m_tables[index.row()];
|
const auto &table = m_tables[index.row()];
|
||||||
|
const auto &t = table._class;
|
||||||
|
const auto &s = table.sizes;
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case NameCol: return t.objectName();
|
case NameCol: return t.objectName();
|
||||||
case NamespaceCol: return t.nsName();
|
case NamespaceCol: return t.nsName();
|
||||||
|
|
@ -131,10 +141,10 @@ QVariant TablesTableModel::getData(const QModelIndex &index) const
|
||||||
case OptionsCol: break;
|
case OptionsCol: break;
|
||||||
case AclCol: return t.aclString();
|
case AclCol: return t.aclString();
|
||||||
case CommentCol: return t.description;
|
case CommentCol: return t.description;
|
||||||
case TotalSize: return t.totalBytes;
|
case TotalSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes;
|
||||||
case TableSize: return t.totalBytes - t.indexBytes - t.toastBytes;
|
case TableSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes - s.indexBytes - s.toastBytes;
|
||||||
case IndexSize: return t.indexBytes;
|
case IndexSizeCol: return s.oid == 0 ? QVariant() : s.indexBytes;
|
||||||
case ToastSize: return t.toastBytes;
|
case ToastSizeCol: return s.oid == 0 ? QVariant() : s.toastBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
@ -142,12 +152,12 @@ QVariant TablesTableModel::getData(const QModelIndex &index) const
|
||||||
|
|
||||||
PgClass TablesTableModel::getTable(int row) const
|
PgClass TablesTableModel::getTable(int row) const
|
||||||
{
|
{
|
||||||
return m_tables[row];
|
return m_tables[row]._class;
|
||||||
}
|
}
|
||||||
|
|
||||||
Oid TablesTableModel::getTableOid(int row) const
|
Oid TablesTableModel::getTableOid(int row) const
|
||||||
{
|
{
|
||||||
return m_tables[row].oid();
|
return m_tables[row]._class.oid();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant TablesTableModel::data(const QModelIndex &index, int role) const
|
QVariant TablesTableModel::data(const QModelIndex &index, int role) const
|
||||||
|
|
@ -158,10 +168,10 @@ QVariant TablesTableModel::data(const QModelIndex &index, int role) const
|
||||||
return getType(index.column());
|
return getType(index.column());
|
||||||
else if (role == CustomDataMeaningRole) {
|
else if (role == CustomDataMeaningRole) {
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case TotalSize:
|
case TotalSizeCol:
|
||||||
case TableSize:
|
case TableSizeCol:
|
||||||
case IndexSize:
|
case IndexSizeCol:
|
||||||
case ToastSize:
|
case ToastSizeCol:
|
||||||
return static_cast<int>(DataMeaningBytes);
|
return static_cast<int>(DataMeaningBytes);
|
||||||
default:
|
default:
|
||||||
return static_cast<int>(DataMeaningNormal);
|
return static_cast<int>(DataMeaningNormal);
|
||||||
|
|
@ -170,3 +180,80 @@ QVariant TablesTableModel::data(const QModelIndex &index, int role) const
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TablesTableModel::StartLoadTableSizes(std::map<Oid, int> oidIndex)
|
||||||
|
{
|
||||||
|
QPointer p(this);
|
||||||
|
QtConcurrent::run([this]
|
||||||
|
{
|
||||||
|
return QueryTableSizes();
|
||||||
|
})
|
||||||
|
.then(qApp, [p, oidIndex] (std::vector<TableSize> sizes)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
p.data()->PopulateSizes(std::move(oidIndex), std::move(sizes));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TablesTableModel::TableSizes TablesTableModel::QueryTableSizes() const
|
||||||
|
{
|
||||||
|
std::string nsfilter;
|
||||||
|
switch (m_namespaceFilter)
|
||||||
|
{
|
||||||
|
case NamespaceFilter::User:
|
||||||
|
nsfilter = "(NOT (nspname LIKE 'pg_%' OR nspname='information_schema'))";
|
||||||
|
break;
|
||||||
|
case NamespaceFilter::PgCatalog:
|
||||||
|
nsfilter = "nspname = 'pg_catalog'";
|
||||||
|
break;
|
||||||
|
case NamespaceFilter::InformationSchema:
|
||||||
|
nsfilter = "nspname = 'information_schema'";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string q =
|
||||||
|
"SELECT pg_class.oid, "
|
||||||
|
" pg_total_relation_size(pg_class.oid) AS total_bytes, "
|
||||||
|
" CASE WHEN relkind='r' THEN pg_indexes_size(pg_class.oid) ELSE 0 END AS index_bytes, "
|
||||||
|
" CASE WHEN relkind='r' THEN pg_total_relation_size(reltoastrelid) ELSE 0 END AS toast_bytes "
|
||||||
|
"\nFROM pg_catalog.pg_class \n"
|
||||||
|
" JOIN pg_namespace ON (relnamespace = pg_namespace.oid)"
|
||||||
|
" LEFT JOIN pg_catalog.pg_description AS d ON (objoid=pg_class.oid AND objsubid=0) \n"
|
||||||
|
"WHERE relkind IN ('r', 'p', 'm') AND " + nsfilter;
|
||||||
|
|
||||||
|
;
|
||||||
|
Pgsql::Connection connection;
|
||||||
|
connection.connect(openDatabase->config().connectionString());
|
||||||
|
Pgsql::Result sizesResult = connection.query(q.c_str());
|
||||||
|
|
||||||
|
TablesTableModel::TableSizes sizes;
|
||||||
|
sizes.reserve(sizesResult.rows());
|
||||||
|
for (const Pgsql::Row& row : sizesResult)
|
||||||
|
{
|
||||||
|
TableSize size;
|
||||||
|
size.oid = row.get(0);
|
||||||
|
size.totalBytes = row.get(1);
|
||||||
|
size.indexBytes = row.get(2);
|
||||||
|
size.toastBytes = row.get(3);
|
||||||
|
sizes.push_back(size);
|
||||||
|
}
|
||||||
|
return sizes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TablesTableModel::PopulateSizes(std::map<Oid, int> oidIndex, std::vector<TableSize> sizes)
|
||||||
|
{
|
||||||
|
for (auto s : sizes)
|
||||||
|
{
|
||||||
|
auto findIter = oidIndex.find(s.oid);
|
||||||
|
if (findIter != oidIndex.end())
|
||||||
|
{
|
||||||
|
m_tables[findIter->second].sizes = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit dataChanged(
|
||||||
|
createIndex(0, TotalSizeCol),
|
||||||
|
createIndex(static_cast<int>(m_tables.size()), ToastSizeCol)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,10 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class OpenDatabase;
|
||||||
class PgClass;
|
class PgClass;
|
||||||
class PgDatabaseCatalog;
|
class PgDatabaseCatalog;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TablesTableModel: public QAbstractTableModel {
|
class TablesTableModel: public QAbstractTableModel {
|
||||||
public:
|
public:
|
||||||
using RowItem = PgClass;
|
using RowItem = PgClass;
|
||||||
|
|
@ -24,14 +23,14 @@ public:
|
||||||
OptionsCol,
|
OptionsCol,
|
||||||
AclCol,
|
AclCol,
|
||||||
CommentCol,
|
CommentCol,
|
||||||
TotalSize,
|
TotalSizeCol,
|
||||||
TableSize,
|
TableSizeCol,
|
||||||
IndexSize,
|
IndexSizeCol,
|
||||||
ToastSize,
|
ToastSizeCol,
|
||||||
|
|
||||||
colCount };
|
colCount };
|
||||||
|
|
||||||
TablesTableModel(QObject *parent);
|
TablesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent);
|
||||||
|
|
||||||
void setNamespaceFilter(NamespaceFilter nsf);
|
void setNamespaceFilter(NamespaceFilter nsf);
|
||||||
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
|
void setCatalog(std::shared_ptr<const PgDatabaseCatalog> cat);
|
||||||
|
|
@ -50,16 +49,44 @@ public:
|
||||||
Oid getTableOid(int row) const;
|
Oid getTableOid(int row) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using t_Tables = std::vector<PgClass>;
|
class TableSize {
|
||||||
|
public:
|
||||||
|
int oid;
|
||||||
|
int64_t totalBytes = -1;
|
||||||
|
int64_t indexBytes = -1;
|
||||||
|
int64_t toastBytes = -1;
|
||||||
|
|
||||||
|
TableSize()
|
||||||
|
: oid(0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
using TableSizes = std::vector<class TableSize>;
|
||||||
|
|
||||||
|
class Table {
|
||||||
|
public:
|
||||||
|
PgClass _class;
|
||||||
|
class TableSize sizes;
|
||||||
|
|
||||||
|
Table(const PgClass &cls)
|
||||||
|
: _class(cls)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
using t_Tables = std::vector<Table>;
|
||||||
|
|
||||||
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
|
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
|
||||||
NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
|
NamespaceFilter m_namespaceFilter = NamespaceFilter::User;
|
||||||
t_Tables m_tables;
|
t_Tables m_tables;
|
||||||
QMetaObject::Connection refreshConnection;
|
QMetaObject::Connection refreshConnection;
|
||||||
|
std::shared_ptr<OpenDatabase> openDatabase;
|
||||||
|
|
||||||
|
|
||||||
Oid getType(int column) const;
|
Oid getType(int column) const;
|
||||||
QVariant getData(const QModelIndex &index) const;
|
QVariant getData(const QModelIndex &index) const;
|
||||||
|
|
||||||
|
void StartLoadTableSizes(std::map<Oid, int> oidIndex);
|
||||||
|
TableSizes QueryTableSizes() const;
|
||||||
|
void PopulateSizes(std::map<Oid, int> oidIndex, std::vector<TableSize> sizes);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
|
|
||||||
CatalogTablesPage::CatalogTablesPage(QWidget *parent)
|
CatalogTablesPage::CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget *parent)
|
||||||
: QSplitter(Qt::Horizontal, parent)
|
: QSplitter(Qt::Horizontal, parent)
|
||||||
, m_tablesTableView(this)
|
, m_tablesTableView(this, new TablesTableModel(opendatabase, this))
|
||||||
{
|
{
|
||||||
auto tv = m_tablesTableView.tableView();
|
auto tv = m_tablesTableView.tableView();
|
||||||
tv->setSelectionMode(QAbstractItemView::SingleSelection);
|
tv->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class TriggerPage;
|
||||||
class CatalogTablesPage: public QSplitter {
|
class CatalogTablesPage: public QSplitter {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CatalogTablesPage(QWidget * parent = nullptr);
|
explicit CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget * parent = nullptr);
|
||||||
|
|
||||||
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat);
|
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat);
|
||||||
void setNamespaceFilter(NamespaceFilter filter);
|
void setNamespaceFilter(NamespaceFilter filter);
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,6 @@ public:
|
||||||
QString viewdef;
|
QString viewdef;
|
||||||
|
|
||||||
QString description; // from pg_description
|
QString description; // from pg_description
|
||||||
int64_t totalBytes;
|
|
||||||
int64_t indexBytes;
|
|
||||||
int64_t toastBytes;
|
|
||||||
|
|
||||||
|
|
||||||
using PgNamespaceObject::PgNamespaceObject;
|
using PgNamespaceObject::PgNamespaceObject;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,6 @@ std::string PgClassContainer::getLoadQuery() const
|
||||||
" reltuples, reltoastrelid, relisshared, relpersistence, "
|
" reltuples, reltoastrelid, relisshared, relpersistence, "
|
||||||
" relkind, relispopulated, relfrozenxid, relminmxid, "
|
" relkind, relispopulated, relfrozenxid, relminmxid, "
|
||||||
" reloptions, d.description, "
|
" reloptions, d.description, "
|
||||||
" pg_total_relation_size(pg_class.oid) AS total_bytes, "
|
|
||||||
" CASE WHEN relkind='r' THEN pg_indexes_size(pg_class.oid) ELSE 0 END AS index_bytes, "
|
|
||||||
" CASE WHEN relkind='r' THEN pg_total_relation_size(reltoastrelid) ELSE 0 END AS toast_bytes, "
|
|
||||||
" relacl, pg_get_viewdef(pg_class.oid)";
|
" relacl, pg_get_viewdef(pg_class.oid)";
|
||||||
|
|
||||||
if (lessThenVersion(120000))
|
if (lessThenVersion(120000))
|
||||||
|
|
@ -41,8 +38,7 @@ PgClass PgClassContainer::loadElem(const Pgsql::Row &row)
|
||||||
>> owner >> v.am >> v.filenode >> v.tablespace >> v.pages_est
|
>> owner >> v.am >> v.filenode >> v.tablespace >> v.pages_est
|
||||||
>> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence
|
>> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence
|
||||||
>> v.kind >> v.ispopulated >> v.frozenxid >> v.minmxid
|
>> v.kind >> v.ispopulated >> v.frozenxid >> v.minmxid
|
||||||
>> v.options >> v.description >> v.totalBytes >> v.indexBytes >> v.toastBytes;
|
>> v.options >> v.description;
|
||||||
|
|
||||||
|
|
||||||
v.setOwnerOid(owner);
|
v.setOwnerOid(owner);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue