diff --git a/pgadmin/dlg/dlgProperty.cpp b/pgadmin/dlg/dlgProperty.cpp index ece5ea3..c25699c 100644 --- a/pgadmin/dlg/dlgProperty.cpp +++ b/pgadmin/dlg/dlgProperty.cpp @@ -1012,11 +1012,11 @@ void dlgProperty::InitDialog(frmMain *frame, pgObject *node) case PGM_FOREIGNKEY: case PGM_INDEX: case PGM_PRIMARYKEY: - case PGM_TRIGGER: case PGM_UNIQUE: owneritem=node->GetTable()->GetId(); break; + case PGM_TRIGGER: case PGM_RULE: // Rules are technically table objects! Yeuch case EDB_PACKAGEFUNCTION: case EDB_PACKAGEVARIABLE: diff --git a/pgadmin/dlg/dlgTrigger.cpp b/pgadmin/dlg/dlgTrigger.cpp index 3661d5b..65e89f4 100644 --- a/pgadmin/dlg/dlgTrigger.cpp +++ b/pgadmin/dlg/dlgTrigger.cpp @@ -66,14 +66,13 @@ dlgProperty *pgTriggerFactory::CreateDialog(frmMain *frame, pgObject *node, pgOb } - - dlgTrigger::dlgTrigger(pgaFactory *f, frmMain *frame, pgTrigger *node, pgTable *parentNode) : dlgCollistProperty(f, frame, wxT("dlgTrigger"), parentNode) { trigger=node; table=parentNode; - wxASSERT(!table || table->GetMetaType() == PGM_TABLE || table->GetMetaType() == GP_PARTITION); + wxASSERT(!table || table->GetMetaType() == PGM_TABLE || table->GetMetaType() == PGM_VIEW + || table->GetMetaType() == GP_PARTITION); bool bVal; settings->Read(wxT("frmQuery/ShowLineNumber"), &bVal, false); @@ -120,7 +119,12 @@ int dlgTrigger::Go(bool modal) chkUpdate->SetValue((trigger->GetTriggerType() & TRIGGER_TYPE_UPDATE) != 0); chkDelete->SetValue((trigger->GetTriggerType() & TRIGGER_TYPE_DELETE) != 0); chkTruncate->SetValue((trigger->GetTriggerType() & TRIGGER_TYPE_TRUNCATE) != 0); - rdbFires->SetSelection(trigger->GetTriggerType() & TRIGGER_TYPE_BEFORE ? 0 : 1); + if (trigger->GetTriggerType() & TRIGGER_TYPE_BEFORE) + rdbFires->SetSelection(0); + else if (trigger->GetTriggerType() & TRIGGER_TYPE_INSTEAD) + rdbFires->SetSelection(2); + else + rdbFires->SetSelection(1); txtArguments->SetValue(trigger->GetArguments()); txtWhen->SetValue(trigger->GetWhen()); if (!connection->BackendMinimumVersion(7, 4)) @@ -196,6 +200,8 @@ int dlgTrigger::Go(bool modal) if (!connection->BackendMinimumVersion(8, 4)) chkTruncate->Disable(); + if (!connection->BackendMinimumVersion(9, 1) || table->GetMetaType() != PGM_VIEW) + rdbFires->Enable(2, false); } cbColumns->Disable(); @@ -259,15 +265,17 @@ wxString dlgTrigger::GetSql() chkUpdate->GetValue() != (trigger->GetTriggerType() & TRIGGER_TYPE_UPDATE ? true : false) || chkDelete->GetValue() != (trigger->GetTriggerType() & TRIGGER_TYPE_DELETE ? true : false) || chkTruncate->GetValue() != (trigger->GetTriggerType() & TRIGGER_TYPE_TRUNCATE ? true : false) || - rdbFires->GetSelection() != (trigger->GetTriggerType() & TRIGGER_TYPE_BEFORE ? 0 : 1)) + rdbFires->GetSelection() != (trigger->GetTriggerType() & TRIGGER_TYPE_BEFORE ? 0 : TRIGGER_TYPE_INSTEAD ? 2 : 1)) { if (cbFunction->GetValue() == wxString::Format(wxT("<%s>"), _("Inline EDB-SPL"))) sql += wxT("CREATE OR REPLACE TRIGGER ") + qtIdent(name); else sql += wxT("CREATE TRIGGER ") + qtIdent(name); - if (rdbFires->GetSelection()) + if (rdbFires->GetSelection() == 1) sql += wxT(" AFTER"); + else if (rdbFires->GetSelection() == 2) + sql += wxT(" INSTEAD OF"); else sql += wxT(" BEFORE"); int actionCount=0; @@ -400,14 +408,14 @@ void dlgTrigger::CheckChange() wxString name=GetName(); // We can only have per-statement TRUNCATE triggers - if (connection->BackendMinimumVersion(8, 4)) + if (trigger || connection->BackendMinimumVersion(8, 4)) { if (chkRow->GetValue()) { chkTruncate->Disable(); chkTruncate->SetValue(false); } - else + else if (connection->EdbMinimumVersion(8,0)) chkTruncate->Enable(); } @@ -432,7 +440,7 @@ void dlgTrigger::CheckChange() chkUpdate->GetValue() != (trigger->GetTriggerType() & TRIGGER_TYPE_UPDATE ? true : false) || chkDelete->GetValue() != (trigger->GetTriggerType() & TRIGGER_TYPE_DELETE ? true : false) || chkTruncate->GetValue() != (trigger->GetTriggerType() & TRIGGER_TYPE_TRUNCATE ? true : false) || - rdbFires->GetSelection() != (trigger->GetTriggerType() & TRIGGER_TYPE_BEFORE ? 0 : 1))); + rdbFires->GetSelection() != (trigger->GetTriggerType() & TRIGGER_TYPE_BEFORE ? 0 : (trigger->GetTriggerType() & TRIGGER_TYPE_INSTEAD ? 2 : 1)))); } else { diff --git a/pgadmin/include/schema/pgTrigger.h b/pgadmin/include/schema/pgTrigger.h index 8e6c9b5..5412473 100644 --- a/pgadmin/include/schema/pgTrigger.h +++ b/pgadmin/include/schema/pgTrigger.h @@ -16,7 +16,22 @@ class pgFunction; -class pgTriggerFactory : public pgTableObjFactory +class pgTriggerObject : public pgSchemaObject +{ +public: + pgTriggerObject(pgSchema *newSchema, pgaFactory &factory, const wxString& newName=wxEmptyString) : pgSchemaObject(newSchema, factory, newName) {} + + wxString GetFormattedDefinition(); + wxString GetDefinition() const { return definition; } + void iSetDefinition(const wxString& s) { definition=s; } + +protected: + wxString definition; +}; + + + +class pgTriggerFactory : public pgSchemaObjFactory { public: pgTriggerFactory(); @@ -26,10 +41,10 @@ public: extern pgTriggerFactory triggerFactory; -class pgTrigger : public pgTableObject +class pgTrigger : public pgTriggerObject { public: - pgTrigger(pgTable *newTable, const wxString& newName = wxT("")); + pgTrigger(pgSchema *newSchema, const wxString& newName = wxT("")); ~pgTrigger(); wxString GetTranslatedMessage(int kindOfMessage) const; @@ -64,6 +79,8 @@ public: wxArrayString GetColumnList() const { return columnList; } long GetColumnCount() const { return columnCount; } void iSetColumnCount(const long l) { columnCount=l; } + void iSetParentIsTable(const bool b) { parentistable=b; } + bool GetParentIsTable() { return parentistable; } void SetDirty(); @@ -87,12 +104,12 @@ private: long columnCount; OID functionOid; long triggerType; - bool enabled; + bool enabled, parentistable; pgFunction *triggerFunction; }; -class pgTriggerCollection : public pgTableObjCollection +class pgTriggerCollection : public pgSchemaObjCollection { public: pgTriggerCollection(pgaFactory *factory, pgSchema *sch); diff --git a/pgadmin/include/schema/pgView.h b/pgadmin/include/schema/pgView.h index 0863374..9704a7d 100644 --- a/pgadmin/include/schema/pgView.h +++ b/pgadmin/include/schema/pgView.h @@ -37,6 +37,7 @@ public: bool CanDropCascaded() { return !GetSystemObject() && pgSchemaObject::CanDrop(); } bool DropObject(wxFrame *frame, ctlTree *browser, bool cascaded); + bool CanCreate() { return GetSchema()->CanCreate(); } bool CanView() { return true; } bool WantDummyChild() { return true; } diff --git a/pgadmin/include/utils/pgDefs.h b/pgadmin/include/utils/pgDefs.h index bd55d06..f26d4c5 100644 --- a/pgadmin/include/utils/pgDefs.h +++ b/pgadmin/include/utils/pgDefs.h @@ -71,5 +71,6 @@ #define TRIGGER_TYPE_DELETE (1 << 3) #define TRIGGER_TYPE_UPDATE (1 << 4) #define TRIGGER_TYPE_TRUNCATE (1 << 5) +#define TRIGGER_TYPE_INSTEAD (1 << 6) #endif diff --git a/pgadmin/schema/pgObject.cpp b/pgadmin/schema/pgObject.cpp index 314a2e8..f61aa6b 100644 --- a/pgadmin/schema/pgObject.cpp +++ b/pgadmin/schema/pgObject.cpp @@ -1311,7 +1311,6 @@ void pgSchemaObject::SetSchema(pgSchema *newSchema) void pgSchemaObject::UpdateSchema(ctlTree *browser, OID schemaOid) { // used e.g. for triggers that use trigger functions from other namespaces - if (!browser) return; diff --git a/pgadmin/schema/pgRule.cpp b/pgadmin/schema/pgRule.cpp index 747f869..60d7af8 100644 --- a/pgadmin/schema/pgRule.cpp +++ b/pgadmin/schema/pgRule.cpp @@ -200,7 +200,8 @@ pgObject *pgRuleFactory::CreateObjects(pgCollection *collection, ctlTree *browse { while (!rules->Eof()) { - rule = new pgRule(collection->GetSchema(), rules->GetVal(wxT("rulename"))); + // Be careful that the schema of a rule (and a trigger) is the schema of the schema + rule = new pgRule(collection->GetSchema()->GetSchema(), rules->GetVal(wxT("rulename"))); rule->iSetOid(rules->GetOid(wxT("oid"))); rule->iSetComment(rules->GetVal(wxT("description"))); diff --git a/pgadmin/schema/pgTrigger.cpp b/pgadmin/schema/pgTrigger.cpp index 222e248..e162be0 100644 --- a/pgadmin/schema/pgTrigger.cpp +++ b/pgadmin/schema/pgTrigger.cpp @@ -22,8 +22,8 @@ #include "schema/pgFunction.h" -pgTrigger::pgTrigger(pgTable *newTable, const wxString& newName) -: pgTableObject(newTable, triggerFactory, newName) +pgTrigger::pgTrigger(pgSchema *newSchema, const wxString& newName) +: pgTriggerObject(newSchema, triggerFactory, newName) { triggerFunction=0; } @@ -195,7 +195,15 @@ wxString pgTrigger::GetSql(ctlTree *browser) wxString pgTrigger::GetFireWhen() const { - return (triggerType & TRIGGER_TYPE_BEFORE) ? wxT("BEFORE") : wxT("AFTER"); + wxString when = wxEmptyString; + + if (triggerType & TRIGGER_TYPE_BEFORE) + when = wxT("BEFORE"); + else if (triggerType & TRIGGER_TYPE_INSTEAD) + when = wxT("INSTEAD OF"); + else + when = wxT("AFTER"); + return when; } @@ -348,11 +356,12 @@ pgObject *pgTrigger::Refresh(ctlTree *browser, const wxTreeItemId item) pgObject *pgTriggerFactory::CreateObjects(pgCollection *coll, ctlTree *browser, const wxString &restriction) { - pgTableObjCollection *collection=(pgTableObjCollection*)coll; + pgSchemaObjCollection *collection=(pgSchemaObjCollection*)coll; pgTrigger *trigger=0; wxString trig_sql; - trig_sql = wxT("SELECT t.oid, t.xmin, t.*, relname, nspname, des.description, l.lanname, p.prosrc, \n") + trig_sql = wxT("SELECT t.oid, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, ") + wxT(" nspname, des.description, l.lanname, p.prosrc, \n") wxT(" trim(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'), '()') AS whenclause\n") wxT(" FROM pg_trigger t\n") wxT(" JOIN pg_class cl ON cl.oid=tgrelid\n") @@ -376,7 +385,8 @@ pgObject *pgTriggerFactory::CreateObjects(pgCollection *coll, ctlTree *browser, { while (!triggers->Eof()) { - trigger = new pgTrigger(collection->GetTable(), triggers->GetVal(wxT("tgname"))); + // Be careful that the schema of a trigger (and a rule) is the schema of the schema + trigger = new pgTrigger(collection->GetSchema()->GetSchema(), triggers->GetVal(wxT("tgname"))); trigger->iSetOid(triggers->GetOid(wxT("oid"))); trigger->iSetXid(triggers->GetOid(wxT("xmin"))); @@ -394,6 +404,8 @@ pgObject *pgTriggerFactory::CreateObjects(pgCollection *coll, ctlTree *browser, trigger->iSetEnabled(triggers->GetBool(wxT("tgenabled"))); trigger->iSetTriggerType(triggers->GetLong(wxT("tgtype"))); + trigger->iSetParentIsTable(triggers->GetBool(wxT("parentistable"))); + trigger->iSetLanguage(triggers->GetVal(wxT("lanname"))); trigger->iSetSource(triggers->GetVal(wxT("prosrc"))); trigger->iSetQuotedFullTable(collection->GetDatabase()->GetQuotedSchemaPrefix(triggers->GetVal(wxT("nspname"))) + qtIdent(triggers->GetVal(wxT("relname")))); @@ -472,7 +484,7 @@ wxString pgTriggerCollection::GetTranslatedMessage(int kindOfMessage) const #include "images/triggers.xpm" pgTriggerFactory::pgTriggerFactory() -: pgTableObjFactory(__("Trigger"), __("New Trigger..."), __("Create a new Trigger."), trigger_xpm) +: pgSchemaObjFactory(__("Trigger"), __("New Trigger..."), __("Create a new Trigger."), trigger_xpm) { metaType = PGM_TRIGGER; } @@ -503,7 +515,8 @@ wxWindow *enabledisableTriggerFactory::StartDialog(frmMain *form, pgObject *obj) bool enabledisableTriggerFactory::CheckEnable(pgObject *obj) { return obj && obj->IsCreatedBy(triggerFactory) && obj->CanEdit() - && ((pgTrigger*)obj)->GetConnection()->BackendMinimumVersion(8, 1); + && ((pgTrigger*)obj)->GetConnection()->BackendMinimumVersion(8, 1) + && ((pgTrigger*)obj)->GetParentIsTable(); } bool enabledisableTriggerFactory::CheckChecked(pgObject *obj) diff --git a/pgadmin/schema/pgView.cpp b/pgadmin/schema/pgView.cpp index f97466f..33272f2 100644 --- a/pgadmin/schema/pgView.cpp +++ b/pgadmin/schema/pgView.cpp @@ -18,6 +18,7 @@ #include "schema/pgColumn.h" #include "schema/pgView.h" #include "frm/frmHint.h" +#include "schema/pgTrigger.h" pgView::pgView(pgSchema *newSchema, const wxString& newName) @@ -107,8 +108,10 @@ wxMenu *pgView::GetNewMenu() { wxMenu *menu=pgObject::GetNewMenu(); if (schema->GetCreatePrivilege()) + { ruleFactory.AppendMenu(menu); - + triggerFactory.AppendMenu(menu); + } return menu; } @@ -172,6 +175,7 @@ wxString pgView::GetSql(ctlTree *browser) } AppendStuff(sql, browser, ruleFactory); + AppendStuff(sql, browser, triggerFactory); } return sql; } @@ -280,6 +284,8 @@ void pgView::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *proper hasDeleteRule = true; } + if (GetConnection()->BackendMinimumVersion(9, 1)) + browser->AppendCollection(this, triggerFactory); } if (properties) { diff --git a/pgadmin/ui/dlgTrigger.xrc b/pgadmin/ui/dlgTrigger.xrc index 7af64e9..091803c 100644 --- a/pgadmin/ui/dlgTrigger.xrc +++ b/pgadmin/ui/dlgTrigger.xrc @@ -104,6 +104,7 @@ BEFORE AFTER + INSTEAD OF 0 1