From 11459e1e12a0383eb336e55292ba5e294c92ceb8 Mon Sep 17 00:00:00 2001 From: eelke Date: Wed, 10 Mar 2021 19:06:40 +0100 Subject: [PATCH] Show sizes table, index, toast and total size per Table size of each index --- pglab/ColumnTableModel.cpp | 2 +- pglab/ConstraintModel.cpp | 2 +- pglab/CustomDataRole.h | 9 ++++- pglab/IndexModel.cpp | 17 +++++++++- pglab/IndexModel.h | 1 + pglab/PgLabItemDelegate.cpp | 48 +++++++++++++++++++++++---- pglab/PropertyProxyModel.cpp | 3 +- pglab/PropertyProxyModel.h | 2 +- pglab/TablesTableModel.cpp | 30 +++++++++++++++-- pglab/TablesTableModel.h | 5 +++ pglab/widgets/CatalogTablesPage.cpp | 13 ++++---- pglablib/catalog/PgClass.h | 4 +++ pglablib/catalog/PgClassContainer.cpp | 10 ++++-- pglablib/catalog/PgIndex.h | 1 + pglablib/catalog/PgIndexContainer.cpp | 4 +-- pgsql/Pgsql_Value.cpp | 13 ++++++-- pgsql/Pgsql_Value.h | 2 ++ 17 files changed, 138 insertions(+), 28 deletions(-) diff --git a/pglab/ColumnTableModel.cpp b/pglab/ColumnTableModel.cpp index 3f654db..55f5270 100644 --- a/pglab/ColumnTableModel.cpp +++ b/pglab/ColumnTableModel.cpp @@ -131,7 +131,7 @@ QVariant ColumnTableModel::headerData(int section, Qt::Orientation orientation, int ColumnTableModel::rowCount(const QModelIndex &/*parent*/) const { - return m_columns.size(); + return static_cast(m_columns.size()); } int ColumnTableModel::columnCount(const QModelIndex &/*parent*/) const diff --git a/pglab/ConstraintModel.cpp b/pglab/ConstraintModel.cpp index 46c32bb..02b36ea 100644 --- a/pglab/ConstraintModel.cpp +++ b/pglab/ConstraintModel.cpp @@ -67,7 +67,7 @@ QVariant ConstraintModel::headerData(int section, Qt::Orientation orientation, i int ConstraintModel::rowCount(const QModelIndex &) const { - return m_constraints.size(); + return static_cast(m_constraints.size()); } int ConstraintModel::columnCount(const QModelIndex &) const diff --git a/pglab/CustomDataRole.h b/pglab/CustomDataRole.h index 849b678..84f19c3 100644 --- a/pglab/CustomDataRole.h +++ b/pglab/CustomDataRole.h @@ -13,10 +13,17 @@ enum class ReferencedType { PgRole }; +/// +enum DataMeaning { + DataMeaningNormal, + DataMeaningBytes ///< the value represents bytes pretty print in KiB, MiB, GiB, TiB, PiB, EiB +}; + enum CustomDataRole { CustomDataTypeRole = Qt::UserRole, ///< Requist the basic type of the value CustomReferencedTypeRole, ///< - // Add other enum before this one is we might want to have multiple hidden values + CustomDataMeaningRole, + // Add other enum before this one as we might want to have multiple hidden values FirstHiddenValue, ///< Used to request value from a model which is not handed to the view }; diff --git a/pglab/IndexModel.cpp b/pglab/IndexModel.cpp index 968358a..9bdb97d 100644 --- a/pglab/IndexModel.cpp +++ b/pglab/IndexModel.cpp @@ -63,6 +63,9 @@ QVariant IndexModel::headerData(int section, Qt::Orientation orientation, int ro case ConditionCol: c = tr("Condition"); break; + case SizeCol: + c = tr("Size"); + break; // case DefinitionCol: // c = tr("Definition"); // break; @@ -99,6 +102,10 @@ QVariant IndexModel::getData(const QModelIndex &index) const case ConditionCol: break; + + case SizeCol: + v = dat.sizeBytes; + break; } return v; } @@ -110,5 +117,13 @@ QVariant IndexModel::data(const QModelIndex &index, int role) const v = getData(index); else if (role == CustomDataTypeRole) v = getType(index.column()); - return v; + else if (role == CustomDataMeaningRole) { + switch (index.column()) { + case SizeCol: + return static_cast(DataMeaningBytes); + default: + return static_cast(DataMeaningNormal); + } + } + return v; } diff --git a/pglab/IndexModel.h b/pglab/IndexModel.h index 677240f..43267a3 100644 --- a/pglab/IndexModel.h +++ b/pglab/IndexModel.h @@ -22,6 +22,7 @@ public: AmCol, ///< Access Method ColumnsCol, /// ConditionCol, + SizeCol, colCount }; // oid diff --git a/pglab/PgLabItemDelegate.cpp b/pglab/PgLabItemDelegate.cpp index 6340734..39c0de2 100644 --- a/pglab/PgLabItemDelegate.cpp +++ b/pglab/PgLabItemDelegate.cpp @@ -87,6 +87,11 @@ void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option, if (value.isValid()) oid = value.toUInt(); //getType(index.column()); + value = index.data(CustomDataMeaningRole); + DataMeaning meaning = value.isValid() + ? static_cast(value.toInt()) + : DataMeaningNormal; + value = index.data(Qt::DisplayRole); option->displayAlignment = GetDefaultAlignmentForType(oid); @@ -96,18 +101,47 @@ void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option, QColor forground_color = oid == Pgsql::bool_oid ? GetDefaultBoolColor(value.toBool()) : GetDefaultColorForType(oid); - option->palette.setBrush(QPalette::Text, QBrush(forground_color)); option->features |= QStyleOptionViewItem::HasDisplay; if (oid == Pgsql::bool_oid) option->text = FormatBoolForDisplay(value.toBool()); else { - auto str = value.toString(); - auto s = str.left(100); -// auto f = s.indexOf('\n'); -// option->text = ((f > 0) ? s.left(f) : s).toString(); - option->text = s; - } + if (meaning == DataMeaningBytes) { + QString suffix; + auto s = value.toLongLong(); + double val; + if (s > 1024 * 1024 * 1000) { + val = s / (1024 * 1024 * 1024); + suffix = "GiB"; + forground_color = QColorConstants::Svg::darkorange; + option->font.setBold(true); + } + else if (s > 1024 * 1000) { + val = s / (1024 * 1024); + suffix = "MiB"; + forground_color = QColorConstants::Svg::darkgoldenrod; + } + else if (s > 1000) { + val = s / 1024; + suffix = "KiB"; + forground_color = QColorConstants::Svg::darkgreen; + } + else { + val = s; + suffix = "B"; + forground_color = QColorConstants::Svg::darkblue; + } + option->text = QString{ "%1 %2" }.arg(val, 3, 'g', -1 ).arg(suffix) ; + } + else { + auto str = value.toString(); + auto s = str.left(100); + // auto f = s.indexOf('\n'); + // option->text = ((f > 0) ? s.left(f) : s).toString(); + option->text = s; + } + option->palette.setBrush(QPalette::Text, QBrush(forground_color)); + } } else { option->palette.setBrush(QPalette::Text, QBrush(GetDefaultNullColor())); diff --git a/pglab/PropertyProxyModel.cpp b/pglab/PropertyProxyModel.cpp index ba2332f..f9c58a3 100644 --- a/pglab/PropertyProxyModel.cpp +++ b/pglab/PropertyProxyModel.cpp @@ -100,7 +100,8 @@ QVariant PropertyProxyModel::data(const QModelIndex &proxyIndex, int role) const void PropertyProxyModel::setActiveRow(const QModelIndex &row) { activeRow = row.isValid() ? row.row() : -1; - emit dataChanged(index(0, valueColumn), index(rowCount(QModelIndex()), valueColumn), QVector() << Qt::DisplayRole); + emit dataChanged(index(0, valueColumn), index(rowCount(QModelIndex()), valueColumn), + QVector() << Qt::DisplayRole); } Qt::ItemFlags PropertyProxyModel::flags(const QModelIndex &index) const diff --git a/pglab/PropertyProxyModel.h b/pglab/PropertyProxyModel.h index 047a17e..1dd1dec 100644 --- a/pglab/PropertyProxyModel.h +++ b/pglab/PropertyProxyModel.h @@ -20,7 +20,7 @@ public: public Q_SLOTS: /** Updates the model (and view) to show the values for row * - * The column part of the index is not used QModelIndex is used to make is eacy to connect to + * The column part of the index is not used QModelIndex is used to make it easy to connect to * QItemSelectionModel::currentRowChanged */ void setActiveRow(const QModelIndex &row); diff --git a/pglab/TablesTableModel.cpp b/pglab/TablesTableModel.cpp index 5524514..e6eca5c 100644 --- a/pglab/TablesTableModel.cpp +++ b/pglab/TablesTableModel.cpp @@ -132,7 +132,11 @@ QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation, case OptionsCol: return tr("Options"); case AclCol: return tr("ACL"); case CommentCol: return tr("Comment"); - } + case TotalSize: return tr("Total size"); + case TableSize: return tr("Table size"); + case IndexSize: return tr("Index size"); + case ToastSize: return tr("TOAST size"); + } } } return QVariant(); @@ -153,6 +157,12 @@ Oid TablesTableModel::getType(int column) const { Oid oid; switch (column) { + case TotalSize: + case TableSize: + case IndexSize: + case ToastSize: + oid = Pgsql::int8_oid; + break; case TablespaceCol: case OwnerCol: case NameCol: @@ -179,7 +189,11 @@ QVariant TablesTableModel::getData(const QModelIndex &index) const case OptionsCol: break; case AclCol: return t.aclString(); case CommentCol: return t.description; - } + case TotalSize: return t.totalBytes; + case TableSize: return t.totalBytes - t.indexBytes - t.toastBytes; + case IndexSize: return t.indexBytes; + case ToastSize: return t.toastBytes; + } return QVariant(); } @@ -207,5 +221,17 @@ QVariant TablesTableModel::data(const QModelIndex &index, int role) const return getData(index); else if (role == CustomDataTypeRole) return getType(index.column()); + else if (role == CustomDataMeaningRole) { + switch (index.column()) { + case TotalSize: + case TableSize: + case IndexSize: + case ToastSize: + return static_cast(DataMeaningBytes); + default: + return static_cast(DataMeaningNormal); + } + } + return QVariant(); } diff --git a/pglab/TablesTableModel.h b/pglab/TablesTableModel.h index 6d8441a..c6d1e6f 100644 --- a/pglab/TablesTableModel.h +++ b/pglab/TablesTableModel.h @@ -23,6 +23,11 @@ public: OptionsCol, AclCol, CommentCol, + TotalSize, + TableSize, + IndexSize, + ToastSize, + colCount }; TablesTableModel(QObject *parent); diff --git a/pglab/widgets/CatalogTablesPage.cpp b/pglab/widgets/CatalogTablesPage.cpp index f78cabf..5e3b936 100644 --- a/pglab/widgets/CatalogTablesPage.cpp +++ b/pglab/widgets/CatalogTablesPage.cpp @@ -58,9 +58,6 @@ CatalogTablesPage::CatalogTablesPage(QWidget *parent) m_propertiesPage->setSourceModel(m_tablesModel); m_detailsTabs->addTab(m_propertiesPage, ""); - connect(m_tableView->selectionModel(), &QItemSelectionModel::currentRowChanged, - m_propertiesPage, &PropertiesPage::setActiveRow); - // - Trigger page m_triggerPage = new TriggerPage(this); m_detailsTabs->addTab(m_triggerPage, ""); @@ -129,13 +126,17 @@ void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex &curr { if (current.row() != previous.row()) { if (current.isValid()) { - auto row = m_tablesSortFilter->mapToSource(current).row(); + auto sourceIndex = m_tablesSortFilter->mapToSource(current); + auto row = sourceIndex.row(); PgClass table = m_tablesModel->getTable(row); selectedTableChanged(table); + m_propertiesPage->setActiveRow(sourceIndex); } - else + else { selectedTableChanged({}); - } + m_propertiesPage->setActiveRow({}); + } + } } diff --git a/pglablib/catalog/PgClass.h b/pglablib/catalog/PgClass.h index 8510345..f5cc2b9 100644 --- a/pglablib/catalog/PgClass.h +++ b/pglablib/catalog/PgClass.h @@ -50,6 +50,10 @@ public: QString viewdef; QString description; // from pg_description + int64_t totalBytes; + int64_t indexBytes; + int64_t toastBytes; + using PgNamespaceObject::PgNamespaceObject; diff --git a/pglablib/catalog/PgClassContainer.cpp b/pglablib/catalog/PgClassContainer.cpp index 9ae7657..4909a82 100644 --- a/pglablib/catalog/PgClassContainer.cpp +++ b/pglablib/catalog/PgClassContainer.cpp @@ -11,13 +11,17 @@ std::string PgClassContainer::getLoadQuery() const " relowner, relam, relfilenode, reltablespace, relpages, " " reltuples, reltoastrelid, relisshared, relpersistence, " " relkind, relispopulated, relfrozenxid, relminmxid, " - " reloptions, d.description, relacl, pg_get_viewdef(oid)"; + " reloptions, d.description, " + " pg_total_relation_size(oid) AS total_bytes, " + " CASE WHEN relkind='r' THEN pg_indexes_size(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(oid)"; if (lessThenVersion(120000)) q += ", relhasoids "; q += - "\nFROM pg_catalog.pg_class \n" + "\nFROM pg_catalog.pg_class \n" " LEFT JOIN pg_catalog.pg_description AS d ON (objoid=pg_class.oid AND objsubid=0) \n" "WHERE relkind IN ('r', 'i', 'p', 'I', 'v', 'm', 'f')"; @@ -37,7 +41,7 @@ PgClass PgClassContainer::loadElem(const Pgsql::Row &row) >> owner >> v.am >> v.filenode >> v.tablespace >> v.pages_est >> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence >> v.kind >> v.ispopulated >> v.frozenxid >> v.minmxid - >> v.options >> v.description; + >> v.options >> v.description >> v.totalBytes >> v.indexBytes >> v.toastBytes; v.setOwnerOid(owner); diff --git a/pglablib/catalog/PgIndex.h b/pglablib/catalog/PgIndex.h index 3823b23..1d77422 100644 --- a/pglablib/catalog/PgIndex.h +++ b/pglablib/catalog/PgIndex.h @@ -29,6 +29,7 @@ public: QString exprs; QString pred; QString definition; + int64_t sizeBytes; using PgNamespaceObject::PgNamespaceObject; QString getAm() const; diff --git a/pglablib/catalog/PgIndexContainer.cpp b/pglablib/catalog/PgIndexContainer.cpp index c0da0e4..d60121b 100644 --- a/pglablib/catalog/PgIndexContainer.cpp +++ b/pglablib/catalog/PgIndexContainer.cpp @@ -11,7 +11,7 @@ SELECT indexrelid, indrelid, indnatts, indisunique, indisprimary, indisexclusion, indimmediate, indisclustered, indisvalid, indcheckxmin, indisready, indislive, indkey, indcollation, indclass, indoption, indexprs, indpred, - pg_get_indexdef(indexrelid))__"; + pg_get_indexdef(indexrelid), pg_total_relation_size(indexrelid))__"; if (minimumVersion(90400)) q += ", indisreplident "; @@ -35,7 +35,7 @@ PgIndex PgIndexContainer::loadElem(const Pgsql::Row &row) col.getAsVector(std::back_inserter(v.collation)); col.getAsVector(std::back_inserter(v.indclass)); col.getAsVector(std::back_inserter(v.option)); - col >> v.exprs >> v.pred >> v.definition; + col >> v.exprs >> v.pred >> v.definition >> v.sizeBytes; if (minimumVersion(90400)) col >> v.isreplident; diff --git a/pgsql/Pgsql_Value.cpp b/pgsql/Pgsql_Value.cpp index b9ee9bf..966f194 100644 --- a/pgsql/Pgsql_Value.cpp +++ b/pgsql/Pgsql_Value.cpp @@ -47,7 +47,10 @@ Value::operator std::string() const Value::operator int16_t() const { - int32_t r = operator int32_t(); + if (m_val == nullptr) + return 0; + + int32_t r = operator int32_t(); if (r <= std::numeric_limits::max() && r >= std::numeric_limits::min()) return int16_t(r); @@ -57,7 +60,10 @@ Value::operator int16_t() const Value::operator int32_t() const { - const size_t len = std::strlen(m_val); + if (m_val == nullptr) + return 0; + + const size_t len = std::strlen(m_val); if (len > 0) { char *endptr = nullptr; long result = std::strtol(m_val, &endptr, 10); @@ -74,6 +80,9 @@ Value::operator Oid() const Value::operator int64_t() const { + if (m_val == nullptr) + return 0LL; + const int len = std::strlen(m_val); if (len > 0) { char *endptr = nullptr; diff --git a/pgsql/Pgsql_Value.h b/pgsql/Pgsql_Value.h index bc0e80b..78f2098 100644 --- a/pgsql/Pgsql_Value.h +++ b/pgsql/Pgsql_Value.h @@ -44,6 +44,8 @@ namespace Pgsql { bool isString() const; + + /// Retrieves an array type value and passes them to an insert iterator. /// /// When the array it self is NULL this function behaves the same as for an empty array. No