Created IndexModel for displaying the indexes on a table. Constraints can now show the SQL to drop and create them.
The keyword list is now directly based of the official keyword list from postgresql.
This commit is contained in:
parent
b436814eb5
commit
97d4e2a1a4
24 changed files with 754 additions and 228 deletions
|
|
@ -69,9 +69,9 @@ QVariant ConstraintModel::headerData(int section, Qt::Orientation orientation, i
|
|||
case SupportingIndexCol:
|
||||
c = tr("Supporting index");
|
||||
break;
|
||||
case DefinitionCol:
|
||||
c = tr("Definition");
|
||||
break;
|
||||
// case DefinitionCol:
|
||||
// c = tr("Definition");
|
||||
// break;
|
||||
}
|
||||
v = c;
|
||||
}
|
||||
|
|
@ -158,11 +158,16 @@ QVariant ConstraintModel::getData(const QModelIndex &index) const
|
|||
case SupportingIndexCol:
|
||||
s = getIndexDisplayString(*m_catalog, t.indid);
|
||||
break;
|
||||
case DefinitionCol:
|
||||
s = t.definition;
|
||||
break;
|
||||
// case DefinitionCol:
|
||||
// s = t.definition;
|
||||
// break;
|
||||
}
|
||||
v = s;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
const PgConstraint& ConstraintModel::constraint(int row)
|
||||
{
|
||||
return m_constraints[row];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public:
|
|||
NameCol, ///
|
||||
NsCol, ///
|
||||
SupportingIndexCol,
|
||||
DefinitionCol,
|
||||
// DefinitionCol,
|
||||
colCount };
|
||||
|
||||
explicit ConstraintModel(QObject *parent = nullptr);
|
||||
|
|
@ -35,6 +35,7 @@ public:
|
|||
|
||||
//QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
const PgConstraint& constraint(int row);
|
||||
protected:
|
||||
|
||||
virtual Oid getType(int column) const override;
|
||||
|
|
|
|||
85
pglab/IndexModel.cpp
Normal file
85
pglab/IndexModel.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#include "IndexModel.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "PgIndexContainer.h"
|
||||
#include "Pgsql_oids.h"
|
||||
#include "ScopeGuard.h"
|
||||
|
||||
void IndexModel::setData(std::shared_ptr<const PgDatabaseCatalog> cat, const PgClass &table)
|
||||
{
|
||||
beginResetModel();
|
||||
SCOPE_EXIT { endResetModel(); };
|
||||
|
||||
m_catalog = cat;
|
||||
m_table = table;
|
||||
|
||||
m_indexes = cat->indexes()->getIndexesForTable(table.oid);
|
||||
}
|
||||
|
||||
int IndexModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return m_indexes.size();
|
||||
}
|
||||
|
||||
int IndexModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return colCount;
|
||||
}
|
||||
|
||||
Oid IndexModel::getType(int column) const
|
||||
{
|
||||
return Pgsql::varchar_oid;
|
||||
}
|
||||
|
||||
QVariant IndexModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
QVariant v;
|
||||
if (orientation == Qt::Horizontal) {
|
||||
if (role == Qt::DisplayRole) {
|
||||
QString c;
|
||||
switch (section) {
|
||||
case TypeCol:
|
||||
c = tr("Type");
|
||||
break;
|
||||
case NameCol:
|
||||
c = tr("Name");
|
||||
break;
|
||||
case ColumnsCol:
|
||||
c = tr("On");
|
||||
break;
|
||||
case ConditionCol:
|
||||
c = tr("Condition");
|
||||
break;
|
||||
// case DefinitionCol:
|
||||
// c = tr("Definition");
|
||||
// break;
|
||||
}
|
||||
v = c;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
QVariant IndexModel::getData(const QModelIndex &index) const
|
||||
{
|
||||
QVariant v;
|
||||
int rij = index.row();
|
||||
const auto &dat = m_indexes[rij];
|
||||
switch (index.column()) {
|
||||
case TypeCol:
|
||||
if (dat.isprimary) v = ":/icons/constraints/primarykey.png";
|
||||
else if (dat.isunique) v = ":/icons/constraints/unique.png";
|
||||
break;
|
||||
|
||||
case NameCol:
|
||||
v = getIndexDisplayString(*m_catalog, dat.indexrelid);
|
||||
break;
|
||||
|
||||
case ColumnsCol:
|
||||
break;
|
||||
|
||||
case ConditionCol:
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
45
pglab/IndexModel.h
Normal file
45
pglab/IndexModel.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef INDEXMODEL_H
|
||||
#define INDEXMODEL_H
|
||||
|
||||
#include "BaseTableModel.h"
|
||||
#include "PgClass.h"
|
||||
#include "PgIndex.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class IndexModel: public BaseTableModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using BaseTableModel::BaseTableModel;
|
||||
|
||||
enum e_Columns : int {
|
||||
TypeCol, /// primary/unique/normal
|
||||
NameCol, ///
|
||||
ColumnsCol, ///
|
||||
ConditionCol,
|
||||
colCount };
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
void setData(std::shared_ptr<const PgDatabaseCatalog> cat, const PgClass &table);
|
||||
|
||||
|
||||
// Basic functionality:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
protected:
|
||||
virtual Oid getType(int column) const override;
|
||||
virtual QVariant getData(const QModelIndex &index) const override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
|
||||
PgClass m_table;
|
||||
|
||||
using t_Indexes = std::vector<PgIndex>;
|
||||
t_Indexes m_indexes;
|
||||
};
|
||||
|
||||
#endif // INDEXMODEL_H
|
||||
|
|
@ -3,104 +3,6 @@
|
|||
#include "PgTypeContainer.h"
|
||||
#include "SqlLexer.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
t_SymbolSet g_Keywords = {
|
||||
"a", "abort", "abs", "absent", "absolute", "access", "according", "action", "ada", "add",
|
||||
"admin", "after", "aggregate", "all", "allocate", "also", "alter", "analyse", "analyze", "and",
|
||||
"any", "are", "array", "array_agg", "array_max_cardinality", "as", "asc", "asensitive",
|
||||
"assetion", "assignment", "asymmetric", "at", "atomic", "attribute", "attributes", "authorization", "avg",
|
||||
"backward", "base64", "before", "begin", "begin_frame", "begin_partition", "bernoulli", "between", "bigint", "binary",
|
||||
"bit", "bit_length", "blob", "blocked", "bom", "boolean", "both", "breadth", "buffer", "by",
|
||||
"c", "cache", "call", "called", "cardinality", "cascade", "cascaded", "case", "cast",
|
||||
"catalog", "catalog_name", "ceil", "ceiling", "chain", "char", "character", "characteristics",
|
||||
"characters", "character_length", "character_set_catalog", "character_set_name", "character_set_schema",
|
||||
"char_length", "check", "checkpoint", "class", "class_origin", "clob", "close", "cluster",
|
||||
"coalesce", "cobol", "collate", "collation", "collation_catalog", "collation_name", "collation_schema",
|
||||
"collect", "column", "columns", "column_name", "command_function", "command_function_code",
|
||||
"comment", "comments", "commit", "committed", "concurrently", "condition", "condition_number",
|
||||
"configuration", "conflict", "connect", "connection", "connection_name", "constraint", "constraints",
|
||||
"constraint_catalog", "constraint_name", "constraint_schema", "constructor", "contains", "content",
|
||||
"continue", "control", "conversion", "convert", "copy", "corr", "corresponding", "cost", "count",
|
||||
"covar_pop", "covar_samp", "create", "cross", "csv", "cube", "cume_dist", "current", "current_catalog",
|
||||
"current_date", "current_default_transform_group", "current_path", "current_role", "current_row",
|
||||
"current_schema", "current_time", "current_timestamp", "current_transform_group_for_type",
|
||||
"current_user", "cursor", "cursor_name", "cycle",
|
||||
"data", "database", "datalink", "date", "datetime_interval_code", "datetime_interval_precision",
|
||||
"day", "db", "deallocate", "dec", "decimal", "declare", "default", "defaults", "deferrable", "deferred",
|
||||
"defined", "definer", "degree", "delete", "delimiter", "delimiters", "dense_rank", "depends", "depth",
|
||||
"deref", "derived", "desc", "describe", "descriptor", "deterministic", "diagnostics", "dictionary",
|
||||
"disable", "discard", "disconnect", "dispatch", "distinct", "dlnewcopy", "dlpreviouscopy", "dlurlcomplete",
|
||||
"dlurlcompleteonly", "dlurlcompletewrite", "dlurlpatch", "dlurlpathonly", "dlurlpathwrite", "dlurlscheme",
|
||||
"dlurlserver", "dlvalue", "do", "document", "domain", "double", "drop", "dynamic", "dynamic_function",
|
||||
"dynamic_function_code",
|
||||
"each", "element", "else", "empty", "enable", "encodign", "encrypted", "end", "end-exec", "end_frame",
|
||||
"end_partition", "enforced", "enum", "equals", "escape", "event", "every", "except", "exception", "exclude",
|
||||
"excluding", "exclusive", "exec", "execute", "exists", "exp", "explain", "expression", "extenstion",
|
||||
"external", "extract", "false", "family", "fetch", "file", "filter", "final", "first", "first_value",
|
||||
"flag", "float", "floor", "following", "for", "force", "foreign", "fortran", "forward", "found",
|
||||
"frame_row", "free", "freeze", "from", "fs", "full", "function", "functions", "fusion",
|
||||
"g", "general", "generated", "get", "global", "go" "goto", "grant", "granted", "greatest", "group",
|
||||
"grouping", "groups", "handler", "having", "header", "hex", "hierarchy", "hold", "hour", "id", "identity",
|
||||
"if", "ignore", "ilike", "immediate", "immediatly", "immutable", "implementation", "implicit", "import", "in",
|
||||
"including", "increment", "indent", "index", "indexes", "indicator", "inherit", "inherits", "initially", "inline",
|
||||
"inner", "inout", "input", "insensitive", "insert", "instance", "instantiable", "instead", "int", "integer",
|
||||
"integrity", "intersect", "intersection", "interval", "into", "invoker", "is", "isnull", "isolation",
|
||||
"join",
|
||||
"k", "key", "key_member", "key_type",
|
||||
"label", "lag", "language", "large", "last", "last_value", "lateral", "lead", "leading", "leakproof",
|
||||
"least", "left", "length", "level", "library", "like", "like_regex", "limit", "link", "listen", "ln", "load", "local",
|
||||
"localtime", "localtimestamp", "location", "locator", "lock", "locked", "logged", "lower",
|
||||
"m", "map", "mapping", "match", "matched", "materialized", "max", "maxvalue", "max_cardinality", "member",
|
||||
"merge", "message_length", "message_octet_length", "message_text", "method", "min", "minute", "minvalue",
|
||||
"mod", "mode", "modifies", "module", "month", "more", "move", "multiset", "mumps",
|
||||
"name", "namespace", "national", "natural", "nchar", "nclob", "nesting", "new", "next", "nfc", "nfd", "nfkc", "nkfd",
|
||||
"nil", "no", "none", "normalize", "normalize", "not", "nothing", "notify", "notnull", "nowait", "nth_value", "ntile",
|
||||
"null", "nullable", "nullif", "nulls", "number", "numeric",
|
||||
"object", "occurrences_regex", "octets", "octet_length", "of", "off", "offset", "oids", "old", "on", "only", "open",
|
||||
"operator", "option", "options", "or", "order", "ordering", "ordinality", "others", "out", "outer", "output", "over",
|
||||
"overlaps", "overlay", "overriding", "owned", "owner",
|
||||
"p", "pad", "parallel", "parameter", "parameter_mode", "parameter_name", "parameter_specific_catalog",
|
||||
"parameter_specific_name", "parameter_specific_schema", "parser",
|
||||
"partial", "partition", "pascal", "passing", "passthrough", "password", "path", "percent", "percentile_cont",
|
||||
"percentile_disc", "percent_rank", "period", "permission", "placing", "plans", "pli", "policy", "portion",
|
||||
"position", "position_regex", "power", "precedes", "preceding", "precision", "prepare", "prepared", "preserve",
|
||||
"primary", "prior", "privileges", "procedural", "procedure", "program", "public",
|
||||
"quote", "range", "rank", "read", "reads", "real", "reassign", "recheck", "recovery", "recursive", "ref",
|
||||
"references", "referencing", "refresh", "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", "regr_r2",
|
||||
"regr_slope", "regr_sxx", "regr_sxy", "regr_syy", "reindex", "relative", "release", "rename", "repeatable",
|
||||
"replace", "replica", "requiring", "reset", "respect", "restart", "restore", "restrict", "result", "return",
|
||||
"returned_cardinality", "returned_length", "returned_octet_length", "returned_sqlstate", "returning", "returns",
|
||||
"revoke", "right", "role", "rollback", "rollup", "routine", "routine_catalog", "routine_name", "routine_schema",
|
||||
"row", "rows", "row_count", "row_number", "rule",
|
||||
"savepoint", "scale", "schema", "schema_name", "scope", "scope_catalog", "scope_name", "scope_schema", "scroll",
|
||||
"search", "second", "section", "security", "select", "selective", "self", "sensitive", "sequence", "sequences",
|
||||
"serializable", "server", "server_name", "session", "session_user", "set", "setof", "sets", "share", "show",
|
||||
"similar", "simple", "size", "skip", "smallint", "snapshot", "some", "source", "space", "specific", "specifictype",
|
||||
"specific_name", "sql", "sqlcode", "sqlerror", "sqlexception", "sqlstate", "sqlwarning", "sqrt", "stable",
|
||||
"standalone", "start", "state", "statement", "static", "statistics", "stddev_pop", "stddev_samp", "stdin", "stdout",
|
||||
"storage", "strict", "strip", "structure", "style", "subclass_origin", "submultiset", "substring", "substring_regex",
|
||||
"succeeds", "sum", "symmetric", "sysid", "system", "system_time", "system_user",
|
||||
"t", "table", "tables", "tablesample", "tablespace", "table_name", "temp", "template", "temporary", "text", "then",
|
||||
"ties", "time", "timestamp", "timezone_hour", "timezone_minute", "to", "token", "top_level_count", "trailing",
|
||||
"transaction", "transaction_committed", "transaction_rolled_back", "transaction_active", "transform", "transforms",
|
||||
"translate", "translate_regex", "translation", "treat", "trigger", "trigger_catalog", "trigger_name", "trigger_schema",
|
||||
"trim", "trim_array", "true", "truncate", "trusted", "type", "types", "uescape", "unbounded", "uncommitted", "under",
|
||||
"unencrypted", "union", "unique", "unknown", "unlink", "unlisten", "unlogged", "unnamed", "unnest", "until", "untyped",
|
||||
"update", "upper", "uri", "usage", "user", "user_defined_type_catalog", "user_defined_type_code",
|
||||
"user_defined_type_name", "user_defined_type_schema", "using",
|
||||
"vacuum", "valid", "validate", "validator", "value", "values", "value_of", "varbinary", "varchar", "variadic",
|
||||
"varying", "var_pop", "var_samp", "verbose", "version", "versioning", "view", "views", "volatile",
|
||||
"when", "whenever", "where", "whitespace", "width_bucket", "window", "with", "within", "without", "work", "wrapper",
|
||||
"write", "xml", "xmlagg", "xmlattributes", "xmlbinary", "xmlcast", "xmlcomment", "xmlconcat", "xmldeclaration",
|
||||
"xmldocument", "xmlelement", "xmlexists", "xmlforest", "xmliterate", "xmlnamespaces", "xmlparse", "xmlpi",
|
||||
"xmlquery", "xmlroot", "xmlschema", "xmlserialize", "xmltable", "xmltext", "xmlvalidate", "year", "yes", "zone"
|
||||
};
|
||||
|
||||
//"bigint",
|
||||
|
||||
}
|
||||
|
||||
|
||||
SqlSyntaxHighlighter::SqlSyntaxHighlighter(QTextDocument *parent)
|
||||
|
|
@ -149,12 +51,14 @@ void SqlSyntaxHighlighter::highlightBlock(const QString &text)
|
|||
case BasicTokenType::End: // End of input
|
||||
case BasicTokenType::DollarQuote:
|
||||
break;
|
||||
case BasicTokenType::Symbol: // can be many things, keyword, object name, operator, ..
|
||||
if (g_Keywords.count(s.toLower()) > 0) {
|
||||
setFormat(startpos, length, m_keywordFormat);
|
||||
}
|
||||
else if (m_typeNames.count(s.toLower()) > 0) {
|
||||
setFormat(startpos, length, m_typeFormat);
|
||||
case BasicTokenType::Symbol: { // can be many things, keyword, object name, operator, ..
|
||||
auto kw = getPgsqlKeyword(s);
|
||||
if (kw != nullptr) {
|
||||
setFormat(startpos, length, m_keywordFormat);
|
||||
}
|
||||
else if (m_typeNames.count(s.toLower()) > 0) {
|
||||
setFormat(startpos, length, m_typeFormat);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BasicTokenType::OpenBlockComment:
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@
|
|||
|
||||
#include <QSyntaxHighlighter>
|
||||
#include <QTextFormat>
|
||||
#include <unordered_set>
|
||||
#include "PgKeywordList.h"
|
||||
#include "util.h"
|
||||
|
||||
using t_SymbolSet = std::unordered_set<QString>;
|
||||
|
||||
class PgTypeContainer;
|
||||
|
||||
class SqlSyntaxHighlighter : public QSyntaxHighlighter
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@
|
|||
#include "ConstraintModel.h"
|
||||
#include "NamespaceFilterWidget.h"
|
||||
#include "IconColumnDelegate.h"
|
||||
#include "IndexModel.h"
|
||||
#include "SqlFormattingUtils.h"
|
||||
#include "SqlSyntaxHighlighter.h"
|
||||
#include <QStringBuilder>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
TablesPage::TablesPage(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
|
|
@ -27,16 +32,32 @@ TablesPage::TablesPage(QWidget *parent) :
|
|||
SetTableViewDefault(ui->constraintsTable);
|
||||
m_constraintModel = new ConstraintModel(this);
|
||||
auto delegate = new IconColumnDelegate(this);
|
||||
|
||||
ui->constraintsTable->setModel(m_constraintModel);
|
||||
ui->constraintsTable->setItemDelegateForColumn(0, delegate);
|
||||
|
||||
QFont font;
|
||||
font.setFamily("Source Code Pro");
|
||||
font.setFixedPitch(true);
|
||||
font.setPointSize(10);
|
||||
ui->constraintSqlEdit->setFont(font);
|
||||
|
||||
SetTableViewDefault(ui->indexesTable);
|
||||
m_indexModel = new IndexModel(this);
|
||||
ui->indexesTable->setModel(m_indexModel);
|
||||
ui->indexesTable->setItemDelegateForColumn(0, delegate);
|
||||
|
||||
m_namespaceFilterWidget = new NamespaceFilterWidget(this);
|
||||
ui->verticalLayoutTableView->addWidget(m_namespaceFilterWidget);
|
||||
|
||||
|
||||
connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
|
||||
&TablesPage::on_tableListTable_currentRowChanged);
|
||||
&TablesPage::on_tableListTable_currentRowChanged);
|
||||
|
||||
// connect(ui->constraintsTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
|
||||
// &TablesPage::on_constraintsTable_currentRowChanged);
|
||||
|
||||
connect(ui->constraintsTable->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||
&TablesPage::on_constraintsTable_selectionChanged);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +72,10 @@ void TablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
|||
m_tablesModel->setCatalog(cat);
|
||||
ui->tableListTable->resizeColumnsToContents();
|
||||
m_namespaceFilterWidget->init(cat->namespaces());
|
||||
|
||||
auto highlighter = new SqlSyntaxHighlighter(ui->constraintSqlEdit->document());
|
||||
highlighter->setTypes(*cat->types());
|
||||
|
||||
}
|
||||
|
||||
void TablesPage::on_tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
|
|
@ -62,5 +87,37 @@ void TablesPage::on_tableListTable_currentRowChanged(const QModelIndex ¤t,
|
|||
|
||||
m_constraintModel->setData(m_catalog, table);
|
||||
ui->constraintsTable->resizeColumnsToContents();
|
||||
ui->constraintsTable->selectionModel()->reset();
|
||||
|
||||
m_indexModel->setData(m_catalog, table);
|
||||
ui->indexesTable->resizeColumnsToContents();
|
||||
}
|
||||
}
|
||||
|
||||
void TablesPage::on_constraintsTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if (current.row() != previous.row()) {
|
||||
// QString drop_definition = m_constraintModel->dropDefinition(current.row());
|
||||
// QString create_definition = m_constraintModel->createDefinition(current.row());
|
||||
const PgConstraint& constraint = m_constraintModel->constraint(current.row());
|
||||
QString drop = getDropConstraintDefinition(*m_catalog, constraint);
|
||||
QString add = getConstraintDefinition(*m_catalog, constraint);
|
||||
|
||||
ui->constraintSqlEdit->setPlainText(drop % QString::fromUtf16(u"\n") % add);
|
||||
}
|
||||
}
|
||||
|
||||
void TablesPage::on_constraintsTable_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
|
||||
{
|
||||
const auto indexes = ui->constraintsTable->selectionModel()->selectedIndexes();
|
||||
boost::container::flat_set<int> rijen;
|
||||
for (const auto e : indexes) rijen.insert(e.row());
|
||||
QString drops;
|
||||
QString creates;
|
||||
for (auto rij : rijen) {
|
||||
const PgConstraint constraint = m_constraintModel->constraint(rij);
|
||||
drops += getDropConstraintDefinition(*m_catalog, constraint) % "\n";
|
||||
creates += getConstraintDefinition(*m_catalog, constraint) % "\n";
|
||||
}
|
||||
ui->constraintSqlEdit->setPlainText(drops % "\n" % creates);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QWidget>
|
||||
#include <memory>
|
||||
#include <QItemSelection>
|
||||
|
||||
namespace Ui {
|
||||
class TablesPage;
|
||||
|
|
@ -13,6 +14,7 @@ class ColumnTableModel;
|
|||
class ConstraintModel;
|
||||
class PgDatabaseCatalog;
|
||||
class NamespaceFilterWidget;
|
||||
class IndexModel;
|
||||
|
||||
class TablesPage : public QWidget
|
||||
{
|
||||
|
|
@ -29,11 +31,14 @@ private:
|
|||
TablesTableModel* m_tablesModel = nullptr;
|
||||
ColumnTableModel* m_columnsModel = nullptr;
|
||||
ConstraintModel* m_constraintModel = nullptr;
|
||||
IndexModel* m_indexModel = nullptr;
|
||||
NamespaceFilterWidget* m_namespaceFilterWidget;
|
||||
|
||||
private slots:
|
||||
|
||||
void on_tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void on_constraintsTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void on_constraintsTable_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
};
|
||||
|
||||
#endif // TABLESPAGE_H
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
</widget>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="columnsTab">
|
||||
<attribute name="title">
|
||||
|
|
@ -56,7 +56,17 @@
|
|||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTableView" name="constraintsTable"/>
|
||||
<widget class="QSplitter" name="splitter_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QTableView" name="constraintsTable">
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPlainTextEdit" name="constraintSqlEdit"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation,
|
|||
case OptionsCol:
|
||||
v = tr("Options");
|
||||
break;
|
||||
case AclCol:
|
||||
v = tr("ACL");
|
||||
break;
|
||||
// case AclCol:
|
||||
// v = tr("ACL");
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ Oid TablesTableModel::getType(int column) const
|
|||
case NameCol:
|
||||
case NamespaceCol:
|
||||
case OptionsCol:
|
||||
case AclCol:
|
||||
// case AclCol:
|
||||
default:
|
||||
oid = Pgsql::VARCHAROID;
|
||||
}
|
||||
|
|
@ -115,9 +115,9 @@ QVariant TablesTableModel::getData(const QModelIndex &index) const
|
|||
case OptionsCol:
|
||||
v = t.options;
|
||||
break;
|
||||
case AclCol:
|
||||
v = t.acl;
|
||||
break;
|
||||
// case AclCol:
|
||||
// v = t.acl;
|
||||
// break;
|
||||
}
|
||||
|
||||
return v;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public:
|
|||
OwnerCol,
|
||||
TablespaceCol,
|
||||
OptionsCol,
|
||||
AclCol,
|
||||
//AclCol,
|
||||
colCount };
|
||||
|
||||
TablesTableModel(QObject *parent);
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ SOURCES += main.cpp\
|
|||
NamespaceItemModel.cpp \
|
||||
ApplicationWindow.cpp \
|
||||
ConstraintModel.cpp \
|
||||
IconColumnDelegate.cpp
|
||||
IconColumnDelegate.cpp \
|
||||
IndexModel.cpp
|
||||
|
||||
HEADERS += \
|
||||
QueryResultModel.h \
|
||||
|
|
@ -102,7 +103,8 @@ HEADERS += \
|
|||
NamespaceItemModel.h \
|
||||
ApplicationWindow.h \
|
||||
ConstraintModel.h \
|
||||
IconColumnDelegate.h
|
||||
IconColumnDelegate.h \
|
||||
IndexModel.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
ConnectionManagerWindow.ui \
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ SUBDIRS += core \
|
|||
pglab.depends = core ctk pgsql pglablib
|
||||
pgsql.depends = core
|
||||
pglablib.depends = core pgsql
|
||||
tests.depends = core pgsql pglablib
|
||||
|
||||
|
||||
CONFIG(debug, debug|release) {
|
||||
|
|
|
|||
10
pglablib/PgCatalogTypes.h
Normal file
10
pglablib/PgCatalogTypes.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef PGCATALOGTYPES_H
|
||||
#define PGCATALOGTYPES_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <vector>
|
||||
|
||||
using AttNumVec = std::vector<int16_t>;
|
||||
using OidVec = std::vector<Oid>;
|
||||
|
||||
#endif // PGCATALOGTYPES_H
|
||||
|
|
@ -105,6 +105,30 @@ void operator<<(ForeignKeyAction &s, const Pgsql::Value &v)
|
|||
}
|
||||
}
|
||||
|
||||
QString ForeignKeyActionToString(ForeignKeyAction fka)
|
||||
{
|
||||
QString result;
|
||||
switch (fka) {
|
||||
case ForeignKeyAction::NoAction:
|
||||
result = "NO ACTION";
|
||||
break;
|
||||
case ForeignKeyAction::Restrict:
|
||||
result = "RESTRICT";
|
||||
break;
|
||||
case ForeignKeyAction::Cascade:
|
||||
result = "CASCADE";
|
||||
break;
|
||||
case ForeignKeyAction::SetNull:
|
||||
result = "SET NULL";
|
||||
break;
|
||||
case ForeignKeyAction::SetDefault:
|
||||
result = "SET DEFAULT";
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void operator<<(ForeignKeyMatch &s, const Pgsql::Value &v)
|
||||
{
|
||||
const char *c = v.c_str();
|
||||
|
|
@ -121,6 +145,22 @@ void operator<<(ForeignKeyMatch &s, const Pgsql::Value &v)
|
|||
}
|
||||
}
|
||||
|
||||
QString ForeignKeyMatchToString(ForeignKeyMatch fkm)
|
||||
{
|
||||
QString result;
|
||||
switch (fkm) {
|
||||
case ForeignKeyMatch::Full :
|
||||
result = "FULL";
|
||||
break;
|
||||
case ForeignKeyMatch::Partial:
|
||||
result = "PARTIAL";
|
||||
break;
|
||||
case ForeignKeyMatch::Simple:
|
||||
result = "SIMPLE";
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
PgConstraint::PgConstraint()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define PGCONSTRAINT_H
|
||||
|
||||
#include "Pgsql_Value.h"
|
||||
#include "PgCatalogTypes.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
|
|
@ -33,6 +34,8 @@ enum class ForeignKeyAction {
|
|||
|
||||
void operator<<(ForeignKeyAction &s, const Pgsql::Value &v);
|
||||
|
||||
QString ForeignKeyActionToString(ForeignKeyAction fka);
|
||||
|
||||
enum class ForeignKeyMatch {
|
||||
Full, // f
|
||||
Partial, // p
|
||||
|
|
@ -41,6 +44,8 @@ enum class ForeignKeyMatch {
|
|||
|
||||
void operator<<(ForeignKeyMatch &s, const Pgsql::Value &v);
|
||||
|
||||
QString ForeignKeyMatchToString(ForeignKeyMatch fkm);
|
||||
|
||||
class PgConstraint {
|
||||
public:
|
||||
Oid oid = InvalidOid;
|
||||
|
|
@ -60,12 +65,12 @@ public:
|
|||
bool islocal;
|
||||
int32_t inhcount;
|
||||
bool noinherit;
|
||||
std::vector<int16_t> key; // list of constraint columns attnum
|
||||
std::vector<int16_t> fkey; // fkey list of referenced columns
|
||||
std::vector<Oid> pfeqop;
|
||||
std::vector<Oid> ppeqop;
|
||||
std::vector<Oid> ffeqop;
|
||||
std::vector<Oid> exclop;
|
||||
AttNumVec key; // list of constraint columns attnum
|
||||
AttNumVec fkey; // fkey list of referenced columns
|
||||
OidVec pfeqop;
|
||||
OidVec ppeqop;
|
||||
OidVec ffeqop;
|
||||
OidVec exclop;
|
||||
QString bin;
|
||||
QString src;
|
||||
|
||||
|
|
@ -78,4 +83,5 @@ public:
|
|||
bool operator<(const PgConstraint &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
|
||||
#endif // PGCONSTRAINT_H
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
#include "Pgsql_oids.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <boost/timer/timer.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
|
||||
using namespace Pgsql;
|
||||
|
||||
|
|
@ -164,8 +166,10 @@ void load(Pgsql::Connection &conn, IPgContainter &pg_cont)
|
|||
//QThread::msleep(400);
|
||||
std::string q = pg_cont.getLoadQuery();
|
||||
Pgsql::Result result = conn.query(q.c_str());
|
||||
if (result && result.resultStatus() == PGRES_TUPLES_OK)
|
||||
if (result && result.resultStatus() == PGRES_TUPLES_OK) {
|
||||
boost::timer::auto_cpu_timer t;
|
||||
pg_cont.load(result);
|
||||
}
|
||||
else {
|
||||
auto details = result.diagDetails();
|
||||
|
||||
|
|
|
|||
116
pglablib/PgKeywordList.cpp
Normal file
116
pglablib/PgKeywordList.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "PgKeywordList.h"
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
using KeywordHT = boost::container::flat_set<Keyword>;
|
||||
|
||||
#define PG_KEYWORD(a,b,c) {a,c},
|
||||
const KeywordHT _ScanKeywords = {
|
||||
#include <server/parser/kwlist.h>
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const Keyword* getPgsqlKeyword(QString s)
|
||||
{
|
||||
const Keyword *result = nullptr;
|
||||
auto fr = _ScanKeywords.find(Keyword(s.toLower(), 0));
|
||||
if (fr != _ScanKeywords.end())
|
||||
result = &*fr;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//t_SymbolSet g_Keywords = {
|
||||
// "a", "abort", "abs", "absent", "absolute", "access", "according", "action", "ada", "add",
|
||||
// "admin", "after", "aggregate", "all", "allocate", "also", "alter", "analyse", "analyze", "and",
|
||||
// "any", "are", "array", "array_agg", "array_max_cardinality", "as", "asc", "asensitive",
|
||||
// "assetion", "assignment", "asymmetric", "at", "atomic", "attribute", "attributes", "authorization", "avg",
|
||||
// "backward", "base64", "before", "begin", "begin_frame", "begin_partition", "bernoulli", "between", "bigint", "binary",
|
||||
// "bit", "bit_length", "blob", "blocked", "bom", "boolean", "both", "breadth", "buffer", "by",
|
||||
// "c", "cache", "call", "called", "cardinality", "cascade", "cascaded", "case", "cast",
|
||||
// "catalog", "catalog_name", "ceil", "ceiling", "chain", "char", "character", "characteristics",
|
||||
// "characters", "character_length", "character_set_catalog", "character_set_name", "character_set_schema",
|
||||
// "char_length", "check", "checkpoint", "class", "class_origin", "clob", "close", "cluster",
|
||||
// "coalesce", "cobol", "collate", "collation", "collation_catalog", "collation_name", "collation_schema",
|
||||
// "collect", "column", "columns", "column_name", "command_function", "command_function_code",
|
||||
// "comment", "comments", "commit", "committed", "concurrently", "condition", "condition_number",
|
||||
// "configuration", "conflict", "connect", "connection", "connection_name", "constraint", "constraints",
|
||||
// "constraint_catalog", "constraint_name", "constraint_schema", "constructor", "contains", "content",
|
||||
// "continue", "control", "conversion", "convert", "copy", "corr", "corresponding", "cost", "count",
|
||||
// "covar_pop", "covar_samp", "create", "cross", "csv", "cube", "cume_dist", "current", "current_catalog",
|
||||
// "current_date", "current_default_transform_group", "current_path", "current_role", "current_row",
|
||||
// "current_schema", "current_time", "current_timestamp", "current_transform_group_for_type",
|
||||
// "current_user", "cursor", "cursor_name", "cycle",
|
||||
// "data", "database", "datalink", "date", "datetime_interval_code", "datetime_interval_precision",
|
||||
// "day", "db", "deallocate", "dec", "decimal", "declare", "default", "defaults", "deferrable", "deferred",
|
||||
// "defined", "definer", "degree", "delete", "delimiter", "delimiters", "dense_rank", "depends", "depth",
|
||||
// "deref", "derived", "desc", "describe", "descriptor", "deterministic", "diagnostics", "dictionary",
|
||||
// "disable", "discard", "disconnect", "dispatch", "distinct", "dlnewcopy", "dlpreviouscopy", "dlurlcomplete",
|
||||
// "dlurlcompleteonly", "dlurlcompletewrite", "dlurlpatch", "dlurlpathonly", "dlurlpathwrite", "dlurlscheme",
|
||||
// "dlurlserver", "dlvalue", "do", "document", "domain", "double", "drop", "dynamic", "dynamic_function",
|
||||
// "dynamic_function_code",
|
||||
// "each", "element", "else", "empty", "enable", "encodign", "encrypted", "end", "end-exec", "end_frame",
|
||||
// "end_partition", "enforced", "enum", "equals", "escape", "event", "every", "except", "exception", "exclude",
|
||||
// "excluding", "exclusive", "exec", "execute", "exists", "exp", "explain", "expression", "extenstion",
|
||||
// "external", "extract", "false", "family", "fetch", "file", "filter", "final", "first", "first_value",
|
||||
// "flag", "float", "floor", "following", "for", "force", "foreign", "fortran", "forward", "found",
|
||||
// "frame_row", "free", "freeze", "from", "fs", "full", "function", "functions", "fusion",
|
||||
// "g", "general", "generated", "get", "global", "go" "goto", "grant", "granted", "greatest", "group",
|
||||
// "grouping", "groups", "handler", "having", "header", "hex", "hierarchy", "hold", "hour", "id", "identity",
|
||||
// "if", "ignore", "ilike", "immediate", "immediatly", "immutable", "implementation", "implicit", "import", "in",
|
||||
// "including", "increment", "indent", "index", "indexes", "indicator", "inherit", "inherits", "initially", "inline",
|
||||
// "inner", "inout", "input", "insensitive", "insert", "instance", "instantiable", "instead", "int", "integer",
|
||||
// "integrity", "intersect", "intersection", "interval", "into", "invoker", "is", "isnull", "isolation",
|
||||
// "join",
|
||||
// "k", "key", "key_member", "key_type",
|
||||
// "label", "lag", "language", "large", "last", "last_value", "lateral", "lead", "leading", "leakproof",
|
||||
// "least", "left", "length", "level", "library", "like", "like_regex", "limit", "link", "listen", "ln", "load", "local",
|
||||
// "localtime", "localtimestamp", "location", "locator", "lock", "locked", "logged", "lower",
|
||||
// "m", "map", "mapping", "match", "matched", "materialized", "max", "maxvalue", "max_cardinality", "member",
|
||||
// "merge", "message_length", "message_octet_length", "message_text", "method", "min", "minute", "minvalue",
|
||||
// "mod", "mode", "modifies", "module", "month", "more", "move", "multiset", "mumps",
|
||||
// "name", "namespace", "national", "natural", "nchar", "nclob", "nesting", "new", "next", "nfc", "nfd", "nfkc", "nkfd",
|
||||
// "nil", "no", "none", "normalize", "normalize", "not", "nothing", "notify", "notnull", "nowait", "nth_value", "ntile",
|
||||
// "null", "nullable", "nullif", "nulls", "number", "numeric",
|
||||
// "object", "occurrences_regex", "octets", "octet_length", "of", "off", "offset", "oids", "old", "on", "only", "open",
|
||||
// "operator", "option", "options", "or", "order", "ordering", "ordinality", "others", "out", "outer", "output", "over",
|
||||
// "overlaps", "overlay", "overriding", "owned", "owner",
|
||||
// "p", "pad", "parallel", "parameter", "parameter_mode", "parameter_name", "parameter_specific_catalog",
|
||||
// "parameter_specific_name", "parameter_specific_schema", "parser",
|
||||
// "partial", "partition", "pascal", "passing", "passthrough", "password", "path", "percent", "percentile_cont",
|
||||
// "percentile_disc", "percent_rank", "period", "permission", "placing", "plans", "pli", "policy", "portion",
|
||||
// "position", "position_regex", "power", "precedes", "preceding", "precision", "prepare", "prepared", "preserve",
|
||||
// "primary", "prior", "privileges", "procedural", "procedure", "program", "public",
|
||||
// "quote", "range", "rank", "read", "reads", "real", "reassign", "recheck", "recovery", "recursive", "ref",
|
||||
// "references", "referencing", "refresh", "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", "regr_r2",
|
||||
// "regr_slope", "regr_sxx", "regr_sxy", "regr_syy", "reindex", "relative", "release", "rename", "repeatable",
|
||||
// "replace", "replica", "requiring", "reset", "respect", "restart", "restore", "restrict", "result", "return",
|
||||
// "returned_cardinality", "returned_length", "returned_octet_length", "returned_sqlstate", "returning", "returns",
|
||||
// "revoke", "right", "role", "rollback", "rollup", "routine", "routine_catalog", "routine_name", "routine_schema",
|
||||
// "row", "rows", "row_count", "row_number", "rule",
|
||||
// "savepoint", "scale", "schema", "schema_name", "scope", "scope_catalog", "scope_name", "scope_schema", "scroll",
|
||||
// "search", "second", "section", "security", "select", "selective", "self", "sensitive", "sequence", "sequences",
|
||||
// "serializable", "server", "server_name", "session", "session_user", "set", "setof", "sets", "share", "show",
|
||||
// "similar", "simple", "size", "skip", "smallint", "snapshot", "some", "source", "space", "specific", "specifictype",
|
||||
// "specific_name", "sql", "sqlcode", "sqlerror", "sqlexception", "sqlstate", "sqlwarning", "sqrt", "stable",
|
||||
// "standalone", "start", "state", "statement", "static", "statistics", "stddev_pop", "stddev_samp", "stdin", "stdout",
|
||||
// "storage", "strict", "strip", "structure", "style", "subclass_origin", "submultiset", "substring", "substring_regex",
|
||||
// "succeeds", "sum", "symmetric", "sysid", "system", "system_time", "system_user",
|
||||
// "t", "table", "tables", "tablesample", "tablespace", "table_name", "temp", "template", "temporary", "text", "then",
|
||||
// "ties", "time", "timestamp", "timezone_hour", "timezone_minute", "to", "token", "top_level_count", "trailing",
|
||||
// "transaction", "transaction_committed", "transaction_rolled_back", "transaction_active", "transform", "transforms",
|
||||
// "translate", "translate_regex", "translation", "treat", "trigger", "trigger_catalog", "trigger_name", "trigger_schema",
|
||||
// "trim", "trim_array", "true", "truncate", "trusted", "type", "types", "uescape", "unbounded", "uncommitted", "under",
|
||||
// "unencrypted", "union", "unique", "unknown", "unlink", "unlisten", "unlogged", "unnamed", "unnest", "until", "untyped",
|
||||
// "update", "upper", "uri", "usage", "user", "user_defined_type_catalog", "user_defined_type_code",
|
||||
// "user_defined_type_name", "user_defined_type_schema", "using",
|
||||
// "vacuum", "valid", "validate", "validator", "value", "values", "value_of", "varbinary", "varchar", "variadic",
|
||||
// "varying", "var_pop", "var_samp", "verbose", "version", "versioning", "view", "views", "volatile",
|
||||
// "when", "whenever", "where", "whitespace", "width_bucket", "window", "with", "within", "without", "work", "wrapper",
|
||||
// "write", "xml", "xmlagg", "xmlattributes", "xmlbinary", "xmlcast", "xmlcomment", "xmlconcat", "xmldeclaration",
|
||||
// "xmldocument", "xmlelement", "xmlexists", "xmlforest", "xmliterate", "xmlnamespaces", "xmlparse", "xmlpi",
|
||||
// "xmlquery", "xmlroot", "xmlschema", "xmlserialize", "xmltable", "xmltext", "xmlvalidate", "year", "yes", "zone"
|
||||
//};
|
||||
|
||||
51
pglablib/PgKeywordList.h
Normal file
51
pglablib/PgKeywordList.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef PGKEYWORDLIST_H
|
||||
#define PGKEYWORDLIST_H
|
||||
|
||||
#include <QString>
|
||||
#include <unordered_set>
|
||||
#include <functional>
|
||||
#include "util.h"
|
||||
|
||||
#define UNRESERVED_KEYWORD 0
|
||||
#define COL_NAME_KEYWORD 1
|
||||
#define TYPE_FUNC_NAME_KEYWORD 2
|
||||
#define RESERVED_KEYWORD 3
|
||||
|
||||
|
||||
|
||||
using t_SymbolSet = std::unordered_set<QString>;
|
||||
|
||||
|
||||
class Keyword {
|
||||
public:
|
||||
Keyword(QString kw, int16_t cat)
|
||||
: m_keyword(kw), m_category(cat)
|
||||
{}
|
||||
|
||||
const QString& getKeyword() const { return m_keyword; }
|
||||
int16_t getCategory() const { return m_category; }
|
||||
|
||||
//bool operator<(const QString &s) const { return m_keyword < s; }
|
||||
bool operator<(const Keyword &kw) const { return m_keyword < kw.m_keyword; }
|
||||
private:
|
||||
QString m_keyword;
|
||||
int16_t m_category;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<Keyword>
|
||||
{
|
||||
std::size_t operator()(const Keyword& s) const
|
||||
{
|
||||
return qHash(s.getKeyword());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const Keyword* getPgsqlKeyword(QString s);
|
||||
|
||||
|
||||
#endif // PGKEYWORDLIST_H
|
||||
201
pglablib/SqlFormattingUtils.cpp
Normal file
201
pglablib/SqlFormattingUtils.cpp
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
#include "SqlFormattingUtils.h"
|
||||
#include <QStringBuilder>
|
||||
|
||||
#include <cassert>
|
||||
#include "PgKeywordList.h"
|
||||
|
||||
#include "PgConstraint.h"
|
||||
#include "PgAttributeContainer.h"
|
||||
#include "PgClass.h"
|
||||
#include "PgClassContainer.h"
|
||||
#include "PgNamespace.h"
|
||||
#include "PgNamespaceContainer.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
|
||||
//inline QString u16(char16_t *utf16)
|
||||
|
||||
bool identNeedsQuotes(QString ident)
|
||||
{
|
||||
if (ident[0].isDigit())
|
||||
return true;
|
||||
for (auto c : ident)
|
||||
if (c < 'a' && c > 'z' && c != '_')
|
||||
return true;
|
||||
|
||||
auto kw = getPgsqlKeyword(ident);
|
||||
if (kw == nullptr)
|
||||
return false;
|
||||
else if (kw->getCategory() == UNRESERVED_KEYWORD)
|
||||
return false;
|
||||
// if (forTypes && sk->category == COL_NAME_KEYWORD)
|
||||
// return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString quoteIdent(QString ident)
|
||||
{
|
||||
assert(ident.length() > 0);
|
||||
|
||||
static const wchar_t dquote = L'"';
|
||||
|
||||
if (identNeedsQuotes(ident)) {
|
||||
QString out;
|
||||
out += dquote;
|
||||
out += ident.replace("\"", "\"\"");
|
||||
out += dquote;
|
||||
return out;
|
||||
}
|
||||
else
|
||||
return ident;
|
||||
}
|
||||
|
||||
|
||||
QString genSchemaPrefix(const PgNamespace &ns)
|
||||
{
|
||||
QString str;
|
||||
if (!ns.name.isEmpty()) {
|
||||
str = quoteIdent(ns.name) % QString::fromUtf16(u".");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
QString genFQTableName(const PgDatabaseCatalog &catalog, const PgClass &cls)
|
||||
{
|
||||
auto ns = catalog.namespaces()->getByKey(cls.relnamespace);
|
||||
|
||||
return genSchemaPrefix(ns) % quoteIdent(cls.name);
|
||||
}
|
||||
|
||||
QString genAlterTable(const PgDatabaseCatalog &catalog, const PgClass &cls)
|
||||
{
|
||||
return "ALTER TABLE " % genFQTableName(catalog, cls);
|
||||
}
|
||||
|
||||
QString getDropConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
||||
{
|
||||
PgClass cls = catalog.classes()->getByKey(constraint.relid);
|
||||
return genAlterTable(catalog, cls) % " DROP CONSTRAINT " % quoteIdent(constraint.name) % ";";
|
||||
}
|
||||
|
||||
|
||||
/// Helper class that builds comma seperated identifier list
|
||||
class IdentListString {
|
||||
public:
|
||||
void add(QString ident)
|
||||
{
|
||||
if (!m_str.isEmpty())
|
||||
m_str += ",";
|
||||
m_str += quoteIdent(ident);
|
||||
}
|
||||
const QString& str() const { return m_str; }
|
||||
private:
|
||||
QString m_str;
|
||||
};
|
||||
|
||||
QString getColumnNameList(const PgDatabaseCatalog &catalog, Oid relid, const AttNumVec &attnums)
|
||||
{
|
||||
IdentListString result;
|
||||
|
||||
const auto ac = catalog.attributes();
|
||||
for (auto an : attnums) {
|
||||
result.add(ac->getByKey({ relid, an }).name);
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
QString getForeignKeyConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
||||
{
|
||||
//PgClass cls = catalog.classes()->getByKey(constraint.relid);
|
||||
PgClass fcls = catalog.classes()->getByKey(constraint.frelid);
|
||||
QString deferrable;
|
||||
QString validated;
|
||||
if (!constraint.validated)
|
||||
validated += " NOT VALID";
|
||||
if (constraint.deferrable) {
|
||||
deferrable = QLatin1String(" DEFERRABLE INITIALLY ") % (constraint.deferred ? "DEFERRED" : "IMMEDIATE");
|
||||
}
|
||||
|
||||
return "\n FOREIGN KEY ("
|
||||
% getColumnNameList(catalog, constraint.relid, constraint.key) % ")\n REFERENCES "
|
||||
% genFQTableName(catalog, fcls) % " ("
|
||||
% getColumnNameList(catalog, constraint.frelid, constraint.fkey) % ")\n MATCH "
|
||||
% ForeignKeyMatchToString(constraint.fmatchtype)
|
||||
% " ON UPDATE " % ForeignKeyActionToString(constraint.fupdtype)
|
||||
% " ON DELETE " % ForeignKeyActionToString(constraint.fdeltype)
|
||||
% deferrable % validated % ";";
|
||||
|
||||
|
||||
}
|
||||
|
||||
QString getPrimaryKeyConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
||||
{
|
||||
QString ddl = " PRIMARY KEY ("
|
||||
% getColumnNameList(catalog, constraint.relid, constraint.key) % ");";
|
||||
|
||||
return ddl;
|
||||
}
|
||||
|
||||
QString getUniqueConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
||||
{
|
||||
QString ddl = " UNIQUE ("
|
||||
% getColumnNameList(catalog, constraint.relid, constraint.key) % ");";
|
||||
|
||||
return ddl;
|
||||
}
|
||||
|
||||
QString getConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint)
|
||||
{
|
||||
PgClass cls = catalog.classes()->getByKey(constraint.relid);
|
||||
// return genAlterTable(catalog, cls) % " ADD CONSTRAINT "
|
||||
// % quoteIdent(constraint.name) % " " % constraint.definition % ";";
|
||||
QString result = genAlterTable(catalog, cls) % "\n ADD CONSTRAINT "
|
||||
% quoteIdent(constraint.name);
|
||||
switch (constraint.type) {
|
||||
case ConstraintType::ForeignKey:
|
||||
result += getForeignKeyConstraintDefinition(catalog, constraint);
|
||||
break;
|
||||
case ConstraintType::PrimaryKey:
|
||||
result += getPrimaryKeyConstraintDefinition(catalog, constraint);
|
||||
break;
|
||||
case ConstraintType::Unique:
|
||||
result += getUniqueConstraintDefinition(catalog, constraint);
|
||||
break;
|
||||
case ConstraintType::Check:
|
||||
default:
|
||||
result = result % " " % constraint.definition;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
wxString sql;
|
||||
|
||||
sql = wxT("(") + GetQuotedFkColumns()
|
||||
+ wxT(")\n REFERENCES ") + GetQuotedSchemaPrefix(GetRefSchema()) + qtIdent(GetReferences())
|
||||
+ wxT(" (") + GetQuotedRefColumns()
|
||||
+ wxT(")");
|
||||
|
||||
if (GetDatabase()->BackendMinimumVersion(7, 4) || GetMatch() == wxT("FULL"))
|
||||
sql += wxT(" MATCH ") + GetMatch();
|
||||
|
||||
sql += wxT("\n ON UPDATE ") + GetOnUpdate()
|
||||
+ wxT(" ON DELETE ") + GetOnDelete();
|
||||
if (GetDeferrable())
|
||||
{
|
||||
sql += wxT(" DEFERRABLE INITIALLY ");
|
||||
if (GetDeferred())
|
||||
sql += wxT("DEFERRED");
|
||||
else
|
||||
sql += wxT("IMMEDIATE");
|
||||
}
|
||||
|
||||
if (GetDatabase()->BackendMinimumVersion(9, 1) && !GetValid())
|
||||
sql += wxT("\n NOT VALID");
|
||||
|
||||
return sql;
|
||||
*/
|
||||
|
||||
17
pglablib/SqlFormattingUtils.h
Normal file
17
pglablib/SqlFormattingUtils.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef SQLFORMATTINGUTILS_H
|
||||
#define SQLFORMATTINGUTILS_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
|
||||
class PgConstraint;
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
bool identNeedsQuotes(QString ident);
|
||||
|
||||
QString getDropConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint);
|
||||
QString getConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint);
|
||||
|
||||
QString getForeignKeyConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint);
|
||||
|
||||
#endif // SQLFORMATTINGUTILS_H
|
||||
|
|
@ -49,7 +49,9 @@ SOURCES += \
|
|||
PgConstraintContainer.cpp \
|
||||
ParamListJson.cpp \
|
||||
ParamListModel.cpp \
|
||||
util.cpp
|
||||
util.cpp \
|
||||
SqlFormattingUtils.cpp \
|
||||
PgKeywordList.cpp
|
||||
|
||||
HEADERS += \
|
||||
Pglablib.h \
|
||||
|
|
@ -75,7 +77,10 @@ HEADERS += \
|
|||
PgConstraintContainer.h \
|
||||
ParamListJson.h \
|
||||
ParamListModel.h \
|
||||
util.h
|
||||
util.h \
|
||||
SqlFormattingUtils.h \
|
||||
PgCatalogTypes.h \
|
||||
PgKeywordList.h
|
||||
|
||||
unix {
|
||||
target.path = /usr/lib
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include "Pgsql_Params.h"
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
|
|
@ -199,6 +200,52 @@ void Connection::setNoticeReceiver(std::function<void(const PGresult *)> callbac
|
|||
, reinterpret_cast<void*>(this));
|
||||
}
|
||||
|
||||
std::string Connection::escapeLiteral(const std::string_view &literal)
|
||||
{
|
||||
std::unique_ptr<char, void(*)(char*)> result(
|
||||
PQescapeLiteral(conn, literal.data(), literal.length()),
|
||||
[](char*p) { if (p) PQfreemem(p); });
|
||||
if (result) {
|
||||
return std::string(result.get());
|
||||
}
|
||||
throw std::runtime_error("escapeLiteral(string_view) failed");
|
||||
}
|
||||
|
||||
QString Connection::escapeLiteral(const QString &literal)
|
||||
{
|
||||
auto u8 = literal.toUtf8();
|
||||
std::unique_ptr<char, void(*)(char*)> result(
|
||||
PQescapeLiteral(conn, u8.data(), u8.length()),
|
||||
[](char*p) { if (p) PQfreemem(p); });
|
||||
if (result) {
|
||||
return QString::fromUtf8(result.get());
|
||||
}
|
||||
throw std::runtime_error("escapeLiteral(QString) failed");
|
||||
}
|
||||
|
||||
std::string Connection::escapeIdentifier(const std::string_view &ident)
|
||||
{
|
||||
std::unique_ptr<char, void(*)(char*)> result(
|
||||
PQescapeIdentifier(conn, ident.data(), ident.length()),
|
||||
[](char*p) { if (p) PQfreemem(p); });
|
||||
if (result) {
|
||||
return std::string(result.get());
|
||||
}
|
||||
throw std::runtime_error("escapeIdentifier failed");
|
||||
}
|
||||
|
||||
QString Connection::escapeIdentifier(const QString &ident)
|
||||
{
|
||||
auto u8 = ident.toUtf8();
|
||||
std::unique_ptr<char, void(*)(char*)> result(
|
||||
PQescapeIdentifier(conn, u8.data(), u8.length()),
|
||||
[](char*p) { if (p) PQfreemem(p); });
|
||||
if (result) {
|
||||
return QString::fromUtf8(result.get());
|
||||
}
|
||||
throw std::runtime_error("escapeIdentifier(QString) failed");
|
||||
}
|
||||
|
||||
void Connection::notifyReceiveFunc(void *arg, const PGresult *result)
|
||||
{
|
||||
Connection *c = reinterpret_cast<Connection *>(arg);
|
||||
|
|
|
|||
|
|
@ -25,28 +25,9 @@ namespace Pgsql {
|
|||
|
||||
*/
|
||||
|
||||
// class ConnectionParams {
|
||||
// public:
|
||||
// std::string host;
|
||||
// std::string hostaddr;
|
||||
// unsigned short port = 5432;
|
||||
// std::string dbname;
|
||||
// std::string user;
|
||||
// std::string password;
|
||||
// int connect_timeout = -1; ///< -1 omit (ie uses default)
|
||||
// std::string application_name;
|
||||
|
||||
// };
|
||||
|
||||
|
||||
|
||||
class Result;
|
||||
class Params;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** \brief Wrapper for a cancel object from libpq.
|
||||
*/
|
||||
class Canceller {
|
||||
|
|
@ -80,16 +61,14 @@ namespace Pgsql {
|
|||
Connection(Connection &&rhs);
|
||||
Connection& operator=(Connection &&rhs);
|
||||
|
||||
// void connect(const ConnectionParams ¶ms);
|
||||
bool connect(const char *params);
|
||||
bool connect(const QString ¶ms)
|
||||
{
|
||||
return connect(params.toUtf8().data());
|
||||
}
|
||||
|
||||
bool connect(const char *const * keywords, const char* const * values, int expand_dbname);
|
||||
|
||||
bool connectStart(const char *params);
|
||||
|
||||
bool connectStart(const std::string ¶ms)
|
||||
{
|
||||
return connectStart(params.c_str());
|
||||
|
|
@ -99,6 +78,7 @@ namespace Pgsql {
|
|||
{
|
||||
return connectStart(params.toUtf8().data());
|
||||
}
|
||||
|
||||
bool connectStart(const char * const *keywords,
|
||||
const char * const *values);
|
||||
|
||||
|
|
@ -135,6 +115,11 @@ namespace Pgsql {
|
|||
bool isBusy();
|
||||
|
||||
void setNoticeReceiver(std::function<void(const PGresult *)> callback);
|
||||
|
||||
std::string escapeLiteral(const std::string_view &literal);
|
||||
QString escapeLiteral(const QString &literal);
|
||||
std::string escapeIdentifier(const std::string_view &ident);
|
||||
QString escapeIdentifier(const QString &ident);
|
||||
private:
|
||||
PGconn *conn = nullptr;
|
||||
std::function<void(const PGresult *)> notifyReceiver;
|
||||
|
|
@ -142,75 +127,6 @@ namespace Pgsql {
|
|||
static void notifyReceiveFunc(void *arg, const PGresult *result);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// class Field {
|
||||
// public:
|
||||
|
||||
// std::string getName() const;
|
||||
|
||||
// private:
|
||||
// //Tuples tuples;
|
||||
// int field;
|
||||
// //
|
||||
|
||||
// };
|
||||
|
||||
// class Tuples {
|
||||
// public:
|
||||
// int getRowCount() const;
|
||||
// int getColCount() const;
|
||||
|
||||
// Field getField(const std::string &fname);
|
||||
// Field getField(const int idx);
|
||||
|
||||
// class const_iterator {
|
||||
// public:
|
||||
// const_iterator& operator++();
|
||||
// };
|
||||
|
||||
// void rewind();
|
||||
|
||||
|
||||
// };
|
||||
|
||||
// class OkResult: public Result {
|
||||
// public:
|
||||
// /** If the result is a data result then returns an interface for processing this data.
|
||||
|
||||
// The returned interface remains valid as long as this OkResult exists.
|
||||
// */
|
||||
// Tuples* hasTuples();
|
||||
// };
|
||||
|
||||
// class ErrorResult: public Result {
|
||||
//
|
||||
// };
|
||||
|
||||
// class ITransaction {
|
||||
// public:
|
||||
//
|
||||
// Canceller Query(std::string query,
|
||||
// std::function<void(OkResult)> on_success,
|
||||
// std::function<void()> on_cancelled,
|
||||
// std::function<void(ErrorResult)> on_error);
|
||||
//
|
||||
// Canceller Query(std::string query,
|
||||
// std::function<void(OkResult)> on_success,
|
||||
// std::function<void()> on_cancelled,
|
||||
// std::function<void(ErrorResult)> on_error);
|
||||
//
|
||||
//
|
||||
// void Rollback(
|
||||
// std::function<void(OkResult)> on_success,
|
||||
// std::function<void(ErrorResult)> on_error);
|
||||
// void Commit(
|
||||
// std::function<void(OkResult)> on_success,
|
||||
// std::function<void()> on_cancelled,
|
||||
// std::function<void(ErrorResult)> on_error);
|
||||
//
|
||||
// };
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue