Show SQL for database

Also improvements to the SQL for tables and views.
This commit is contained in:
eelke 2022-01-20 20:13:56 +01:00
parent b5a706a2a2
commit 3158a4364b
12 changed files with 172 additions and 58 deletions

View file

@ -142,10 +142,9 @@ QVariant DatabasesTableModel::getData(const QModelIndex &index) const
v = db.objectName(); v = db.objectName();
break; break;
case DbaCol: case DbaCol:
v = getRoleDisplayString(*m_catalog, db.dba); v = db.ownerName();
break; break;
case EncodingCol: case EncodingCol:
// todo lookup encoding name
v = db.encodingString; v = db.encodingString;
break; break;
case CollateCol: case CollateCol:
@ -164,7 +163,6 @@ QVariant DatabasesTableModel::getData(const QModelIndex &index) const
v = db.connLimit; v = db.connLimit;
break; break;
case TablespaceCol: case TablespaceCol:
// todo lookup tablespace name
v = getTablespaceDisplayString(*m_catalog, db.tablespace); v = getTablespaceDisplayString(*m_catalog, db.tablespace);
break; break;
case CommentCol: case CommentCol:

View file

@ -38,6 +38,10 @@ public:
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;
RowItem rowItem(int row) const
{
return databases.at(row).database;
}
protected: protected:
virtual QVariant getDataMeaning(const QModelIndex &index) const override; virtual QVariant getDataMeaning(const QModelIndex &index) const override;
private: private:

View file

@ -1,8 +1,11 @@
#include "DatabasesPage.h" #include "DatabasesPage.h"
#include "DatabasesTableModel.h" #include "DatabasesTableModel.h"
#include "SqlCodePreview.h"
#include "SqlFormattingUtils.h"
#include "catalog/PgDatabaseCatalog.h" #include "catalog/PgDatabaseCatalog.h"
#include "PgLabTableView.h" #include "PgLabTableView.h"
#include <QStringBuilder>
DatabasesPage::DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget * parent) DatabasesPage::DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget * parent)
@ -12,10 +15,18 @@ DatabasesPage::DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget
auto tv = m_databasesTableView.tableView(); auto tv = m_databasesTableView.tableView();
tv->setSelectionMode(QAbstractItemView::SingleSelection); tv->setSelectionMode(QAbstractItemView::SingleSelection);
m_detailsTabs = new QTabWidget(this); // m_detailsTabs = new QTabWidget(this);
addWidget(tv); 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<PgDatabaseCatalog> cat) void DatabasesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
@ -25,6 +36,34 @@ void DatabasesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
m_databasesTableView.tableView()->resizeColumnsToContents(); 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 &current, const QModelIndex &previous)
{
if (current.row() == previous.row())
return;
auto db = m_databasesTableView.rowItemForProxyIndex(current);
updateDatabaseDetails(db);
}

View file

@ -6,9 +6,11 @@
#include "PgLabTableViewHelper.h" #include "PgLabTableViewHelper.h"
#include "DatabasesTableModel.h" #include "DatabasesTableModel.h"
class PgDatabase;
class PgDatabaseCatalog; class PgDatabaseCatalog;
class PgLabTableView; class PgLabTableView;
class QSortFilterProxyModel; class QSortFilterProxyModel;
class SqlCodePreview;
class DatabasesPage: public QSplitter { class DatabasesPage: public QSplitter {
public: public:
@ -20,9 +22,16 @@ public:
private: private:
PgLabTableViewHelper<DatabasesTableModel> m_databasesTableView; PgLabTableViewHelper<DatabasesTableModel> m_databasesTableView;
QTabWidget *m_detailsTabs = nullptr; // QTabWidget *m_detailsTabs = nullptr;
SqlCodePreview *m_tableSql = nullptr;
std::shared_ptr<PgDatabaseCatalog> m_catalog; std::shared_ptr<PgDatabaseCatalog> m_catalog;
void updateDatabaseDetails(const PgDatabase &db);
void updateSqlTab(const PgDatabase &db);
private slots:
void databaseSelectionChanged(const QModelIndex &current, const QModelIndex &previous);
}; };

