diff --git a/core/core.pro b/core/core.pro index c1ea4ac..9b02792 100644 --- a/core/core.pro +++ b/core/core.pro @@ -58,7 +58,8 @@ HEADERS += PasswordManager.h \ SqlAstSelectList.h \ SqlAstSelectListEntry.h \ SqlAstSelect.h \ - SqlAstExpression.h + SqlAstExpression.h \ + std_utils.h unix { target.path = /usr/lib diff --git a/core/std_utils.h b/core/std_utils.h new file mode 100644 index 0000000..1163811 --- /dev/null +++ b/core/std_utils.h @@ -0,0 +1,14 @@ +#ifndef STD_UTILS_H +#define STD_UTILS_H + +#include + +template +const T& value_or(const std::vector &vec, const size_t index, const T &def) +{ + if (index < 0 || index >= vec.size()) + return def; + return vec[index]; +} + +#endif // STD_UTILS_H diff --git a/pglab/FunctionsPage.cpp b/pglab/FunctionsPage.cpp new file mode 100644 index 0000000..5745030 --- /dev/null +++ b/pglab/FunctionsPage.cpp @@ -0,0 +1,40 @@ +#include "FunctionsPage.h" +#include "ResultTableModelUtil.h" +#include "CustomFilterSortModel.h" +#include "CustomDataRole.h" +#include "PgLabItemDelegate.h" +#include "ProcTableModel.h" +#include +#include + +FunctionsPage::FunctionsPage(QWidget *parent) : QWidget(parent) +{ + + m_functionTable = new QTableView(this); + SetTableViewDefault(m_functionTable); + + m_model = new ProcTableModel(this); + m_sortFilterProxy = new CustomFilterSortModel(this); + m_sortFilterProxy->setSourceModel(m_model); + m_functionTable->setModel(m_sortFilterProxy); + m_functionTable->setSortingEnabled(true); + m_functionTable->setSelectionBehavior(QAbstractItemView::SelectRows); + + auto item_delegate = new PgLabItemDelegate(this); + m_functionTable->setItemDelegate(item_delegate); + + auto mainLayout = new QVBoxLayout; + mainLayout->addWidget(m_functionTable); + setLayout(mainLayout); +} + +void FunctionsPage::retranslateUi(bool all) +{ + +} + +void FunctionsPage::setCatalog(std::shared_ptr cat) +{ + m_catalog = cat; + m_model->setCatalog(cat); +} diff --git a/pglab/FunctionsPage.h b/pglab/FunctionsPage.h new file mode 100644 index 0000000..805825a --- /dev/null +++ b/pglab/FunctionsPage.h @@ -0,0 +1,32 @@ +#ifndef FUNCTIONSPAGE_H +#define FUNCTIONSPAGE_H + +#include +#include + +class QTableView; +class PgDatabaseCatalog; +class ProcTableModel; +class CustomFilterSortModel; + +class FunctionsPage : public QWidget { + Q_OBJECT +public: + explicit FunctionsPage(QWidget *parent = nullptr); + + void setCatalog(std::shared_ptr cat); +signals: + +public slots: + +private: + QTableView *m_functionTable = nullptr; + ProcTableModel *m_model = nullptr; + CustomFilterSortModel *m_sortFilterProxy = nullptr; + std::shared_ptr m_catalog; + + void retranslateUi(bool all = true); + +}; + +#endif // FUNCTIONSPAGE_H diff --git a/pglab/MainWindow.cpp b/pglab/MainWindow.cpp index 5410a64..ffba2cb 100644 --- a/pglab/MainWindow.cpp +++ b/pglab/MainWindow.cpp @@ -1,6 +1,7 @@ #include "MainWindow.h" #include "ui_MainWindow.h" #include "TablesPage.h" +#include "FunctionsPage.h" #include #include @@ -103,8 +104,10 @@ void MainWindow::catalogLoaded() auto tt = new TablesPage(this); tt->setCatalog(m_database->catalog()); ui->tabWidget->addTab(tt, "Tables"); - ui->tabWidget->setCurrentWidget(tt); + auto functions_page = new FunctionsPage(this); + functions_page->setCatalog(m_database->catalog()); + ui->tabWidget->addTab(functions_page, "Functions"); newSqlPage(); } catch (std::runtime_error &ex) { diff --git a/pglab/ProcTableModel.cpp b/pglab/ProcTableModel.cpp new file mode 100644 index 0000000..ff9f9e0 --- /dev/null +++ b/pglab/ProcTableModel.cpp @@ -0,0 +1,90 @@ +#include "ProcTableModel.h" +#include "PgDatabaseCatalog.h" +#include "PgProcContainer.h" +#include "CustomDataRole.h" + +ProcTableModel::ProcTableModel(QObject *parent) + : QAbstractTableModel(parent) +{ +} + +QVariant ProcTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal) { + if (role == Qt::DisplayRole) { + switch (section) { + case NameCol: return tr("Name"); + case NamespaceCol: return tr("Schema"); + case OwnerCol: return tr("Owner"); + case LangCol: return tr("Language"); + case AclCol: return tr("ACL"); + } + } + } + return QVariant(); +} + +void ProcTableModel::setCatalog(std::shared_ptr cat) +{ + beginResetModel(); + + m_catalog = cat; + m_procs = cat->procs(); + + endResetModel(); +} + +int ProcTableModel::rowCount(const QModelIndex &) const +{ + return m_procs ? static_cast(m_procs->count()) : 0; +} + +int ProcTableModel::columnCount(const QModelIndex &) const +{ + return colCount; +} + +QVariant ProcTableModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::DisplayRole) + return getData(index); + else if (role == CustomDataTypeRole) + return getType(index.column()); +// else if (role == FirstHiddenValue) { +// auto&& t = m_triggers->getByIdx(index.row()); +// return t.relid; // +// } + return QVariant(); +} + +PgProc ProcTableModel::proc(int row) const +{ + return m_procs->getByIdx(row); +} + +Oid ProcTableModel::getType(int ) const +{ +// switch (column) { +// case NameCol: return tr("Name"); +// case NamespaceCol: return tr("Schema"); +// case OwnerCol: return tr("Owner"); +// case LangCol: return tr("Language"); +// return Pgsql::bool_oid; +// } + return Pgsql::varchar_oid; +} + +QVariant ProcTableModel::getData(const QModelIndex &index) const +{ + auto&& t = m_procs->getByIdx(index.row()); + switch (index.column()) { + case NameCol: return t.name; + case NamespaceCol: return t.schemaOid(); + case OwnerCol: return t.owner; + case LangCol: return t.lang; + case AclCol: return t.acl; + } + return QVariant(); +} + + diff --git a/pglab/ProcTableModel.h b/pglab/ProcTableModel.h new file mode 100644 index 0000000..fb1bf11 --- /dev/null +++ b/pglab/ProcTableModel.h @@ -0,0 +1,56 @@ +#ifndef PROCTABLEMODEL_H +#define PROCTABLEMODEL_H + +#include +#include "PgClass.h" +#include "PgProc.h" +#include + +class PgDatabaseCatalog; +class PgProcContainer; + +/** + * @brief The ProcTableModel class + * + * Hidden values: + * + */ +class ProcTableModel: public QAbstractTableModel { + Q_OBJECT +public: + //using QAbstractTableModel::QAbstractTableModel; + + enum e_Columns : int { + NameCol, // + NamespaceCol, // Schema + OwnerCol, + LangCol, + AclCol, + + colCount + }; + + ProcTableModel(QObject *parent = nullptr); + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + void setCatalog(std::shared_ptr cat); + + // Basic functionality: + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + virtual QVariant data(const QModelIndex &index, int role) const override; + + PgProc proc(int row) const; + +private: + std::shared_ptr m_catalog; + std::shared_ptr m_procs; + + Oid getType(int column) const; + QVariant getData(const QModelIndex &index) const; + +}; + + +#endif // PROCTABLEMODEL_H diff --git a/pglab/TablesTableModel.cpp b/pglab/TablesTableModel.cpp index e534f79..52f9a7e 100644 --- a/pglab/TablesTableModel.cpp +++ b/pglab/TablesTableModel.cpp @@ -92,32 +92,19 @@ void TablesTableModel::doSort(int ) QVariant TablesTableModel::headerData(int section, Qt::Orientation orientation, int role) const { - QVariant v; if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole) { switch (section) { - case NameCol: - v = tr("Name"); - break; - case NamespaceCol: - v = tr("Schema"); - break; - case OwnerCol: - v = tr("Owner"); - break; - case TablespaceCol: - v = tr("Tablespace"); - break; - case OptionsCol: - v = tr("Options"); - break; -// case AclCol: -// v = tr("ACL"); -// break; + case NameCol: return tr("Name"); + case NamespaceCol: return tr("Schema"); + case OwnerCol: return tr("Owner"); + case TablespaceCol: return tr("Tablespace"); + case OptionsCol: return tr("Options"); + case AclCol: return tr("ACL"); } } } - return v; + return QVariant(); } // Basic functionality: @@ -140,7 +127,7 @@ Oid TablesTableModel::getType(int column) const case NameCol: case NamespaceCol: case OptionsCol: -// case AclCol: + case AclCol: default: oid = Pgsql::varchar_oid; } @@ -149,30 +136,17 @@ Oid TablesTableModel::getType(int column) const QVariant TablesTableModel::getData(const QModelIndex &index) const { - QVariant v; const auto &t = m_tables[index.row()]; switch (index.column()) { - case NameCol: - v = t.name; //formatTableName(t); - break; - case NamespaceCol: - v = getNamespaceDisplayString(*m_catalog, t.relnamespace); - break; - case OwnerCol: - v = getRoleDisplayString(*m_catalog, t.owner); - break; - case TablespaceCol: - v = getTablespaceDisplayString(*m_catalog, t.tablespace); - break; - case OptionsCol: - //v = t.options; - break; - // case AclCol: - // v = t.acl; - // break; + case NameCol: return t.name; //formatTableName(t); + case NamespaceCol: return getNamespaceDisplayString(*m_catalog, t.relnamespace); + case OwnerCol: return getRoleDisplayString(*m_catalog, t.owner); + case TablespaceCol: return getTablespaceDisplayString(*m_catalog, t.tablespace); + case OptionsCol: break; + case AclCol: return t.acl; } - return v; + return QVariant(); } PgClass TablesTableModel::getTable(int row) const diff --git a/pglab/TablesTableModel.h b/pglab/TablesTableModel.h index 1277c82..e1aa57f 100644 --- a/pglab/TablesTableModel.h +++ b/pglab/TablesTableModel.h @@ -17,7 +17,7 @@ public: OwnerCol, TablespaceCol, OptionsCol, - //AclCol, + AclCol, colCount }; TablesTableModel(QObject *parent); diff --git a/pglab/pglab.pro b/pglab/pglab.pro index ed02d76..28f23c7 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -77,7 +77,9 @@ PropertyProxyModel.cpp \ SqlCodePreview.cpp \ CustomFilterSortModel.cpp \ PropertiesPage.cpp \ - PasswordPromptDialog.cpp + PasswordPromptDialog.cpp \ + ProcTableModel.cpp \ + FunctionsPage.cpp HEADERS += \ QueryResultModel.h \ @@ -132,7 +134,9 @@ CustomDataRole.h \ SqlCodePreview.h \ CustomFilterSortModel.h \ PropertiesPage.h \ - PasswordPromptDialog.h + PasswordPromptDialog.h \ + ProcTableModel.h \ + FunctionsPage.h FORMS += mainwindow.ui \ ConnectionManagerWindow.ui \ diff --git a/pglablib/PgClass.h b/pglablib/PgClass.h index 6ee7984..5497f1f 100644 --- a/pglablib/PgClass.h +++ b/pglablib/PgClass.h @@ -51,7 +51,7 @@ public: bool ispopulated; int frozenxid; int minmxid; - std::vector acl; + QString acl; std::vector options; bool operator==(Oid _oid) const { return oid == _oid; } diff --git a/pglablib/PgProc.cpp b/pglablib/PgProc.cpp index 6ca74de..32540e5 100644 --- a/pglablib/PgProc.cpp +++ b/pglablib/PgProc.cpp @@ -1,6 +1,283 @@ #include "PgProc.h" +#include "std_utils.h" +#include "SqlFormattingUtils.h" +#include "PgDatabaseCatalog.h" +#include "PgTypeContainer.h" +#include + +namespace { + + Arg::Mode CharToArgMode(char c) + { + switch (c) { + case 'i': return Arg::In; + case 'o': return Arg::Out; + case 'b': return Arg::InOut; + case 'v': return Arg::Variadic; + case 't': return Arg::Table; + } + throw std::runtime_error("Unexpected value for pg_proc.proargmodes"); + } + + QString ArgModeToString(Arg::Mode m) + { + switch (m) { + case Arg::In: return "IN"; + case Arg::Out: return "OUT"; + case Arg::InOut: return "INOUT"; + case Arg::Variadic: return "VARIADIC"; + case Arg::Table: return "TABLE"; + } + throw std::runtime_error("Unexpected value for Arg::Mode"); + } + + + + std::vector getArrayFromCommaSeparatedList(const QString &str) + { + std::vector res; + const int len = str.length(); + if (len == 0) + return res; + + // setup start state for parsing + int index = 0, brackets = 0, start_array = 0; + bool single_quote = false, double_quote = false; + + for(; index < len; index++) { + QChar ch = str[index]; + if (!double_quote && ch == L'\'') + single_quote = !single_quote; + else if (!single_quote && ch == L'"') + double_quote = !double_quote; + else if (!double_quote && !single_quote && ch == L'(') + brackets++; + else if (!double_quote && !single_quote && ch == L')') + brackets--; + else if (!double_quote && !single_quote && brackets == 0 && ch == L',') { + if (index != start_array) + res.push_back(str.mid(start_array, index - 1).trimmed()); + else + res.push_back(QString()); + start_array = index + 1; + } + } + if (double_quote || single_quote || brackets != 0) + throw std::runtime_error("Error parsing comma seperated array"); + + + // Add last value to array + res.push_back(str.right(start_array).trimmed()); + return res; + } + + +} QString PgProc::objectName() const { return name; } + +void PgProc::setArgs( + std::vector argtypes, + std::vector allargtypes, + std::vector argmodes, + std::vector argnames, + std::optional argdefaults + ) +{ + // When all args are of type IN allargtypes is empty and only argtypes is filled + const std::vector &types = allargtypes.empty() ? argtypes : allargtypes; + const size_t count = types.size(); + m_args.clear(); + m_args.reserve(count); + for (size_t index = 0; index < count; ++index) { + // we "forget" the default here because it is easier + // to apply them in reverse order when we have already + // filled the list + m_args.emplace_back( + types[index], + CharToArgMode(value_or(argmodes, index, 'i')), + value_or(argnames, index, QString()), + "" + ); + } + auto defaults_array = getArrayFromCommaSeparatedList(argdefaults.value_or(QString())); + + // Apply defaults from end to start to IN en INOUT parameters (others can't have a default) + size_t arg_idx = m_args.size() - 1; + for (auto def_iter = defaults_array.rbegin(); def_iter != defaults_array.rend(); ++def_iter) { + // skip arguments with wrong mode + while (m_args[arg_idx].mode != Arg::In && m_args[arg_idx].mode != Arg::InOut) + if (arg_idx == 0) throw std::runtime_error("Error processing defaults"); + else --arg_idx; + m_args[arg_idx].def = *def_iter; + } +} + +const std::vector& PgProc::args() const +{ + return m_args; +} + +QString PgProc::argListWithNames(bool multiline) const +{ + QString args; + size_t nArgs = 0; + + auto&& types = catalog().types(); + + for (auto&& arg_elem : m_args) { + + // All Table arguments lies at the end of the list + // Do not include them as the part of the argument list + if (arg_elem.mode == Arg::Table) + break; + + nArgs++; + if (args.length() > 0) + args += (multiline) ? ",\n " : ", "; + + QString arg; + if (arg_elem.mode != Arg::In) + arg += ArgModeToString(arg_elem.mode); + + if (!arg_elem.name.isEmpty()) { + if (!arg.isEmpty()) + arg += " "; + arg += quoteIdent(arg_elem.name); + } + + if (!arg.isEmpty()) + arg += " "; + arg += types->getByKey(arg_elem.type)->name; + + if (!arg_elem.def.isEmpty()) + arg += " DEFAULT " + arg_elem.def; + + args += arg; + } + + if (multiline && nArgs > 1) + args = "\n " + args; + + return args; +} + +// Return the signature arguments list. If forScript = true, we format the list +// appropriately for use in a SELECT script. +QString PgProc::argSigList(const bool forScript) const +{ + QString args; + + auto&& types = catalog().types(); + + for (auto&& arg_elem : m_args) { + // OUT parameters are not considered part of the signature, except for EDB-SPL, + // although this is not true for EDB AS90 onwards.. + if (arg_elem.mode != Arg::Out && arg_elem.mode != Arg::Table) { + if (args.length() > 0) { + if (forScript) + args += ",\n"; + else + args += ", "; + } + + QString typname = types->getByKey(arg_elem.type)->name; + if (forScript) + args += " <" + typname + ">"; + else + args += typname; + } + } + return args; +} + + +QString PgProc::createSql() const +{ + if (createSqlCache.isEmpty()) { + QString sql; + + //wxString qtName = GetQuotedFullIdentifier() + wxT("(") + GetArgListWithNames(true) + wxT(")"); + QString quoted_name = QString("%1(%2)").arg(fullyQualifiedQuotedObjectName(), argListWithNames(true)); +// wxString qtSig = GetQuotedFullIdentifier() + wxT("(") + GetArgSigList() + wxT(")"); + QString quoted_sig = QString("%1(%2)").arg(fullyQualifiedQuotedObjectName(), argSigList()); + + auto&& types = catalog().types(); + QString return_type = types->getByKey(rettype)->name; + + + sql = QString("-- Function: %1\n\n" + "-- DROP FUNCTION %1;\n\n" + "CREATE OR REPLACE FUNCTION %2\n" + " RETURNS %3 AS\n" + ).arg(quoted_sig, quoted_name, return_type); + +// if (GetLanguage().IsSameAs(wxT("C"), false)) +// { +// sql += qtDbString(GetBin()) + wxT(", ") + qtDbString(GetSource()); +// } +// else +// { +// if (GetConnection()->BackendMinimumVersion(7, 5)) +// sql += qtDbStringDollar(GetSource()); + sql += dollarQuoteString(src); +// else +// sql += qtDbString(GetSource()); +// } +// sql += wxT("\n LANGUAGE ") + GetLanguage() + wxT(" "); +// if (GetConnection()->BackendMinimumVersion(8, 4) && GetIsWindow()) +// sql += wxT("WINDOW "); +// sql += GetVolatility(); + +// if (GetConnection()->BackendMinimumVersion(9, 2) && GetIsLeakProof()) +// sql += wxT(" LEAKPROOF"); +// if (GetIsStrict()) +// sql += wxT(" STRICT"); +// if (GetSecureDefiner()) +// sql += wxT(" SECURITY DEFINER"); + +// // PostgreSQL 8.3+ cost/row estimations +// if (GetConnection()->BackendMinimumVersion(8, 3)) +// { +// sql += wxT("\n COST ") + NumToStr(GetCost()); + +// if (GetReturnAsSet()) +// sql += wxT("\n ROWS ") + NumToStr(GetRows()); +// } + +// if (!sql.Strip(wxString::both).EndsWith(wxT(";"))) +// sql += wxT(";"); + +// size_t i; +// for (i = 0 ; i < configList.GetCount() ; i++) +// { +// if (configList.Item(i).BeforeFirst('=') != wxT("search_path") && +// configList.Item(i).BeforeFirst('=') != wxT("temp_tablespaces")) +// sql += wxT("\nALTER FUNCTION ") + qtSig +// + wxT(" SET ") + configList.Item(i).BeforeFirst('=') + wxT("='") + configList.Item(i).AfterFirst('=') + wxT("';\n"); +// else +// sql += wxT("\nALTER FUNCTION ") + qtSig +// + wxT(" SET ") + configList.Item(i).BeforeFirst('=') + wxT("=") + configList.Item(i).AfterFirst('=') + wxT(";\n"); +// } + +// sql += wxT("\n") +// + GetOwnerSql(8, 0, wxT("FUNCTION ") + qtSig) +// + GetGrant(wxT("X"), wxT("FUNCTION ") + qtSig); + +// if (!GetComment().IsNull()) +// { +// sql += wxT("COMMENT ON FUNCTION ") + qtSig +// + wxT(" IS ") + qtDbString(GetComment()) + wxT(";\n"); +// } + +// if (GetConnection()->BackendMinimumVersion(9, 1)) +// sql += GetSeqLabelsSql(); + + createSqlCache = std::move(sql); + } + + return createSqlCache; +} diff --git a/pglablib/PgProc.h b/pglablib/PgProc.h index 5be9fd9..e99c0ee 100644 --- a/pglablib/PgProc.h +++ b/pglablib/PgProc.h @@ -5,6 +5,24 @@ #include #include #include "Pgsql_Value.h" +#include + +class Arg { +public: + enum Mode { + In, Out, InOut, Variadic, Table + }; + + Oid type; + Mode mode; + QString name; + QString def; + + Arg(Oid t, Mode m, QString n, QString d) + : type(t), mode(m), name(n), def(d) + {} +}; + class PgProc: public PgSchemaObject { public: @@ -28,18 +46,24 @@ public: char provolatile = '\0'; // char char parallel = '\0'; // char, version >= 9.6 int16_t nargs = 0; // int2 - int16_t nargdefaults = 0; // int2 + int16_t nargdefaults; // = 0; // int2 Oid rettype = InvalidOid; // oid - std::vector argtypes; // oid[] - std::vector allargtypes; // oid[] - std::vector argmodes; // char[] - std::vector argnames; // text[] - std::optional argdefaults; // pg_node_tree std::vector trftypes; // oid[], version >= 9.5 QString src; // text QString bin; // text std::vector config; // text[] - std::vector acl; // aclitem[] + QString acl; // aclitem[] + + /// Converts the collection of arrays about the arguments to a single list of arguments + /// making it much easier to work with them correctly + void setArgs( + std::vector argtypes, + std::vector allargtypes, + std::vector argmodes, + std::vector argnames, + std::optional argdefaults + ); + const std::vector& args() const; bool operator==(Oid _oid) const { return oid == _oid; } bool operator==(const QString &n) const { return name == n; } @@ -47,6 +71,19 @@ public: bool operator<(const PgProc &rhs) const { return oid < rhs.oid; } virtual QString objectName() const override; + + QString createSql() const; + QString argListWithNames(bool multiline = false) const; + QString argSigList(const bool forScript = false) const; + +// bool isTrigger() const +// { +// return typname == wxT("\"trigger\"") || typname == wxT("trigger") || typname == wxT("event_trigger") || typname == wxT("\"event_trigger\"")) +// } +private: + mutable QString createSqlCache; + + std::vector m_args; }; #endif // PGPROC_H diff --git a/pglablib/PgProcContainer.cpp b/pglablib/PgProcContainer.cpp index f7239e8..bb5f0c9 100644 --- a/pglablib/PgProcContainer.cpp +++ b/pglablib/PgProcContainer.cpp @@ -28,17 +28,22 @@ PgProc PgProcContainer::loadElem(const Pgsql::Row &row) Pgsql::Col col(row); PgProc v(m_catalog); Oid namespace_oid; + std::vector argtypes; // oid[] + std::vector allargtypes; // oid[] + std::vector argmodes; // char[] + std::vector argnames; // text[] + std::optional argdefaults; // pg_node_tree + col >> v.oid >> v.name >> namespace_oid >> v.owner >> v.lang >> v.cost >> v.rows >> v.variadic >> v.transform >> v.isagg >> v.iswindow >> v.secdef >> v.leakproof >> v.isstrict >> v.retset >> v.provolatile >> v.nargs >> v.nargdefaults >> v.rettype; - col.getAsVector(std::back_inserter(v.argtypes)); - col >> v.allargtypes >> v.argmodes >> v.argnames - >> v.argdefaults; - col >> v.src; - col >> v.bin >> v.config >> v.acl; + col.getAsVector(std::back_inserter(argtypes)); + col >> allargtypes >> argmodes >> argnames >> argdefaults + >> v.src >> v.bin >> v.config >> v.acl; v.setSchemaOid(namespace_oid); + v.setArgs(argtypes, allargtypes, argmodes, argnames, argdefaults); if (minimumVersion(90500)) { col >> v.trftypes; diff --git a/pglablib/PgType.h b/pglablib/PgType.h index e82f2e0..2841090 100644 --- a/pglablib/PgType.h +++ b/pglablib/PgType.h @@ -31,7 +31,8 @@ public: PgType(); Oid oid = InvalidOid; - QString name;//"name";"NO" + QString name; // formatted name as per database, arrays + QString typname; //"name";"NO" Oid typnamespace = InvalidOid;//"oid";"NO" Oid owner = InvalidOid;//"oid";"NO" short len = -1;//"smallint";"NO" diff --git a/pglablib/PgTypeContainer.cpp b/pglablib/PgTypeContainer.cpp index b8c0256..eede570 100644 --- a/pglablib/PgTypeContainer.cpp +++ b/pglablib/PgTypeContainer.cpp @@ -1,5 +1,6 @@ #include "PgTypeContainer.h" #include "Pgsql_Connection.h" +#include "Pgsql_Col.h" #include //const PgType& PgTypeContainer::getTypeByOid(Oid oid) const @@ -29,7 +30,7 @@ std::string PgTypeContainer::getLoadQuery() const { return - "SELECT oid, typname, typnamespace, typowner, typlen, typbyval, typtype, typcategory, \n" + "SELECT oid, format_type(oid, NULL) AS name, typname, typnamespace, typowner, typlen, typbyval, typtype, typcategory, \n" " typispreferred, typisdefined, typdelim, typrelid, typelem, typarray, typinput, typoutput, \n" " typreceive, typsend, typmodin, typmodout, typanalyze, typalign, typstorage, typnotnull, \n" " typbasetype, typtypmod, typndims, typcollation, typdefaultbin, typdefault, typacl \n" @@ -38,37 +39,11 @@ std::string PgTypeContainer::getLoadQuery() const PgType PgTypeContainer::loadElem(const Pgsql::Row &row) { + Pgsql::Col col(row); PgType v; - v.oid << row.get(0); // InvalidOid; - v.name << row.get(1); //. operator QString(); // "name";"NO" - v.typnamespace << row.get(2); // InvalidOid;//"oid";"NO" - v.owner << row.get(3); // InvalidOid;//"oid";"NO" - v.len << row.get(4); // -1;//"smallint";"NO" - v.byval << row.get(5); // false;//"boolean";"NO" - v.type << row.get(6);//""char"";"NO" - v.category << row.get(7);//""char"";"NO" - v.ispreferred << row.get(8); //false;//"boolean";"NO" - v.isdefined << row.get(9); //false;//"boolean";"NO" - v.delim << row.get(10); //""char"";"NO" - v.relid << row.get(11); // InvalidOid;//"oid";"NO" - v.elem << row.get(12); // InvalidOid;//"oid";"NO" - v.array << row.get(13); // InvalidOid;//"oid";"NO" - v.input << row.get(14);//regproc";"NO" - v.output << row.get(15);//"regproc";"NO" - v.receive << row.get(16);//"regproc";"NO" - v.send << row.get(17);//"regproc";"NO" - v.modin << row.get(18);//"regproc";"NO" - v.modout << row.get(19);//"regproc";"NO" - v.analyze << row.get(20);//"regproc";"NO" - v.align << row.get(21); // //""char"";"NO" - v.storage << row.get(22); //""char"";"NO" - v.notnull << row.get(23); //"boolean";"NO" - v.basetype << row.get(24); //"oid";"NO" - v.typmod << row.get(25); //-1;//"integer";"NO" - v.ndims << row.get(26); //"integer";"NO" - v.collation << row.get(27); //InvalidOid;//"oid";"NO" - v.defaultbin << row.get(28);//"pg_node_tree";"YES" - v.typdefault << row.get(29);//"text";"YES" - v.acl << row.get(30);//"ARRAY";"YES" + col >> v.oid >> v.name >> v.typname >> v.typnamespace >> v.owner >> v.len >> v.byval >> v.type >> v.category + >> v.ispreferred >> v.isdefined >> v.delim >> v.relid >> v.elem >> v.array >> v.input >> v.output + >> v.receive >> v.send >> v.modin >> v.modout >> v.analyze >> v.align >> v.storage >> v.notnull + >> v.basetype >> v.typmod >> v.ndims >> v.collation >> v.defaultbin >> v.typdefault >> v.acl; return v; } diff --git a/pglablib/SqlFormattingUtils.cpp b/pglablib/SqlFormattingUtils.cpp index f326872..7df5fa5 100644 --- a/pglablib/SqlFormattingUtils.cpp +++ b/pglablib/SqlFormattingUtils.cpp @@ -227,6 +227,23 @@ QString quoteIdent(QString ident) } +QString dollarQuoteString(const QString &value) +{ + QString def_tag = "BODY"; + QString tag = QString("$%1$").arg(def_tag); + + int counter = 1; + while (value.indexOf(tag) >= 0) + tag = QString("$%1%2$").arg(def_tag, counter++); + + + return tag + + value + + tag; +} + + + QString genSchemaPrefix(const PgNamespace &ns) { QString str; diff --git a/pglablib/SqlFormattingUtils.h b/pglablib/SqlFormattingUtils.h index 3920cca..48b805f 100644 --- a/pglablib/SqlFormattingUtils.h +++ b/pglablib/SqlFormattingUtils.h @@ -13,6 +13,10 @@ QString escapeLiteral(const QString &input); bool identNeedsQuotes(QString ident); QString quoteIdent(QString ident); +/// Puts a string in dollar quote for passing in a query +/// the standard quotes are $BODY$ if the tag already exists in the string it will start numbering +QString dollarQuoteString(const QString &value); + QString genFQTableName(const PgDatabaseCatalog &catalog, const PgClass &cls); QString getDropConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint); diff --git a/pglablib/pglablib.pro b/pglablib/pglablib.pro index 76a9b21..ce2fa6f 100644 --- a/pglablib/pglablib.pro +++ b/pglablib/pglablib.pro @@ -155,3 +155,16 @@ else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsq else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/release/pgsql.lib else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/debug/pgsql.lib else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../pgsql/libpgsql.a + +win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../core/release/ -lcore +else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../core/debug/ -lcore +else:unix: LIBS += -L$$OUT_PWD/../core/ -lcore + +INCLUDEPATH += $$PWD/../core +DEPENDPATH += $$PWD/../core + +win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/libcore.a +else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/libcore.a +else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/core.lib +else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/core.lib +else:unix: PRE_TARGETDEPS += $$OUT_PWD/../core/libcore.a