diff --git a/pglab/DatabasesTableModel.cpp b/pglab/DatabasesTableModel.cpp index 039d150..d53b9a8 100644 --- a/pglab/DatabasesTableModel.cpp +++ b/pglab/DatabasesTableModel.cpp @@ -142,10 +142,9 @@ QVariant DatabasesTableModel::getData(const QModelIndex &index) const v = db.objectName(); break; case DbaCol: - v = getRoleDisplayString(*m_catalog, db.dba); + v = db.ownerName(); break; case EncodingCol: - // todo lookup encoding name v = db.encodingString; break; case CollateCol: @@ -164,7 +163,6 @@ QVariant DatabasesTableModel::getData(const QModelIndex &index) const v = db.connLimit; break; case TablespaceCol: - // todo lookup tablespace name v = getTablespaceDisplayString(*m_catalog, db.tablespace); break; case CommentCol: diff --git a/pglab/DatabasesTableModel.h b/pglab/DatabasesTableModel.h index f0dbfe6..a8ecc8e 100644 --- a/pglab/DatabasesTableModel.h +++ b/pglab/DatabasesTableModel.h @@ -38,6 +38,10 @@ public: virtual Oid getType(int column) const override; virtual QVariant getData(const QModelIndex &index) const override; + RowItem rowItem(int row) const + { + return databases.at(row).database; + } protected: virtual QVariant getDataMeaning(const QModelIndex &index) const override; private: diff --git a/pglab/serverinspector/DatabasesPage.cpp b/pglab/serverinspector/DatabasesPage.cpp index 8946eef..239f23f 100644 --- a/pglab/serverinspector/DatabasesPage.cpp +++ b/pglab/serverinspector/DatabasesPage.cpp @@ -1,8 +1,11 @@ #include "DatabasesPage.h" #include "DatabasesTableModel.h" +#include "SqlCodePreview.h" +#include "SqlFormattingUtils.h" #include "catalog/PgDatabaseCatalog.h" #include "PgLabTableView.h" +#include DatabasesPage::DatabasesPage(std::shared_ptr opendatabase, QWidget * parent) @@ -12,10 +15,18 @@ DatabasesPage::DatabasesPage(std::shared_ptr opendatabase, QWidget auto tv = m_databasesTableView.tableView(); tv->setSelectionMode(QAbstractItemView::SingleSelection); - m_detailsTabs = new QTabWidget(this); +// m_detailsTabs = new QTabWidget(this); addWidget(tv); - addWidget(m_detailsTabs); +// addWidget(m_detailsTabs); + + m_tableSql = new SqlCodePreview(this); +// m_detailsTabs->addTab(m_tableSql, ""); + addWidget(m_tableSql); + + + connect(m_databasesTableView.tableView()->selectionModel(), &QItemSelectionModel::currentRowChanged, + this, &DatabasesPage::databaseSelectionChanged); } void DatabasesPage::setCatalog(std::shared_ptr cat) @@ -25,6 +36,34 @@ void DatabasesPage::setCatalog(std::shared_ptr cat) m_databasesTableView.tableView()->resizeColumnsToContents(); } +void DatabasesPage::updateDatabaseDetails(const PgDatabase &db) +{ + updateSqlTab(db); +} + +void DatabasesPage::updateSqlTab(const PgDatabase &db) +{ + QString drop_sql = db.dropSql(); + QString create_sql = db.createSql(); + + create_sql += "\n\n-- set Privileges\n"; + create_sql += db.grantSql() % "\n"; + + create_sql += "-- set comment\n"; + create_sql += db.commentSql() % "\n"; + + m_tableSql->setPlainText(drop_sql % "\n\n" % create_sql); +} + +void DatabasesPage::databaseSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + if (current.row() == previous.row()) + return; + + auto db = m_databasesTableView.rowItemForProxyIndex(current); + updateDatabaseDetails(db); +} + diff --git a/pglab/serverinspector/DatabasesPage.h b/pglab/serverinspector/DatabasesPage.h index 62b9161..e76671f 100644 --- a/pglab/serverinspector/DatabasesPage.h +++ b/pglab/serverinspector/DatabasesPage.h @@ -6,9 +6,11 @@ #include "PgLabTableViewHelper.h" #include "DatabasesTableModel.h" +class PgDatabase; class PgDatabaseCatalog; class PgLabTableView; class QSortFilterProxyModel; +class SqlCodePreview; class DatabasesPage: public QSplitter { public: @@ -20,9 +22,16 @@ public: private: PgLabTableViewHelper m_databasesTableView; - QTabWidget *m_detailsTabs = nullptr; +// QTabWidget *m_detailsTabs = nullptr; + SqlCodePreview *m_tableSql = nullptr; std::shared_ptr m_catalog; + void updateDatabaseDetails(const PgDatabase &db); + void updateSqlTab(const PgDatabase &db); + +private slots: + + void databaseSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous); }; diff --git a/pglab/widgets/CatalogTablesPage.cpp b/pglab/widgets/CatalogTablesPage.cpp index c2df79a..1ed83ac 100644 --- a/pglab/widgets/CatalogTablesPage.cpp +++ b/pglab/widgets/CatalogTablesPage.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +//#include #include CatalogTablesPage::CatalogTablesPage(std::shared_ptr opendatabase, QWidget *parent) @@ -69,12 +69,6 @@ CatalogTablesPage::CatalogTablesPage(std::shared_ptr opendatabase, // Signals connect(tv->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &CatalogTablesPage::tableListTable_currentRowChanged); -// connect(m_tablesTableView.dataModel(), &TablesTableModel::modelReset, -// [this] () -// { -// selectedTableChanged({}); -// m_propertiesPage->setActiveRow({}); -// }); connect(m_tablesTableView.dataModel(), &QAbstractItemModel::layoutChanged, this, &CatalogTablesPage::tableListTable_layoutChanged); @@ -117,10 +111,11 @@ void CatalogTablesPage::setNamespaceFilter(NamespaceFilter filter) void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) { - if (current.row() != previous.row()) { - auto table = m_tablesTableView.rowItemForProxyIndex(current); - selectedTableChanged(table); - } + if (current.row() == previous.row()) + return; + + auto table = m_tablesTableView.rowItemForProxyIndex(current); + selectedTableChanged(table); } @@ -160,8 +155,9 @@ void CatalogTablesPage::updateSqlTab(const std::optional &table) QString drop_sql; QString create_sql; - // create table - create_sql += table->createSql(); + // table + drop_sql += table->dropSql() % "\n"; + create_sql += table->createSql() % "\n"; // - columns // - constraints // table details (inherits etc) @@ -194,10 +190,7 @@ void CatalogTablesPage::updateSqlTab(const std::optional &table) // Comments create_sql += "-- set Comments table + columns\n"; - if (!table->description.isEmpty()) { - create_sql += "COMMENT ON TABLE " + table->fullyQualifiedQuotedObjectName() - + " IS " + dollarQuoteString(table->description) + ";\n"; - } + create_sql += table->commentSql() % "\n"; auto && cols = m_catalog->attributes()->getColumnsForRelation(table->oid()); for (auto && col : cols) { diff --git a/pglablib/catalog/PgClass.cpp b/pglablib/catalog/PgClass.cpp index 557453e..ed7f71b 100644 --- a/pglablib/catalog/PgClass.cpp +++ b/pglablib/catalog/PgClass.cpp @@ -13,7 +13,8 @@ void operator<<(RelPersistence &s, const Pgsql::Value &v) { //s = static_cast(v); const char *c = v.c_str(); - switch (*c) { + switch (*c) + { case 'p': s = RelPersistence::Permanent; break; @@ -30,7 +31,8 @@ void operator<<(RelKind &s, const Pgsql::Value &v) { //s = static_cast(v); const char *c = v.c_str(); - switch (*c) { + switch (*c) + { case 'r': s = RelKind::Table; break; @@ -58,26 +60,27 @@ void operator<<(RelKind &s, const Pgsql::Value &v) } } -//QString PgClass::objectName() const -//{ -// return name; -//} - QString PgClass::createSql() const { - if (createSqlCache.isEmpty()) { - if (kind == RelKind::Table) - createSqlCache = createTableSql(); - else if (kind == RelKind::View) - createSqlCache = createViewSql(); - + if (createSqlCache.isEmpty()) + { + switch (kind) + { + case RelKind::Table: + createSqlCache = createTableSql(); + break; + case RelKind::View: + createSqlCache = createViewSql(); + break; + } } return createSqlCache; } QString PgClass::typeName() const { - switch (kind) { + switch (kind) + { case RelKind::Table: return "TABLE"; case RelKind::Index: return "INDEX"; case RelKind::Sequence: return "SEQUENCE"; @@ -92,7 +95,8 @@ QString PgClass::typeName() const QString PgClass::aclAllPattern() const { - switch (kind) { + switch (kind) + { case RelKind::Table: return "arwdDxt"; default: break; @@ -115,9 +119,12 @@ QString PgClass::createTableSql() const auto && cols = catalog().attributes()->getColumnsForRelation(oid()); bool first = true; - for (auto && col : cols) { - if (col.num > 0 && !col.isdropped) { - if (first) { + for (auto && col : cols) + { + if (col.num > 0 && !col.isdropped) + { + if (first) + { first = false; } else sql += ",\n "; @@ -129,8 +136,10 @@ QString PgClass::createTableSql() const // ] ) } auto && constraints = catalog().constraints()->getConstraintsForRelation(oid()); - for (auto && constraint: constraints) { - if (first) { + for (auto && constraint: constraints) + { + if (first) + { sql += "\n "; first = false; } @@ -142,10 +151,12 @@ QString PgClass::createTableSql() const { // [ INHERITS ( parent_table [, ... ] ) ] auto parents = catalog().inherits()->getParentsOf(oid()); - if (!parents.empty()) { + if (!parents.empty()) + { sql += "\nINHERITS ("; bool first = true; - for (auto parent_oid : parents) { + for (auto parent_oid : parents) + { if (first) first = false; else sql += ", "; sql += catalog().classes()->getByKey(parent_oid)->fullyQualifiedQuotedObjectName(); @@ -156,8 +167,12 @@ QString PgClass::createTableSql() const // [ PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ] // [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] // [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] -// [ TABLESPACE tablespace_name ] - sql += ";\n"; + if (tablespace != 0) + { + auto ns = getTablespaceDisplayString(catalog(), tablespace); + sql += "\n TABLESPACE " % quoteIdent(ns); + } + sql += ";\n"; return sql; } diff --git a/pglablib/catalog/PgClass.h b/pglablib/catalog/PgClass.h index 8510345..0121a28 100644 --- a/pglablib/catalog/PgClass.h +++ b/pglablib/catalog/PgClass.h @@ -32,7 +32,6 @@ class PgClass: public PgNamespaceObject { public: Oid type = InvalidOid; Oid oftype = InvalidOid; - //Oid owner = InvalidOid; Oid am = InvalidOid; Oid filenode = InvalidOid; Oid tablespace = InvalidOid; @@ -49,8 +48,6 @@ public: std::vector options; QString viewdef; - QString description; // from pg_description - using PgNamespaceObject::PgNamespaceObject; QString kindString() const; diff --git a/pglablib/catalog/PgDatabase.cpp b/pglablib/catalog/PgDatabase.cpp index 3c1bffe..7b401d1 100644 --- a/pglablib/catalog/PgDatabase.cpp +++ b/pglablib/catalog/PgDatabase.cpp @@ -1,6 +1,51 @@ #include "PgDatabase.h" +#include "PgDatabaseCatalog.h" +#include "SqlFormattingUtils.h" +#include QString PgDatabase::typeName() const { - return "DATABASE"; + return "DATABASE"; +} + +QString PgDatabase::aclAllPattern() const +{ + // Create + // Connect + // Temporary + return "CcT"; +} + +QString PgDatabase::dropSql() const +{ + return "DROP DATABASE " % quotedObjectName() % ";"; +} + +QString PgDatabase::createSql() const +{ + QString s = "CREATE DATABASE " % quotedObjectName() + // TEMPLATE is missing as this is not stored in the catalog + % "\n OWNER " % quoteIdent(ownerName()) + % "\n ENCODING " % escapeLiteral(encodingString) + % "\n LC_COLLATE " % escapeLiteral(collate) + % "\n LC_TYPE " % escapeLiteral(ctype); + auto ns = getTablespaceDisplayString(catalog(), tablespace); + if (ns != "pg_default") + { + s += "\n TABLESPACE " % quoteIdent(ns); + } + if (!allowConn) + { + s += "\n ALLOW_CONNECTIONS FALSE"; + } + if (connLimit >= 0) + { + s += "\n CONNECTION LIMIT " % QString::number(connLimit); + } + if (isTemplate) + { + s += "\n IS_TEMPLATE TRUE"; + } + s += ";"; + return s; } diff --git a/pglablib/catalog/PgDatabase.h b/pglablib/catalog/PgDatabase.h index 3402bab..da6cd06 100644 --- a/pglablib/catalog/PgDatabase.h +++ b/pglablib/catalog/PgDatabase.h @@ -8,7 +8,6 @@ class PgDatabase: public PgServerObject { public: - Oid dba; // owner? int encoding; QString encodingString; QString collate; @@ -17,13 +16,15 @@ public: bool allowConn; int connLimit; Oid tablespace; - QString description; using PgServerObject::PgServerObject; bool isValid() const { return oid() != InvalidOid; } QString typeName() const override; + virtual QString aclAllPattern() const override; + virtual QString dropSql() const override; + virtual QString createSql() const override; }; #endif // PGDATABASE_H diff --git a/pglablib/catalog/PgDatabaseContainer.cpp b/pglablib/catalog/PgDatabaseContainer.cpp index 2ed07da..009f906 100644 --- a/pglablib/catalog/PgDatabaseContainer.cpp +++ b/pglablib/catalog/PgDatabaseContainer.cpp @@ -18,9 +18,10 @@ PgDatabase PgDatabaseContainer::loadElem(const Pgsql::Row &row) Oid oid = col.nextValue(); QString name = col.nextValue(); PgDatabase v(m_catalog, oid, name); - col >> v.dba >> v.encoding >> v.encodingString >> v.collate >> v.ctype >> v.isTemplate + Oid owner; + col >> owner >> v.encoding >> v.encodingString >> v.collate >> v.ctype >> v.isTemplate >> v.allowConn >> v.connLimit >> v.tablespace >> v.description; - + v.setOwnerOid(owner); AclList acl_list; col >> acl_list; v.setAcls(std::move(acl_list)); diff --git a/pglablib/catalog/PgServerObject.cpp b/pglablib/catalog/PgServerObject.cpp index 95c22fc..07f8284 100644 --- a/pglablib/catalog/PgServerObject.cpp +++ b/pglablib/catalog/PgServerObject.cpp @@ -94,10 +94,20 @@ QString PgServerObject::aclAllPattern() const QString PgServerObject::dropSql() const { - return {}; + return "DROP " % typeName() % " " % fullyQualifiedQuotedObjectName() % ";"; } QString PgServerObject::createSql() const { - return {}; + return {}; } + +QString PgServerObject::commentSql() const +{ + if (description.isEmpty()) + return {}; + + return "COMMENT ON " + typeName() + " " + fullyQualifiedQuotedObjectName() + + " IS " + escapeLiteral(description) + ";"; +} + diff --git a/pglablib/catalog/PgServerObject.h b/pglablib/catalog/PgServerObject.h index f20469c..1098745 100644 --- a/pglablib/catalog/PgServerObject.h +++ b/pglablib/catalog/PgServerObject.h @@ -13,7 +13,6 @@ class PgServerObject: public PgObject { public: using PgObject::PgObject; - void setOwnerOid(Oid oid); Oid ownerOid() const; bool hasOwner() const; @@ -21,6 +20,8 @@ public: const PgAuthId* owner() const; QString alterOwnerSql(const QString& ident) const; + QString description; + /** * @brief setAcls * @param acls Important: pass empty optional when acl IS NULL, pass empty list for empty array @@ -44,6 +45,7 @@ public: virtual QString dropSql() const; virtual QString createSql() const; + QString commentSql() const; private: Oid m_ownerOid = InvalidOid; const PgAuthId * m_owner;