View file

@ -20,7 +20,7 @@
#include <QApplication> #include <QApplication>
#include <QHeaderView> #include <QHeaderView>
#include <QStringBuilder> #include <QStringBuilder>
#include <QSortFilterProxyModel> //#include <QSortFilterProxyModel>
#include <QTableWidget> #include <QTableWidget>
CatalogTablesPage::CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget *parent) CatalogTablesPage::CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget *parent)
@ -69,12 +69,6 @@ CatalogTablesPage::CatalogTablesPage(std::shared_ptr<OpenDatabase> opendatabase,
// Signals // Signals
connect(tv->selectionModel(), &QItemSelectionModel::currentRowChanged, this, connect(tv->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&CatalogTablesPage::tableListTable_currentRowChanged); &CatalogTablesPage::tableListTable_currentRowChanged);
// connect(m_tablesTableView.dataModel(), &TablesTableModel::modelReset,
// [this] ()
// {
// selectedTableChanged({});
// m_propertiesPage->setActiveRow({});
// });
connect(m_tablesTableView.dataModel(), &QAbstractItemModel::layoutChanged, connect(m_tablesTableView.dataModel(), &QAbstractItemModel::layoutChanged,
this, &CatalogTablesPage::tableListTable_layoutChanged); this, &CatalogTablesPage::tableListTable_layoutChanged);
@ -117,10 +111,11 @@ void CatalogTablesPage::setNamespaceFilter(NamespaceFilter filter)
void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous) void CatalogTablesPage::tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{ {
if (current.row() != previous.row()) { if (current.row() == previous.row())
return;
auto table = m_tablesTableView.rowItemForProxyIndex(current); auto table = m_tablesTableView.rowItemForProxyIndex(current);
selectedTableChanged(table); selectedTableChanged(table);
}
} }
@ -160,8 +155,9 @@ void CatalogTablesPage::updateSqlTab(const std::optional<PgClass> &table)
QString drop_sql; QString drop_sql;
QString create_sql; QString create_sql;
// create table // table
create_sql += table->createSql(); drop_sql += table->dropSql() % "\n";
create_sql += table->createSql() % "\n";
// - columns // - columns
// - constraints // - constraints
// table details (inherits etc) // table details (inherits etc)
@ -194,10 +190,7 @@ void CatalogTablesPage::updateSqlTab(const std::optional<PgClass> &table)
// Comments // Comments
create_sql += "-- set Comments table + columns\n"; create_sql += "-- set Comments table + columns\n";
if (!table->description.isEmpty()) { create_sql += table->commentSql() % "\n";
create_sql += "COMMENT ON TABLE " + table->fullyQualifiedQuotedObjectName()
+ " IS " + dollarQuoteString(table->description) + ";\n";
}
auto && cols = m_catalog->attributes()->getColumnsForRelation(table->oid()); auto && cols = m_catalog->attributes()->getColumnsForRelation(table->oid());
for (auto && col : cols) { for (auto && col : cols) {

View file

@ -13,7 +13,8 @@ void operator<<(RelPersistence &s, const Pgsql::Value &v)
{ {
//s = static_cast<T>(v); //s = static_cast<T>(v);
const char *c = v.c_str(); const char *c = v.c_str();
switch (*c) { switch (*c)
{
case 'p': case 'p':
s = RelPersistence::Permanent; s = RelPersistence::Permanent;
break; break;
@ -30,7 +31,8 @@ void operator<<(RelKind &s, const Pgsql::Value &v)
{ {
//s = static_cast<T>(v); //s = static_cast<T>(v);
const char *c = v.c_str(); const char *c = v.c_str();
switch (*c) { switch (*c)
{
case 'r': case 'r':
s = RelKind::Table; s = RelKind::Table;
break; break;
@ -58,26 +60,27 @@ void operator<<(RelKind &s, const Pgsql::Value &v)
} }
} }
//QString PgClass::objectName() const
//{
// return name;
//}
QString PgClass::createSql() const QString PgClass::createSql() const
{ {
if (createSqlCache.isEmpty()) { if (createSqlCache.isEmpty())
if (kind == RelKind::Table) {
switch (kind)
{
case RelKind::Table:
createSqlCache = createTableSql(); createSqlCache = createTableSql();
else if (kind == RelKind::View) break;
case RelKind::View:
createSqlCache = createViewSql(); createSqlCache = createViewSql();
break;
}
} }
return createSqlCache; return createSqlCache;
} }
QString PgClass::typeName() const QString PgClass::typeName() const
{ {
switch (kind) { switch (kind)
{
case RelKind::Table: return "TABLE"; case RelKind::Table: return "TABLE";
case RelKind::Index: return "INDEX"; case RelKind::Index: return "INDEX";
case RelKind::Sequence: return "SEQUENCE"; case RelKind::Sequence: return "SEQUENCE";
@ -92,7 +95,8 @@ QString PgClass::typeName() const
QString PgClass::aclAllPattern() const QString PgClass::aclAllPattern() const
{ {
switch (kind) { switch (kind)
{
case RelKind::Table: return "arwdDxt"; case RelKind::Table: return "arwdDxt";
default: default:
break; break;
@ -115,9 +119,12 @@ QString PgClass::createTableSql() const
auto && cols = catalog().attributes()->getColumnsForRelation(oid()); auto && cols = catalog().attributes()->getColumnsForRelation(oid());
bool first = true; bool first = true;
for (auto && col : cols) { for (auto && col : cols)
if (col.num > 0 && !col.isdropped) { {
if (first) { if (col.num > 0 && !col.isdropped)
{
if (first)
{
first = false; first = false;
} }
else sql += ",\n "; else sql += ",\n ";
@ -129,8 +136,10 @@ QString PgClass::createTableSql() const
// ] ) // ] )
} }
auto && constraints = catalog().constraints()->getConstraintsForRelation(oid()); auto && constraints = catalog().constraints()->getConstraintsForRelation(oid());
for (auto && constraint: constraints) { for (auto && constraint: constraints)
if (first) { {
if (first)
{
sql += "\n "; sql += "\n ";
first = false; first = false;
} }
@ -142,10 +151,12 @@ QString PgClass::createTableSql() const
{ {
// [ INHERITS ( parent_table [, ... ] ) ] // [ INHERITS ( parent_table [, ... ] ) ]
auto parents = catalog().inherits()->getParentsOf(oid()); auto parents = catalog().inherits()->getParentsOf(oid());
if (!parents.empty()) { if (!parents.empty())
{
sql += "\nINHERITS ("; sql += "\nINHERITS (";
bool first = true; bool first = true;
for (auto parent_oid : parents) { for (auto parent_oid : parents)
{
if (first) first = false; if (first) first = false;
else sql += ", "; else sql += ", ";
sql += catalog().classes()->getByKey(parent_oid)->fullyQualifiedQuotedObjectName(); sql += catalog().classes()->getByKey(parent_oid)->fullyQualifiedQuotedObjectName();
@ -156,7 +167,11 @@ QString PgClass::createTableSql() const
// [ PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ] // [ PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ]
// [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] // [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
// [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] // [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
// [ TABLESPACE tablespace_name ] if (tablespace != 0)
{
auto ns = getTablespaceDisplayString(catalog(), tablespace);
sql += "\n TABLESPACE " % quoteIdent(ns);
}
sql += ";\n"; sql += ";\n";
return sql; return sql;
} }

View file

@ -32,7 +32,6 @@ class PgClass: public PgNamespaceObject {
public: public:
Oid type = InvalidOid; Oid type = InvalidOid;
Oid oftype = InvalidOid; Oid oftype = InvalidOid;
//Oid owner = InvalidOid;
Oid am = InvalidOid; Oid am = InvalidOid;
Oid filenode = InvalidOid; Oid filenode = InvalidOid;
Oid tablespace = InvalidOid; Oid tablespace = InvalidOid;
@ -49,8 +48,6 @@ public:
std::vector<QString> options; std::vector<QString> options;
QString viewdef; QString viewdef;
QString description; // from pg_description
using PgNamespaceObject::PgNamespaceObject; using PgNamespaceObject::PgNamespaceObject;
QString kindString() const; QString kindString() const;

View file

@ -1,6 +1,51 @@
#include "PgDatabase.h" #include "PgDatabase.h"
#include "PgDatabaseCatalog.h"
#include "SqlFormattingUtils.h"
#include <QStringBuilder>
QString PgDatabase::typeName() const 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;
}

View file

@ -8,7 +8,6 @@
class PgDatabase: public PgServerObject { class PgDatabase: public PgServerObject {
public: public:
Oid dba; // owner?
int encoding; int encoding;
QString encodingString; QString encodingString;
QString collate; QString collate;
@ -17,13 +16,15 @@ public:
bool allowConn; bool allowConn;
int connLimit; int connLimit;
Oid tablespace; Oid tablespace;
QString description;
using PgServerObject::PgServerObject; using PgServerObject::PgServerObject;
bool isValid() const { return oid() != InvalidOid; } bool isValid() const { return oid() != InvalidOid; }
QString typeName() const override; QString typeName() const override;
virtual QString aclAllPattern() const override;
virtual QString dropSql() const override;
virtual QString createSql() const override;
}; };
#endif // PGDATABASE_H #endif // PGDATABASE_H

View file

@ -18,9 +18,10 @@ PgDatabase PgDatabaseContainer::loadElem(const Pgsql::Row &row)
Oid oid = col.nextValue(); Oid oid = col.nextValue();
QString name = col.nextValue(); QString name = col.nextValue();
PgDatabase v(m_catalog, oid, name); 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.allowConn >> v.connLimit >> v.tablespace >> v.description;
v.setOwnerOid(owner);
AclList acl_list; AclList acl_list;
col >> acl_list; col >> acl_list;
v.setAcls(std::move(acl_list)); v.setAcls(std::move(acl_list));

View file

@ -94,10 +94,20 @@ QString PgServerObject::aclAllPattern() const
QString PgServerObject::dropSql() const QString PgServerObject::dropSql() const
{ {
return {}; return "DROP " % typeName() % " " % fullyQualifiedQuotedObjectName() % ";";
} }
QString PgServerObject::createSql() const QString PgServerObject::createSql() const
{ {
return {}; return {};
} }
QString PgServerObject::commentSql() const
{
if (description.isEmpty())
return {};
return "COMMENT ON " + typeName() + " " + fullyQualifiedQuotedObjectName()
+ " IS " + escapeLiteral(description) + ";";
}

View file

@ -13,7 +13,6 @@ class PgServerObject: public PgObject {
public: public:
using PgObject::PgObject; using PgObject::PgObject;
void setOwnerOid(Oid oid); void setOwnerOid(Oid oid);
Oid ownerOid() const; Oid ownerOid() const;
bool hasOwner() const; bool hasOwner() const;
@ -21,6 +20,8 @@ public:
const PgAuthId* owner() const; const PgAuthId* owner() const;
QString alterOwnerSql(const QString& ident) const; QString alterOwnerSql(const QString& ident) const;
QString description;
/** /**
* @brief setAcls * @brief setAcls
* @param acls Important: pass empty optional when acl IS NULL, pass empty list for empty array * @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 dropSql() const;
virtual QString createSql() const; virtual QString createSql() const;
QString commentSql() const;
private: private:
Oid m_ownerOid = InvalidOid; Oid m_ownerOid = InvalidOid;
const PgAuthId * m_owner; const PgAuthId * m_owner;