Le 24/10/2010 00:18, Dave Page a écrit :
> [Ashesh, if you haven't aready, I suggest reviewing this thread. It
> may shed some light on that Rule weirdness on Solaris]
> 
> On Sat, Oct 23, 2010 at 11:03 PM, Guillaume Lelarge
> <[email protected]> wrote:
>>> pgView derives from pgSchemaObject
>>
>> Actually, pgView derives from pgRuleObject, which is already weird by
>> itself but makes the whole thing even more weird.
> 
> Oh, I misread that. pgView*Factory* derives from pgSchemaObj*Factory*.
> Which seems bizarre.
> 
>>> pgColumn derives from pgTableObject
>>
>> Seems logical.
>>
>>> and:
>>>
>>> pgRule derives from pgRuleObject
>>> pgRuleObject derives from pgSchemaObject
>>
>> Which just doesn't make sense. I would really like to know the reason of
>> all this.
> 
> I think the point is, that pgRule can't be a descendent of a table or
> a view (in the inheritance hierarchy), because it is a descendent of
> both (logically).
> 
>>> My guess is to do this properly you'll probably have to create a
>>> similar pgTriggerObject class (or make pgRuleObject into a more
>>> generic pgRelationObject), and then add properties to represent the
>>> table/view directly to pgTrigger and re-parent it appropriately.
>>
>> Will look into this.
>>
>> Thanks for your remarks. I hope to come up with something. We'll
>> probably need someone more knowledgable than me with C++.
> 
> I don't think it needs "more C++ knowledge", just some patience to
> untangle things. Do you know of any tools that can automatically
> visually display the object model and members? I'm sure there used to
> be something in Visual Studio, but I can't find it atm.
> 

Some patience, yeah, I did use that :)

New patch attached. Works good for me.


-- 
Guillaume
 http://www.postgresql.fr
 http://dalibo.com
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 @@
                     <content>
                       <item>BEFORE</item>
                       <item>AFTER</item>
+                      <item>INSTEAD OF</item>
                     </content>
                     <selection>0</selection>
                     <dimension>1</dimension>
-- 
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers

Reply via email to