Added listing of triggers for selected table (not completely finished).
Used slightly different approach. This tab is fully build in source code using subclasses to adjust behaviour of widgets for reuse in the other tabs. Uses custom proxy model for filtering triggers for correct table and supporting out of the box sorting by QTableView. SqlCodePreview: QPlainTextEditor which sql highlighter and in readonly mode but allows copy.
This commit is contained in:
parent
446923ebaf
commit
2a75e86102
23 changed files with 697 additions and 67 deletions
|
|
@ -10,6 +10,7 @@
|
|||
#include "PgIndexContainer.h"
|
||||
#include "PgNamespaceContainer.h"
|
||||
#include "PgTablespaceContainer.h"
|
||||
#include "PgTriggerContainer.h"
|
||||
#include "PgTypeContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_oids.h"
|
||||
|
|
@ -134,7 +135,7 @@ void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn,
|
|||
std::function<bool(int, int)> progress_callback)
|
||||
{
|
||||
loadInfo(conn);
|
||||
const int count = 11;
|
||||
const int count = 12;
|
||||
int n = 0;
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
|
|
@ -163,10 +164,15 @@ void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn,
|
|||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_ams, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_triggers, conn);
|
||||
if (progress_callback && !progress_callback(++n, count))
|
||||
return;
|
||||
load2(m_types, conn);
|
||||
progress_callback && progress_callback(++n, count);
|
||||
|
||||
refreshed(this, All);
|
||||
}
|
||||
|
||||
void PgDatabaseCatalog::loadInfo(Pgsql::Connection &conn)
|
||||
|
|
@ -260,6 +266,11 @@ std::shared_ptr<const PgTablespaceContainer> PgDatabaseCatalog::tablespaces() co
|
|||
return m_tablespaces;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgTriggerContainer> PgDatabaseCatalog::triggers() const
|
||||
{
|
||||
return m_triggers;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgTypeContainer> PgDatabaseCatalog::types() const
|
||||
{
|
||||
return m_types;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
#define PGSQLDATABASECATALOGUE_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -22,9 +24,11 @@ class PgIndexContainer;
|
|||
class PgNamespaceContainer;
|
||||
class PgAmContainer;
|
||||
class PgTablespaceContainer;
|
||||
class PgTriggerContainer;
|
||||
class PgTypeContainer;
|
||||
|
||||
class PgDatabaseCatalog: public std::enable_shared_from_this<PgDatabaseCatalog> {
|
||||
class PgDatabaseCatalog: public QObject, public std::enable_shared_from_this<PgDatabaseCatalog> {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PgDatabaseCatalog();
|
||||
PgDatabaseCatalog(const PgDatabaseCatalog&) = delete;
|
||||
|
|
@ -49,8 +53,27 @@ public:
|
|||
std::shared_ptr<const PgAmContainer> ams() const;
|
||||
std::shared_ptr<const PgNamespaceContainer> namespaces() const;
|
||||
std::shared_ptr<const PgTablespaceContainer> tablespaces() const;
|
||||
std::shared_ptr<const PgTriggerContainer> triggers() const;
|
||||
std::shared_ptr<const PgTypeContainer> types() const;
|
||||
|
||||
enum RefreshFlag {
|
||||
Attributes = 1,
|
||||
AuthIds = (1 << 1),
|
||||
Classes = (1 << 2),
|
||||
Constraints = (1 << 3),
|
||||
Databases = (1 << 4),
|
||||
Indexes = (1 << 5),
|
||||
Ams = (1 << 6),
|
||||
Namespaces = (1 << 7),
|
||||
Tablespaces = (1 << 8),
|
||||
Triggers = (1 << 9),
|
||||
Types = (1 << 10),
|
||||
All = 0xffffffff
|
||||
};
|
||||
using RefreshFlags = int;
|
||||
|
||||
signals:
|
||||
void refreshed(const PgDatabaseCatalog *catalog, RefreshFlags flags);
|
||||
private:
|
||||
QString m_serverVersionString;
|
||||
int m_serverVersion;
|
||||
|
|
@ -65,6 +88,7 @@ private:
|
|||
std::shared_ptr<PgAmContainer> m_ams;
|
||||
std::shared_ptr<PgNamespaceContainer> m_namespaces;
|
||||
std::shared_ptr<PgTablespaceContainer> m_tablespaces;
|
||||
std::shared_ptr<PgTriggerContainer> m_triggers;
|
||||
std::shared_ptr<PgTypeContainer> m_types;
|
||||
|
||||
template <typename T>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,126 @@
|
|||
#include "PgTrigger.h"
|
||||
#include "PgTrigger.h"
|
||||
#include "PgClassContainer.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "SqlFormattingUtils.h"
|
||||
#include <QStringBuilder>
|
||||
|
||||
PgTrigger::PgTrigger()
|
||||
|
||||
QString PgTrigger::dropSql(const PgDatabaseCatalog &catalog)
|
||||
{
|
||||
|
||||
if (m_dropSql.isEmpty()) {
|
||||
auto&& fqtablename = genFQTableName(catalog, catalog.classes()->getByKey(relid));
|
||||
m_dropSql = "DROP TRIGGER " % quoteIdent(name)
|
||||
% " ON " % fqtablename % ";";
|
||||
}
|
||||
return m_dropSql;
|
||||
}
|
||||
|
||||
QString PgTrigger::createSql(const PgDatabaseCatalog &catalog)
|
||||
{
|
||||
if (m_createSql.isEmpty()) {
|
||||
auto&& fqtablename = genFQTableName(catalog, catalog.classes()->getByKey(relid));
|
||||
// if (GetLanguage() == wxT("edbspl"))
|
||||
// sql += wxT("CREATE OR REPLACE TRIGGER ");
|
||||
// else if (GetConnection()->BackendMinimumVersion(8, 2) && GetIsConstraint())
|
||||
if (constraint != InvalidOid)
|
||||
m_createSql += "CREATE CONSTRAINT TRIGGER ";
|
||||
else
|
||||
m_createSql += "CREATE TRIGGER ";
|
||||
|
||||
m_createSql += quoteIdent(name) + "\n "
|
||||
+ typeFireWhen()
|
||||
+ " " + event();
|
||||
|
||||
m_createSql += "\n ON " + fqtablename;
|
||||
if (deferrable) {
|
||||
m_createSql += "\n DEFERRABLE INITIALLY ";
|
||||
if (initdeferred)
|
||||
m_createSql += "DEFERRED";
|
||||
else
|
||||
m_createSql += "IMMEDIATE";
|
||||
}
|
||||
m_createSql += "\n FOR EACH " + forEach();
|
||||
|
||||
// if (GetConnection()->BackendMinimumVersion(8, 5)
|
||||
// && !GetWhen().IsEmpty())
|
||||
// sql += wxT("\n WHEN (") + GetWhen() + wxT(")");
|
||||
|
||||
// if (GetLanguage() == wxT("edbspl"))
|
||||
// {
|
||||
// sql += wxT("\n") + GetSource();
|
||||
// if (!sql.Trim().EndsWith(wxT(";")))
|
||||
// sql = sql.Trim() + wxT(";");
|
||||
// sql += wxT("\n");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// sql += wxT("\n EXECUTE PROCEDURE ") + triggerFunction->GetQuotedFullIdentifier()
|
||||
// + wxT("(") + GetArguments() + wxT(")")
|
||||
// + wxT(";\n");
|
||||
// }
|
||||
|
||||
// if (!GetEnabled())
|
||||
// {
|
||||
// sql += wxT("ALTER TABLE ") + GetQuotedFullTable() + wxT(" ")
|
||||
// + wxT("DISABLE TRIGGER ") + GetQuotedIdentifier() + wxT(";\n");
|
||||
// }
|
||||
|
||||
// if (!GetComment().IsEmpty())
|
||||
// sql += wxT("COMMENT ON TRIGGER ") + GetQuotedIdentifier() + wxT(" ON ") + GetQuotedFullTable()
|
||||
// + wxT(" IS ") + qtDbString(GetComment()) + wxT(";\n");
|
||||
}
|
||||
|
||||
return m_createSql;
|
||||
}
|
||||
|
||||
|
||||
QString PgTrigger::typeFireWhen() const
|
||||
{
|
||||
QString when;
|
||||
|
||||
if (type & TriggerTypeBefore)
|
||||
when = "BEFORE";
|
||||
else if (type & TriggerTypeInstead)
|
||||
when = "INSTEAD OF";
|
||||
else
|
||||
when = "AFTER";
|
||||
return when;
|
||||
}
|
||||
|
||||
|
||||
QString PgTrigger::eventAbbr() const
|
||||
{
|
||||
QString event;
|
||||
if (type & TriggerTypeInsert)
|
||||
event += "I";
|
||||
if (type & TriggerTypeUpdate)
|
||||
event += "U";
|
||||
if (type & TriggerTypeDelete)
|
||||
event += "D";
|
||||
if (type & TriggerTypeTruncate)
|
||||
event += "T";
|
||||
return event;
|
||||
}
|
||||
|
||||
QString PgTrigger::event() const
|
||||
{
|
||||
QString event;
|
||||
if (type & TriggerTypeInsert)
|
||||
event += "INSERT ";
|
||||
if (type & TriggerTypeUpdate)
|
||||
event += "UPDATE ";
|
||||
if (type & TriggerTypeDelete)
|
||||
event += "DELETE ";
|
||||
if (type & TriggerTypeTruncate)
|
||||
event += "TRUNCATE";
|
||||
return event.trimmed();
|
||||
}
|
||||
|
||||
QString PgTrigger::forEach() const
|
||||
{
|
||||
if (isRow())
|
||||
return "ROW";
|
||||
else
|
||||
return "STATEMENT";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,24 +5,57 @@
|
|||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class PgTrigger {
|
||||
public:
|
||||
Oid tgrelid;
|
||||
QString tgname;
|
||||
Oid tgfoid;
|
||||
int16_t tgtype;
|
||||
char tgenabled;
|
||||
bool tgisinternal;
|
||||
Oid tgconstrrelid;
|
||||
Oid tgconstrindid;
|
||||
Oid tgconstraint;
|
||||
bool tgdeferrable;
|
||||
bool tginitdeferred;
|
||||
int16_t tgnargs;
|
||||
QString tgattr;
|
||||
QString tgargs;
|
||||
QString tgqual;
|
||||
Oid oid = InvalidOid;
|
||||
Oid relid;
|
||||
QString name;
|
||||
Oid foid;
|
||||
int16_t type;
|
||||
char enabled;
|
||||
bool isinternal;
|
||||
Oid constrrelid;
|
||||
Oid constrindid;
|
||||
Oid constraint;
|
||||
bool deferrable;
|
||||
bool initdeferred;
|
||||
int16_t nargs;
|
||||
QString attr;
|
||||
QString args;
|
||||
QString qual;
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgTrigger &rhs) const { return oid < rhs.oid; }
|
||||
|
||||
static constexpr int TriggerTypeRow = (1 << 0);
|
||||
static constexpr int TriggerTypeBefore = (1 << 1);
|
||||
static constexpr int TriggerTypeInsert = (1 << 2);
|
||||
static constexpr int TriggerTypeDelete = (1 << 3);
|
||||
static constexpr int TriggerTypeUpdate = (1 << 4);
|
||||
static constexpr int TriggerTypeTruncate = (1 << 5);
|
||||
static constexpr int TriggerTypeInstead = (1 << 6);
|
||||
|
||||
QString dropSql(const PgDatabaseCatalog &catalog);
|
||||
QString createSql(const PgDatabaseCatalog &catalog);
|
||||
bool isRow() const { return type & TriggerTypeRow; }
|
||||
bool isBefore() const { return type & TriggerTypeBefore; }
|
||||
QString typeFireWhen() const;
|
||||
QString eventAbbr() const;
|
||||
QString event() const;
|
||||
QString forEach() const;
|
||||
|
||||
//wxString pgTrigger::GetForEach() const
|
||||
//{
|
||||
// return (triggerType & TRIGGER_TYPE_ROW) ? wxT("ROW") : wxT("STATEMENT");
|
||||
//}
|
||||
|
||||
private:
|
||||
mutable QString m_dropSql; // cache
|
||||
mutable QString m_createSql; // cache
|
||||
};
|
||||
|
||||
#endif // PGTRIGGER_H
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
#include "PgTriggerContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
std::string PgTriggerContainer::getLoadQuery() const
|
||||
{
|
||||
return R"(SELECT *
|
||||
return R"(SELECT oid, *
|
||||
FROM pg_trigger
|
||||
WHERE NOT tgisinternal)";
|
||||
}
|
||||
|
|
@ -14,8 +15,19 @@ PgTrigger PgTriggerContainer::loadElem(const Pgsql::Row &row)
|
|||
{
|
||||
Pgsql::Col col(row);
|
||||
PgTrigger v;
|
||||
col >> v.tgrelid >> v.tgname >> v.tgfoid >> v.tgtype >> v.tgenabled >> v.tgisinternal >> v.tgconstrrelid
|
||||
>> v.tgconstrindid >> v.tgconstraint >> v.tgdeferrable >> v.tginitdeferred >> v.tgnargs >> v.tgattr
|
||||
>> v.tgargs >> v.tgqual;
|
||||
col >> v.oid >> v.relid >> v.name >> v.foid >> v.type >> v.enabled >> v.isinternal >> v.constrrelid
|
||||
>> v.constrindid >> v.constraint >> v.deferrable >> v.initdeferred >> v.nargs >> v.attr
|
||||
>> v.args >> v.qual;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
std::vector<PgTrigger> PgTriggerContainer::getTriggersForRelation(Oid cls) const
|
||||
{
|
||||
std::vector<PgTrigger> result;
|
||||
for (auto e : m_container)
|
||||
if (e.relid == cls)
|
||||
result.push_back(e);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "PgContainer.h"
|
||||
#include "PgTrigger.h"
|
||||
#include <vector>
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
|
|
@ -16,6 +17,8 @@ public:
|
|||
using PgContainer<PgTrigger>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
|
||||
std::vector<PgTrigger> getTriggersForRelation(Oid cls) const;
|
||||
protected:
|
||||
PgTrigger loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue