]> granicus.if.org Git - postgresql/commitdiff
Changes pg_trigger and extend pg_rewrite in order to allow triggers and
authorJan Wieck <JanWieck@Yahoo.com>
Mon, 19 Mar 2007 23:38:32 +0000 (23:38 +0000)
committerJan Wieck <JanWieck@Yahoo.com>
Mon, 19 Mar 2007 23:38:32 +0000 (23:38 +0000)
rules to be defined with different, per session controllable, behaviors
for replication purposes.

This will allow replication systems like Slony-I and, as has been stated
on pgsql-hackers, other products to control the firing mechanism of
triggers and rewrite rules without modifying the system catalog directly.

The firing mechanisms are controlled by a new superuser-only GUC
variable, session_replication_role, together with a change to
pg_trigger.tgenabled and a new column pg_rewrite.ev_enabled. Both
columns are a single char data type now (tgenabled was a bool before).
The possible values in these attributes are:

     'O' - Trigger/Rule fires when session_replication_role is "origin"
           (default) or "local". This is the default behavior.

     'D' - Trigger/Rule is disabled and fires never

     'A' - Trigger/Rule fires always regardless of the setting of
           session_replication_role

     'R' - Trigger/Rule fires when session_replication_role is "replica"

The GUC variable can only be changed as long as the system does not have
any cached query plans. This will prevent changing the session role and
accidentally executing stored procedures or functions that have plans
cached that expand to the wrong query set due to differences in the rule
firing semantics.

The SQL syntax for changing a triggers/rules firing semantics is

     ALTER TABLE <tabname> <when> TRIGGER|RULE <name>;

     <when> ::= ENABLE | ENABLE ALWAYS | ENABLE REPLICA | DISABLE

psql's \d command as well as pg_dump are extended in a backward
compatible fashion.

Jan

24 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/config.sgml
doc/src/sgml/ref/alter_table.sgml
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/rewrite/rewriteDefine.c
src/backend/rewrite/rewriteHandler.c
src/backend/utils/cache/plancache.c
src/backend/utils/cache/relcache.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/psql/describe.c
src/include/catalog/pg_rewrite.h
src/include/catalog/pg_trigger.h
src/include/commands/trigger.h
src/include/nodes/parsenodes.h
src/include/rewrite/prs2lock.h
src/include/rewrite/rewriteDefine.h
src/include/utils/plancache.h
src/include/utils/rel.h

index 9a9f9b55bef5378e34f297aae5fde5b4b5e4c03e..31db6521c5efc270a99a12f960292046faf94cda 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.145 2007/02/14 01:58:55 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.146 2007/03/19 23:38:28 wieck Exp $ -->
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
  -->
       </entry>
      </row>
 
+     <row>
+      <entry><structfield>ev_enabled</structfield></entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>
+          Controls in which <xref linkend="guc-session-replication-role"> modes
+          the rule fires.
+          <literal>O</> = rule fires in <quote>origin</> and <quote>local</> modes,
+          <literal>D</> = rule is disabled,
+          <literal>R</> = rule fires in <quote>replica</> mode,
+          <literal>A</> = rule fires always.
+         </entry>
+     </row>
+
      <row>
       <entry><structfield>is_instead</structfield></entry>
       <entry><type>bool</type></entry>
 
      <row>
       <entry><structfield>tgenabled</structfield></entry>
-      <entry><type>bool</type></entry>
+      <entry><type>char</type></entry>
       <entry></entry>
-      <entry>True if trigger is enabled</entry>
+      <entry>
+          Controls in which <xref linkend="guc-session-replication-role"> modes
+          the trigger fires.
+          <literal>O</> = trigger fires in <quote>origin</> and <quote>local</> modes,
+          <literal>D</> = trigger is disabled,
+          <literal>R</> = trigger fires in <quote>replica</> mode,
+          <literal>A</> = trigger fires always.
+         </entry>
      </row>
 
      <row>
index 17504b3d5e8a00aa358303284b92dd89ad6da16d..1fe39db2af7db0cad0759d29d6dfca043f4dfca9 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.115 2007/03/06 02:06:12 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.116 2007/03/19 23:38:28 wieck Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -3523,6 +3523,23 @@ SELECT * FROM parent WHERE key = 2400;
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-session-replication-role" xreflabel="session_replication_role">
+      <term><varname>session_replication_role</varname> (<type>string</type>)</term>
+      <indexterm>
+       <primary><varname>session_replication_role</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+               Controls the trigger and rule firing for the current session.
+               See <xref linkend="sql-altertable"> for the different options to
+               enable or disable triggers and rules. Setting the variable requires
+               superuser privilege and can only be done before any query plans have
+               been cached. Possible values are <literal>origin</>,
+               <literal>replica</> and <literal>local</>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-vacuum-freeze-min-age" xreflabel="vacuum_freeze_min_age">
       <term><varname>vacuum_freeze_min_age</varname> (<type>integer</type>)</term>
       <indexterm>
index 6ff289b21a40910e8f86c63d177f5a5aa49b1f14..9b34c4fb9934f3f60d2f99a963785e0efd79369a 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.94 2007/02/01 00:28:18 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.95 2007/03/19 23:38:29 wieck Exp $
 PostgreSQL documentation
 -->
 
@@ -43,6 +43,12 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
     DROP CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
     DISABLE TRIGGER [ <replaceable class="PARAMETER">trigger_name</replaceable> | ALL | USER ]
     ENABLE TRIGGER [ <replaceable class="PARAMETER">trigger_name</replaceable> | ALL | USER ]
+    ENABLE REPLICA TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable>
+    ENABLE ALWAYS TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable>
+    DISABLE RULE <replaceable class="PARAMETER">rewrite_rule_name</replaceable>
+    ENABLE RULE <replaceable class="PARAMETER">rewrite_rule_name</replaceable>
+    ENABLE REPLICA RULE <replaceable class="PARAMETER">rewrite_rule_name</replaceable>
+    ENABLE ALWAYS RULE <replaceable class="PARAMETER">rewrite_rule_name</replaceable>
     CLUSTER ON <replaceable class="PARAMETER">index_name</replaceable>
     SET WITHOUT CLUSTER
     SET WITHOUT OIDS
@@ -193,10 +199,10 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
    </varlistentry>
 
    <varlistentry>
-    <term><literal>DISABLE</literal>/<literal>ENABLE TRIGGER</literal></term>
+    <term><literal>DISABLE</literal>/<literal>ENABLE [ REPLICA | ALWAYS ] TRIGGER</literal></term>
     <listitem>
      <para>
-      These forms disable or enable trigger(s) belonging to the table.
+      These forms configure the firing of trigger(s) belonging to the table.
       A disabled trigger is still known to the system, but is not executed
       when its triggering event occurs.  For a deferred trigger, the enable
       status is checked when the event occurs, not when the trigger function
@@ -207,6 +213,27 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
       requires superuser privileges; it should be done with caution since
       of course the integrity of the constraint cannot be guaranteed if the
       triggers are not executed.
+         The trigger firing mechanism is also affected by the configuration
+         variable <xref linkend="guc-session-replication-role">. Simply ENABLEd
+         triggers will fire when the replication role is <quote>origin</>
+         (the default) or <quote>local</>. Triggers configured ENABLE REPLICA 
+         will only fire if the session is in <quote>replica</> mode and triggers 
+         configured ENABLE ALWAYS will fire regardless of the current replication 
+         mode.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>DISABLE</literal>/<literal>ENABLE [ REPLICA | ALWAYS ] RULE</literal></term>
+    <listitem>
+     <para>
+      These forms configure the firing of rewrite rules belonging to the table.
+      A disabled rule is still known to the system, but is not applied
+         during query rewriting. The semantics are as for disabled/enabled
+         triggers. This configuration is ignored for ON SELECT rules, which
+         are always applied in order to keep views working even if the current
+         session is in a non-default replication role.
      </para>
     </listitem>
    </varlistentry>
index ddc62086f51a8c6928d646715005a34d06878c5d..25e53a3dc43d10861fcff64e62a1e92c1da5b727 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.217 2007/03/13 00:33:39 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.218 2007/03/19 23:38:29 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,7 @@
 #include "parser/parse_relation.h"
 #include "parser/parse_type.h"
 #include "parser/parser.h"
+#include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/smgr.h"
 #include "utils/acl.h"
@@ -253,7 +254,9 @@ static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
 static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
 static void ATExecSetRelOptions(Relation rel, List *defList, bool isReset);
 static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
-                                                  bool enable, bool skip_system);
+                                                  char fires_when, bool skip_system);
+static void ATExecEnableDisableRule(Relation rel, char *rulename,
+                                                  char fires_when);
 static void ATExecAddInherit(Relation rel, RangeVar *parent);
 static void ATExecDropInherit(Relation rel, RangeVar *parent);
 static void copy_relation_data(Relation rel, SMgrRelation dst);
@@ -1955,11 +1958,17 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
                        pass = AT_PASS_MISC;
                        break;
                case AT_EnableTrig:             /* ENABLE TRIGGER variants */
+               case AT_EnableAlwaysTrig:
+               case AT_EnableReplicaTrig:
                case AT_EnableTrigAll:
                case AT_EnableTrigUser:
                case AT_DisableTrig:    /* DISABLE TRIGGER variants */
                case AT_DisableTrigAll:
                case AT_DisableTrigUser:
+               case AT_EnableRule:             /* ENABLE/DISABLE RULE variants */
+               case AT_EnableAlwaysRule:
+               case AT_EnableReplicaRule:
+               case AT_DisableRule:
                case AT_AddInherit:             /* INHERIT / NO INHERIT */
                case AT_DropInherit:
                        ATSimplePermissions(rel, false);
@@ -2127,24 +2136,57 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd)
                case AT_ResetRelOptions:                /* RESET (...) */
                        ATExecSetRelOptions(rel, (List *) cmd->def, true);
                        break;
-               case AT_EnableTrig:             /* ENABLE TRIGGER name */
-                       ATExecEnableDisableTrigger(rel, cmd->name, true, false);
+
+               case AT_EnableTrig:                     /* ENABLE TRIGGER name */
+                       ATExecEnableDisableTrigger(rel, cmd->name, 
+                                       TRIGGER_FIRES_ON_ORIGIN, false);
+                       break;
+               case AT_EnableAlwaysTrig:       /* ENABLE ALWAYS TRIGGER name */
+                       ATExecEnableDisableTrigger(rel, cmd->name, 
+                                       TRIGGER_FIRES_ALWAYS, false);
+                       break;
+               case AT_EnableReplicaTrig:      /* ENABLE REPLICA TRIGGER name */
+                       ATExecEnableDisableTrigger(rel, cmd->name, 
+                                       TRIGGER_FIRES_ON_REPLICA, false);
                        break;
                case AT_DisableTrig:    /* DISABLE TRIGGER name */
-                       ATExecEnableDisableTrigger(rel, cmd->name, false, false);
+                       ATExecEnableDisableTrigger(rel, cmd->name, 
+                                       TRIGGER_DISABLED, false);
                        break;
                case AT_EnableTrigAll:  /* ENABLE TRIGGER ALL */
-                       ATExecEnableDisableTrigger(rel, NULL, true, false);
+                       ATExecEnableDisableTrigger(rel, NULL, 
+                                       TRIGGER_FIRES_ON_ORIGIN, false);
                        break;
                case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
-                       ATExecEnableDisableTrigger(rel, NULL, false, false);
+                       ATExecEnableDisableTrigger(rel, NULL, 
+                                       TRIGGER_DISABLED, false);
                        break;
                case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
-                       ATExecEnableDisableTrigger(rel, NULL, true, true);
+                       ATExecEnableDisableTrigger(rel, NULL, 
+                                       TRIGGER_FIRES_ON_ORIGIN, true);
                        break;
                case AT_DisableTrigUser:                /* DISABLE TRIGGER USER */
-                       ATExecEnableDisableTrigger(rel, NULL, false, true);
+                       ATExecEnableDisableTrigger(rel, NULL, 
+                                       TRIGGER_DISABLED, true);
+                       break;
+
+               case AT_EnableRule:                     /* ENABLE RULE name */
+                       ATExecEnableDisableRule(rel, cmd->name, 
+                                       RULE_FIRES_ON_ORIGIN);
+                       break;
+               case AT_EnableAlwaysRule:       /* ENABLE ALWAYS RULE name */
+                       ATExecEnableDisableRule(rel, cmd->name, 
+                                       RULE_FIRES_ALWAYS);
+                       break;
+               case AT_EnableReplicaRule:      /* ENABLE REPLICA RULE name */
+                       ATExecEnableDisableRule(rel, cmd->name, 
+                                       RULE_FIRES_ON_REPLICA);
+                       break;
+               case AT_DisableRule:    /* DISABLE RULE name */
+                       ATExecEnableDisableRule(rel, cmd->name, 
+                                       RULE_DISABLED);
                        break;
+
                case AT_AddInherit:
                        ATExecAddInherit(rel, (RangeVar *) cmd->def);
                        break;
@@ -4380,7 +4422,7 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint,
        MemSet(&trig, 0, sizeof(trig));
        trig.tgoid = InvalidOid;
        trig.tgname = fkconstraint->constr_name;
-       trig.tgenabled = TRUE;
+       trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
        trig.tgisconstraint = TRUE;
        trig.tgconstrrelid = RelationGetRelid(pkrel);
        trig.tgconstraint = constraintOid;
@@ -5877,9 +5919,21 @@ copy_relation_data(Relation rel, SMgrRelation dst)
  */
 static void
 ATExecEnableDisableTrigger(Relation rel, char *trigname,
-                                                  bool enable, bool skip_system)
+                                                  char fires_when, bool skip_system)
+{
+       EnableDisableTrigger(rel, trigname, fires_when, skip_system);
+}
+
+/*
+ * ALTER TABLE ENABLE/DISABLE RULE
+ *
+ * We just pass this off to rewriteDefine.c.
+ */
+static void
+ATExecEnableDisableRule(Relation rel, char *trigname,
+                                                  char fires_when)
 {
-       EnableDisableTrigger(rel, trigname, enable, skip_system);
+       EnableDisableRule(rel, trigname, fires_when);
 }
 
 /*
index c08525c2e040ffb41b44ce4fa9a060b4713c2cbe..e2dadb7a7e283c9c34d11d44414d6974cb4fd06c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.213 2007/02/14 01:58:56 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.214 2007/03/19 23:38:29 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -54,6 +54,13 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
 static void AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event,
                                          bool row_trigger, HeapTuple oldtup, HeapTuple newtup);
 
+/*
+ * SessionReplicationRole -
+ *
+ *     Global variable that controls the trigger firing behaviour based
+ *     on pg_trigger.tgenabled. This is maintained from misc/guc.c.
+ */
+int    SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
 
 /*
  * Create a trigger.  Returns the OID of the created trigger.
@@ -270,7 +277,7 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
                                                                                                  CStringGetDatum(trigname));
        values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
        values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
-       values[Anum_pg_trigger_tgenabled - 1] = BoolGetDatum(true);
+       values[Anum_pg_trigger_tgenabled - 1] = CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
        values[Anum_pg_trigger_tgisconstraint - 1] = BoolGetDatum(stmt->isconstraint);
        values[Anum_pg_trigger_tgconstrname - 1] = DirectFunctionCall1(namein,
                                                                                                CStringGetDatum(constrname));
@@ -701,11 +708,11 @@ renametrig(Oid relid,
  * EnableDisableTrigger()
  *
  *     Called by ALTER TABLE ENABLE/DISABLE TRIGGER
- *     to change 'tgenabled' flag for the specified trigger(s)
+ *     to change 'tgenabled' field for the specified trigger(s)
  *
  * rel: relation to process (caller must hold suitable lock on it)
  * tgname: trigger to process, or NULL to scan all triggers
- * enable: new value for tgenabled flag
+ * enable: new value for tgenabled field
  * skip_system: if true, skip "system" triggers (constraint triggers)
  *
  * Caller should have checked permissions for the table; here we also
@@ -714,7 +721,7 @@ renametrig(Oid relid,
  */
 void
 EnableDisableTrigger(Relation rel, const char *tgname,
-                                        bool enable, bool skip_system)
+                                        char fires_when, bool skip_system)
 {
        Relation        tgrel;
        int                     nkeys;
@@ -765,13 +772,13 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 
                found = true;
 
-               if (oldtrig->tgenabled != enable)
+               if (oldtrig->tgenabled != fires_when)
                {
                        /* need to change this one ... make a copy to scribble on */
                        HeapTuple       newtup = heap_copytuple(tuple);
                        Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
 
-                       newtrig->tgenabled = enable;
+                       newtrig->tgenabled = fires_when;
 
                        simple_heap_update(tgrel, &newtup->t_self, newtup);
 
@@ -1333,8 +1340,18 @@ ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
                Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
                HeapTuple       newtuple;
 
-               if (!trigger->tgenabled)
-                       continue;
+               if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
+               else /* ORIGIN or LOCAL role */
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
                LocTriggerData.tg_trigger = trigger;
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
                                                                           tgindx[i],
@@ -1382,8 +1399,18 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
        {
                Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
 
-               if (!trigger->tgenabled)
-                       continue;
+               if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
+               else /* ORIGIN or LOCAL role */
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
                LocTriggerData.tg_trigtuple = oldtuple = newtuple;
                LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
                LocTriggerData.tg_trigger = trigger;
@@ -1444,8 +1471,18 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
                Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
                HeapTuple       newtuple;
 
-               if (!trigger->tgenabled)
-                       continue;
+               if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
+               else /* ORIGIN or LOCAL role */
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
                LocTriggerData.tg_trigger = trigger;
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
                                                                           tgindx[i],
@@ -1500,8 +1537,18 @@ ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
        {
                Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
 
-               if (!trigger->tgenabled)
-                       continue;
+               if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
+               else /* ORIGIN or LOCAL role */
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
                LocTriggerData.tg_trigtuple = trigtuple;
                LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
                LocTriggerData.tg_trigger = trigger;
@@ -1575,8 +1622,18 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
                Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
                HeapTuple       newtuple;
 
-               if (!trigger->tgenabled)
-                       continue;
+               if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
+               else /* ORIGIN or LOCAL role */
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
                LocTriggerData.tg_trigger = trigger;
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
                                                                           tgindx[i],
@@ -1636,8 +1693,18 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
        {
                Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
 
-               if (!trigger->tgenabled)
-                       continue;
+               if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
+               else /* ORIGIN or LOCAL role */
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
                LocTriggerData.tg_trigtuple = trigtuple;
                LocTriggerData.tg_newtuple = oldtuple = newtuple;
                LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
@@ -3267,8 +3334,18 @@ AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
                Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
 
                /* Ignore disabled triggers */
-               if (!trigger->tgenabled)
-                       continue;
+               if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
+               else /* ORIGIN or LOCAL role */
+               {
+                       if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+                               trigger->tgenabled == TRIGGER_DISABLED)
+                               continue;
+               }
 
                /*
                 * If this is an UPDATE of a PK table or FK table that does not change
index 22d03f0b23461227ca331bbaa9220b5a4eb3fa8f..75404716d5a1f82a6a70d46188484e22fbe88ab4 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.582 2007/03/17 19:27:12 meskes Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.583 2007/03/19 23:38:29 wieck Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -365,7 +365,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
 
 /* ordinary key words in alphabetical order */
 %token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
-       AGGREGATE ALL ALSO ALTER ANALYSE ANALYZE AND ANY ARRAY AS ASC
+       AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
        ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION
 
        BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
@@ -422,8 +422,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
        QUOTE
 
        READ REAL REASSIGN RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME
-       REPEATABLE REPLACE RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT
-       ROLE ROLLBACK ROW ROWS RULE
+       REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE
+       RIGHT ROLE ROLLBACK ROW ROWS RULE
 
        SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
        SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
@@ -1480,6 +1480,22 @@ alter_table_cmd:
                                        n->name = $3;
                                        $$ = (Node *)n;
                                }
+                       /* ALTER TABLE <name> ENABLE ALWAYS TRIGGER <trig> */
+                       | ENABLE_P ALWAYS TRIGGER name
+                               {
+                                       AlterTableCmd *n = makeNode(AlterTableCmd);
+                                       n->subtype = AT_EnableAlwaysTrig;
+                                       n->name = $4;
+                                       $$ = (Node *)n;
+                               }
+                       /* ALTER TABLE <name> ENABLE REPLICA TRIGGER <trig> */
+                       | ENABLE_P REPLICA TRIGGER name
+                               {
+                                       AlterTableCmd *n = makeNode(AlterTableCmd);
+                                       n->subtype = AT_EnableReplicaTrig;
+                                       n->name = $4;
+                                       $$ = (Node *)n;
+                               }
                        /* ALTER TABLE <name> ENABLE TRIGGER ALL */
                        | ENABLE_P TRIGGER ALL
                                {
@@ -1516,6 +1532,38 @@ alter_table_cmd:
                                        n->subtype = AT_DisableTrigUser;
                                        $$ = (Node *)n;
                                }
+                       /* ALTER TABLE <name> ENABLE RULE <rule> */
+                       | ENABLE_P RULE name
+                               {
+                                       AlterTableCmd *n = makeNode(AlterTableCmd);
+                                       n->subtype = AT_EnableRule;
+                                       n->name = $3;
+                                       $$ = (Node *)n;
+                               }
+                       /* ALTER TABLE <name> ENABLE ALWAYS RULE <rule> */
+                       | ENABLE_P ALWAYS RULE name
+                               {
+                                       AlterTableCmd *n = makeNode(AlterTableCmd);
+                                       n->subtype = AT_EnableAlwaysRule;
+                                       n->name = $4;
+                                       $$ = (Node *)n;
+                               }
+                       /* ALTER TABLE <name> ENABLE REPLICA RULE <rule> */
+                       | ENABLE_P REPLICA RULE name
+                               {
+                                       AlterTableCmd *n = makeNode(AlterTableCmd);
+                                       n->subtype = AT_EnableReplicaRule;
+                                       n->name = $4;
+                                       $$ = (Node *)n;
+                               }
+                       /* ALTER TABLE <name> DISABLE RULE <rule> */
+                       | DISABLE_P RULE name
+                               {
+                                       AlterTableCmd *n = makeNode(AlterTableCmd);
+                                       n->subtype = AT_DisableRule;
+                                       n->name = $3;
+                                       $$ = (Node *)n;
+                               }
                        /* ALTER TABLE <name> INHERIT <parent> */
                        | INHERIT qualified_name
                                {
@@ -8651,6 +8699,7 @@ unreserved_keyword:
                        | AGGREGATE
                        | ALSO
                        | ALTER
+                       | ALWAYS
                        | ASSERTION
                        | ASSIGNMENT
                        | AT
@@ -8796,6 +8845,7 @@ unreserved_keyword:
                        | RENAME
                        | REPEATABLE
                        | REPLACE
+                       | REPLICA
                        | RESET
                        | RESTART
                        | RESTRICT
index 368f3e06947972e98cc00c34508431f6b6b40b3f..9be91e7e6e62a43cb0b176d491669a56c93568c8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.184 2007/01/25 11:53:51 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.185 2007/03/19 23:38:29 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,6 +42,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"all", ALL},
        {"also", ALSO},
        {"alter", ALTER},
+       {"always", ALWAYS},
        {"analyse", ANALYSE},           /* British spelling */
        {"analyze", ANALYZE},
        {"and", AND},
@@ -289,6 +290,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"rename", RENAME},
        {"repeatable", REPEATABLE},
        {"replace", REPLACE},
+       {"replica", REPLICA},
        {"reset", RESET},
        {"restart", RESTART},
        {"restrict", RESTRICT},
index 64a2a96f0e9a8d7b1056c183f62fdeabaa698848..864b00f1e73554c208d4e37afb061fa9c21aca37 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.118 2007/03/13 00:33:42 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.119 2007/03/19 23:38:29 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,6 +30,7 @@
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
+#include "utils/inval.h"
 
 
 static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
@@ -79,6 +80,7 @@ InsertRule(char *rulname,
        values[i++] = ObjectIdGetDatum(eventrel_oid);           /* ev_class */
        values[i++] = Int16GetDatum(evslot_index);      /* ev_attr */
        values[i++] = CharGetDatum(evtype + '0');       /* ev_type */
+       values[i++] = CharGetDatum(RULE_FIRES_ON_ORIGIN);       /* ev_enabled */
        values[i++] = BoolGetDatum(evinstead);          /* is_instead */
        values[i++] = DirectFunctionCall1(textin, CStringGetDatum(evqual)); /* ev_qual */
        values[i++] = DirectFunctionCall1(textin, CStringGetDatum(actiontree));         /* ev_action */
@@ -628,6 +630,72 @@ setRuleCheckAsUser_Query(Query *qry, Oid userid)
 }
 
 
+/*
+ * Change the firing semantics of an existing rule.
+ *
+ */
+void
+EnableDisableRule(Relation rel, const char *rulename,
+                                 char fires_when)
+{
+       Relation        pg_rewrite_desc;
+       Oid                     owningRel = RelationGetRelid(rel);
+       Oid                     eventRelationOid;
+       HeapTuple       ruletup;
+       bool            changed = false;
+
+       /*
+        * Find the rule tuple to change.
+        */
+       pg_rewrite_desc = heap_open(RewriteRelationId, RowExclusiveLock);
+       ruletup = SearchSysCacheCopy(RULERELNAME,
+                                                                ObjectIdGetDatum(owningRel),
+                                                                PointerGetDatum(rulename),
+                                                                0, 0);
+       if (!HeapTupleIsValid(ruletup))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("rule \"%s\" for relation \"%s\" does not exist",
+                                               rulename, get_rel_name(owningRel))));
+
+       /*
+        * Verify that the user has appropriate permissions.
+        */
+       eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_class;
+       Assert(eventRelationOid == owningRel);
+       if (!pg_class_ownercheck(eventRelationOid, GetUserId()))
+               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+                                               get_rel_name(eventRelationOid));
+       
+       /*
+        * Change ev_enabled if it is different from the desired new state.
+        */
+       if (DatumGetChar(((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_enabled) !=
+                       fires_when)
+               {
+               ((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_enabled =
+                                       CharGetDatum(fires_when);
+               simple_heap_update(pg_rewrite_desc, &ruletup->t_self, ruletup);
+
+               /* keep system catalog indexes current */
+               CatalogUpdateIndexes(pg_rewrite_desc, ruletup);
+
+               changed = true;
+       }
+
+       heap_freetuple(ruletup);
+       heap_close(pg_rewrite_desc, RowExclusiveLock);
+
+       /*
+        * If we changed anything, broadcast a SI inval message to force each
+        * backend (including our own!) to rebuild relation's relcache entry.
+        * Otherwise they will fail to apply the change promptly.
+        */
+       if (changed)
+               CacheInvalidateRelcache(rel);
+}
+
+
 /*
  * Rename an existing rewrite rule.
  *
index e5a1d4c74725f172e826eb917f683fef9a9d8693..cd1cb54e9af35d5b69658e89e4276cd79af6b8c1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.172 2007/03/17 00:11:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.173 2007/03/19 23:38:29 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parsetree.h"
+#include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteHandler.h"
 #include "rewrite/rewriteManip.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
+#include "commands/trigger.h"
 
 
 /* We use a list of these to detect recursion in RewriteQuery */
@@ -1035,6 +1037,29 @@ matchLocks(CmdType event,
        {
                RewriteRule *oneLock = rulelocks->rules[i];
 
+               /*
+                * Suppress ON INSERT/UPDATE/DELETE rules that are disabled
+                * or configured to not fire during the current sessions
+                * replication role. ON SELECT rules will always be applied
+                * in order to keep views working even in LOCAL or REPLICA
+                * role.
+                */
+               if (oneLock->event != CMD_SELECT)
+               {
+                       if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+                       {
+                               if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
+                                       oneLock->enabled == RULE_DISABLED)
+                                       continue;
+                       }
+                       else /* ORIGIN or LOCAL ROLE */
+                       {
+                               if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
+                                       oneLock->enabled == RULE_DISABLED)
+                                       continue;
+                       }
+               }
+
                if (oneLock->event == event)
                {
                        if (parsetree->commandType != CMD_SELECT ||
index 61a576d35d981928d9baade9ec64955729cdb8f9..4648b05803e13c4fb5065247a20f5f0b8e964260 100644 (file)
@@ -33,7 +33,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.2 2007/03/15 23:12:06 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.3 2007/03/19 23:38:29 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -860,3 +860,14 @@ InvalRelid(Oid relid, LOCKMODE lockmode, InvalRelidContext *context)
        if (relid == context->inval_relid)
                context->plan->dead = true;
 }
+
+/*
+ * HaveCachedPlans 
+ *             Check if the plancache has stored any plans at all.
+ */
+bool
+HaveCachedPlans(void)
+{
+       return (cached_plans_list != NIL);
+}
+
index 4ce955917a54a958001945faf2c2cc6b62d614e9..91b7f146b43abd96b9a8d1dcf2d9e0e169908856 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.257 2007/03/03 20:08:41 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.258 2007/03/19 23:38:29 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -651,6 +651,7 @@ RelationBuildRuleLock(Relation relation)
 
                rule->event = rewrite_form->ev_type - '0';
                rule->attrno = rewrite_form->ev_attr;
+               rule->enabled = rewrite_form->ev_enabled;
                rule->isInstead = rewrite_form->is_instead;
 
                /*
index 8088432bac869555cd8373183ed3a97e623bcdd6..f921c75a60b6997e1acd18f131b10b70432e5944 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.382 2007/03/13 14:32:25 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.383 2007/03/19 23:38:30 wieck Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -34,6 +34,7 @@
 #include "commands/async.h"
 #include "commands/vacuum.h"
 #include "commands/variable.h"
+#include "commands/trigger.h"
 #include "funcapi.h"
 #include "libpq/auth.h"
 #include "libpq/pqformat.h"
@@ -59,6 +60,7 @@
 #include "utils/guc_tables.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
+#include "utils/plancache.h"
 #include "utils/ps_status.h"
 #include "utils/tzparser.h"
 #include "utils/xml.h"
@@ -124,6 +126,8 @@ static const char *assign_syslog_ident(const char *ident,
 
 static const char *assign_defaultxactisolevel(const char *newval, bool doit,
                                                   GucSource source);
+static const char *assign_session_replication_role(const char *newval, bool doit,
+                                                  GucSource source);
 static const char *assign_log_min_messages(const char *newval, bool doit,
                                                GucSource source);
 static const char *assign_client_min_messages(const char *newval,
@@ -226,6 +230,7 @@ static char *backslash_quote_string;
 static char *client_encoding_string;
 static char *datestyle_string;
 static char *default_iso_level_string;
+static char *session_replication_role_string;
 static char *locale_collate;
 static char *locale_ctype;
 static char *regex_flavor_string;
@@ -1928,6 +1933,16 @@ static struct config_string ConfigureNamesString[] =
                "read committed", assign_defaultxactisolevel, NULL
        },
 
+       {
+               {"session_replication_role", PGC_SUSET, CLIENT_CONN_STATEMENT,
+                       gettext_noop("Sets the sessions behaviour for triggers and rewrite rules."),
+                       gettext_noop("Each session can be either"
+                                                " \"origin\", \"replica\" or \"local\".")
+               },
+               &session_replication_role_string,
+               "origin", assign_session_replication_role, NULL
+       },
+
        {
                {"dynamic_library_path", PGC_SUSET, CLIENT_CONN_OTHER,
                        gettext_noop("Sets the path for dynamically loadable modules."),
@@ -6115,6 +6130,33 @@ assign_defaultxactisolevel(const char *newval, bool doit, GucSource source)
        return newval;
 }
 
+static const char *
+assign_session_replication_role(const char *newval, bool doit, GucSource source)
+{
+       if (HaveCachedPlans())
+               elog(ERROR, "session_replication_role cannot be changed "
+                                       "after prepared plans have been cached");
+
+       if (pg_strcasecmp(newval, "origin") == 0)
+       {
+               if (doit)
+                       SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
+       }
+       else if (pg_strcasecmp(newval, "replica") == 0)
+       {
+               if (doit)
+                       SessionReplicationRole = SESSION_REPLICATION_ROLE_REPLICA;
+       }
+       else if (pg_strcasecmp(newval, "local") == 0)
+       {
+               if (doit)
+                       SessionReplicationRole = SESSION_REPLICATION_ROLE_LOCAL;
+       }
+       else
+               return NULL;
+       return newval;
+}
+
 static const char *
 assign_log_min_messages(const char *newval,
                                                bool doit, GucSource source)
index cf2dfdc099e07211e7bc1e48be80c9ce924ce5e2..22f9685bbdce04a4995c988cb0a6976f2191a7a0 100644 (file)
 #default_transaction_isolation = 'read committed'
 #default_transaction_read_only = off
 #statement_timeout = 0                 # 0 is disabled
+#session_replication_role = "origin"
 #vacuum_freeze_min_age = 100000000
 #xmlbinary = 'base64'
 #xmloption = 'content'
index eef9a4c875a13a7861fc634124283a09348e0a30..90e78c36d15ff50396ebdfbc33aa01a7d4cd5549 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.460 2007/02/14 01:58:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.461 2007/03/19 23:38:30 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3699,15 +3699,26 @@ getRules(int *numRules)
        int                     i_ruletable;
        int                     i_ev_type;
        int                     i_is_instead;
+       int                     i_ev_enabled;
 
        /* Make sure we are in proper schema */
        selectSourceSchema("pg_catalog");
 
-       if (g_fout->remoteVersion >= 70100)
+       if (g_fout->remoteVersion >= 80300)
        {
                appendPQExpBuffer(query, "SELECT "
                                                  "tableoid, oid, rulename, "
-                                                 "ev_class as ruletable, ev_type, is_instead "
+                                                 "ev_class as ruletable, ev_type, is_instead, "
+                                                 "ev_enabled "
+                                                 "FROM pg_rewrite "
+                                                 "ORDER BY oid");
+       }
+       else if (g_fout->remoteVersion >= 70100)
+       {
+               appendPQExpBuffer(query, "SELECT "
+                                                 "tableoid, oid, rulename, "
+                                                 "ev_class as ruletable, ev_type, is_instead, "
+                                                 "'O'::char as ev_enabled "
                                                  "FROM pg_rewrite "
                                                  "ORDER BY oid");
        }
@@ -3716,7 +3727,8 @@ getRules(int *numRules)
                appendPQExpBuffer(query, "SELECT "
                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
                                                  "oid, rulename, "
-                                                 "ev_class as ruletable, ev_type, is_instead "
+                                                 "ev_class as ruletable, ev_type, is_instead, "
+                                                 "'O'::char as ev_enabled "
                                                  "FROM pg_rewrite "
                                                  "ORDER BY oid");
        }
@@ -3736,6 +3748,7 @@ getRules(int *numRules)
        i_ruletable = PQfnumber(res, "ruletable");
        i_ev_type = PQfnumber(res, "ev_type");
        i_is_instead = PQfnumber(res, "is_instead");
+       i_ev_enabled = PQfnumber(res, "ev_enabled");
 
        for (i = 0; i < ntups; i++)
        {
@@ -3759,6 +3772,7 @@ getRules(int *numRules)
                ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
                ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
                ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
+               ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
                if (ruleinfo[i].ruletable)
                {
                        /*
@@ -3956,7 +3970,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
                        tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
                        tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
                        tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
-                       tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled)) == 't';
+                       tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
                        tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
                        tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
 
@@ -8824,11 +8838,27 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
        }
        appendPQExpBuffer(query, ");\n");
 
-       if (!tginfo->tgenabled)
+       if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
        {
                appendPQExpBuffer(query, "\nALTER TABLE %s ",
                                                  fmtId(tbinfo->dobj.name));
-               appendPQExpBuffer(query, "DISABLE TRIGGER %s;\n",
+               switch (tginfo->tgenabled)
+               {
+                       case 'D':
+                       case 'f':
+                               appendPQExpBuffer(query, "DISABLE");
+                               break;
+                       case 'A':
+                               appendPQExpBuffer(query, "ENABLE ALWAYS");
+                               break;
+                       case 'R':
+                               appendPQExpBuffer(query, "ENABLE REPLICA");
+                               break;
+                       default:
+                               appendPQExpBuffer(query, "ENABLE");
+                               break;
+               }
+               appendPQExpBuffer(query, " TRIGGER %s;\n",
                                                  fmtId(tginfo->dobj.name));
        }
 
@@ -8914,6 +8944,33 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 
        printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
 
+       /*
+        * Add the command to alter the rules replication firing semantics
+        * if it differs from the default.
+        */
+       if (rinfo->ev_enabled != 'O')
+       {
+               appendPQExpBuffer(cmd, "ALTER TABLE %s.",
+                                       fmtId(tbinfo->dobj.namespace->dobj.name));
+               appendPQExpBuffer(cmd, "%s ",
+                                       fmtId(tbinfo->dobj.name));
+               switch (rinfo->ev_enabled)
+               {
+                       case 'A':
+                               appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
+                                                       fmtId(rinfo->dobj.name));
+                               break;
+                       case 'R':
+                               appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
+                                                       fmtId(rinfo->dobj.name));
+                               break;
+                       case 'D':
+                               appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
+                                                       fmtId(rinfo->dobj.name));
+                               break;
+               }
+       }
+
        /*
         * DROP must be fully qualified in case same name appears in pg_catalog
         */
index b584ab1fe017ef9c88a4d7f442966d1428ef0c67..8694376b5299c42a29a5d04e3effb472fa2cffe5 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.133 2007/02/19 15:05:06 mha Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.134 2007/03/19 23:38:30 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -314,6 +314,7 @@ typedef struct _ruleInfo
        TableInfo  *ruletable;          /* link to table the rule is for */
        char            ev_type;
        bool            is_instead;
+       char            ev_enabled;
        bool            separate;               /* TRUE if must dump as separate item */
        /* separate is always true for non-ON SELECT rules */
 } RuleInfo;
@@ -330,7 +331,7 @@ typedef struct _triggerInfo
        char       *tgconstrname;
        Oid                     tgconstrrelid;
        char       *tgconstrrelname;
-       bool            tgenabled;
+       char            tgenabled;
        bool            tgdeferrable;
        bool            tginitdeferred;
 } TriggerInfo;
index 5dfaf9367a1da18d127b6bdd3323a3ccac21531e..13d3be678e84f6a22c9d5fb2c30004321ff4d6cd 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.154 2007/03/18 16:50:44 neilc Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.155 2007/03/19 23:38:31 wieck Exp $
  */
 #include "postgres_fe.h"
 #include "describe.h"
@@ -1055,14 +1055,12 @@ describeOneTableDetails(const char *schemaname,
                                   *result3 = NULL,
                                   *result4 = NULL,
                                   *result5 = NULL,
-                                  *result6 = NULL,
-                                  *result7 = NULL;
+                                  *result6 = NULL;
                int                     check_count = 0,
                                        index_count = 0,
                                        foreignkey_count = 0,
                                        rule_count = 0,
                                        trigger_count = 0,
-                                       disabled_trigger_count = 0,
                                        inherits_count = 0;
                int                     count_footers = 0;
 
@@ -1105,11 +1103,24 @@ describeOneTableDetails(const char *schemaname,
                /* count rules */
                if (tableinfo.hasrules)
                {
-                       printfPQExpBuffer(&buf,
-                                                         "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
+                       if (pset.sversion < 80300)
+                       {
+                               printfPQExpBuffer(&buf,
+                                                         "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+                                                         "'O'::char AS ev_enabled\n"
                                                          "FROM pg_catalog.pg_rewrite r\n"
                                                          "WHERE r.ev_class = '%s' ORDER BY 1",
                                                          oid);
+                       }
+                       else
+                       {
+                               printfPQExpBuffer(&buf,
+                                                         "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+                                                         "ev_enabled\n"
+                                                         "FROM pg_catalog.pg_rewrite r\n"
+                                                         "WHERE r.ev_class = '%s' ORDER BY 1",
+                                                         oid);
+                       }
                        result3 = PSQLexec(buf.data, false);
                        if (!result3)
                        {
@@ -1125,10 +1136,10 @@ describeOneTableDetails(const char *schemaname,
                if (tableinfo.triggers)
                {
                        printfPQExpBuffer(&buf,
-                                        "SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid)\n"
+                                        "SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid), "
+                                                       "t.tgenabled\n"
                                                          "FROM pg_catalog.pg_trigger t\n"
                                                          "WHERE t.tgrelid = '%s' "
-                                                         "AND t.tgenabled "
                                                          "AND t.tgconstraint = 0\n"
                                                          "ORDER BY 1",
                                                          oid);
@@ -1142,27 +1153,6 @@ describeOneTableDetails(const char *schemaname,
                        }
                        else
                                trigger_count = PQntuples(result4);
-
-                       /* acquire disabled triggers as a separate list */
-                       printfPQExpBuffer(&buf,
-                                        "SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid)\n"
-                                                         "FROM pg_catalog.pg_trigger t\n"
-                                                         "WHERE t.tgrelid = '%s' "
-                                                         "AND NOT t.tgenabled "
-                                                         "AND t.tgconstraint = 0\n"
-                                                         "ORDER BY 1",
-                                                         oid);
-                       result7 = PSQLexec(buf.data, false);
-                       if (!result7)
-                       {
-                               PQclear(result1);
-                               PQclear(result2);
-                               PQclear(result3);
-                               PQclear(result4);
-                               goto error_return;
-                       }
-                       else
-                               disabled_trigger_count = PQntuples(result7);
                }
 
                /* count foreign-key constraints (there are none if no triggers) */
@@ -1181,7 +1171,6 @@ describeOneTableDetails(const char *schemaname,
                                PQclear(result2);
                                PQclear(result3);
                                PQclear(result4);
-                               PQclear(result7);
                                goto error_return;
                        }
                        else
@@ -1199,7 +1188,6 @@ describeOneTableDetails(const char *schemaname,
                        PQclear(result3);
                        PQclear(result4);
                        PQclear(result5);
-                       PQclear(result7);
                        goto error_return;
                }
                else
@@ -1297,63 +1285,143 @@ describeOneTableDetails(const char *schemaname,
                /* print rules */
                if (rule_count > 0)
                {
-                       printfPQExpBuffer(&buf, _("Rules:"));
-                       footers[count_footers++] = pg_strdup(buf.data);
-                       for (i = 0; i < rule_count; i++)
-                       {
-                               const char *ruledef;
-
-                               /* Everything after "CREATE RULE" is echoed verbatim */
-                               ruledef = PQgetvalue(result3, i, 1);
-                               ruledef += 12;
+                       bool    have_heading;
+                       int             category;
 
-                               printfPQExpBuffer(&buf, "    %s", ruledef);
+                       for (category = 0; category < 4; category++)
+                       {
+                               have_heading = false;
 
-                               footers[count_footers++] = pg_strdup(buf.data);
+                               for (i = 0; i < rule_count; i++)
+                               {
+                                       const char *ruledef;
+                                       bool            list_rule = false;
+
+                                       switch (category)
+                                       {
+                                               case 0:
+                                                       if (*PQgetvalue(result3, i, 2) == 'O')
+                                                               list_rule = true;
+                                                       break;
+                                               case 1:
+                                                       if (*PQgetvalue(result3, i, 2) == 'D')
+                                                               list_rule = true;
+                                                       break;
+                                               case 2:
+                                                       if (*PQgetvalue(result3, i, 2) == 'A')
+                                                               list_rule = true;
+                                                       break;
+                                               case 3:
+                                                       if (*PQgetvalue(result3, i, 2) == 'R')
+                                                               list_rule = true;
+                                                       break;
+                                       }
+                                       if (!list_rule)
+                                               continue;
+
+                                       if (!have_heading)
+                                       {
+                                               switch (category)
+                                               {
+                                                       case 0:
+                                                               printfPQExpBuffer(&buf, _("Rules:"));
+                                                               break;
+                                                       case 1:
+                                                               printfPQExpBuffer(&buf, _("Disabled Rules:"));
+                                                               break;
+                                                       case 2:
+                                                               printfPQExpBuffer(&buf, _("Rules firing always:"));
+                                                               break;
+                                                       case 3:
+                                                               printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
+                                                               break;
+                                               }
+                                               footers[count_footers++] = pg_strdup(buf.data);
+                                               have_heading = true;
+                                       }
+
+                                       /* Everything after "CREATE RULE" is echoed verbatim */
+                                       ruledef = PQgetvalue(result3, i, 1);
+                                       ruledef += 12;
+                                       printfPQExpBuffer(&buf, "    %s", ruledef);
+                                       footers[count_footers++] = pg_strdup(buf.data);
+                               }
                        }
                }
 
                /* print triggers */
                if (trigger_count > 0)
                {
-                       printfPQExpBuffer(&buf, _("Triggers:"));
-                       footers[count_footers++] = pg_strdup(buf.data);
-                       for (i = 0; i < trigger_count; i++)
-                       {
-                               const char *tgdef;
-                               const char *usingpos;
-
-                               /* Everything after "TRIGGER" is echoed verbatim */
-                               tgdef = PQgetvalue(result4, i, 1);
-                               usingpos = strstr(tgdef, " TRIGGER ");
-                               if (usingpos)
-                                       tgdef = usingpos + 9;
-
-                               printfPQExpBuffer(&buf, "    %s", tgdef);
-
-                               footers[count_footers++] = pg_strdup(buf.data);
-                       }
-               }
-
-               /* print disabled triggers */
-               if (disabled_trigger_count > 0)
-               {
-                       printfPQExpBuffer(&buf, _("Disabled triggers:"));
-                       footers[count_footers++] = pg_strdup(buf.data);
-                       for (i = 0; i < disabled_trigger_count; i++)
+                       bool    have_heading;
+                       int             category;
+
+                       /* split the output into 4 different categories.
+                        * Enabled triggers, disabled triggers and the two
+                        * special ALWAYS and REPLICA configurations.
+                        */
+                       for (category = 0; category < 4; category++)
                        {
-                               const char *tgdef;
-                               const char *usingpos;
-
-                               /* Everything after "TRIGGER" is echoed verbatim */
-                               tgdef = PQgetvalue(result7, i, 1);
-                               usingpos = strstr(tgdef, " TRIGGER ");
-                               if (usingpos)
-                                       tgdef = usingpos + 9;
-
-                               printfPQExpBuffer(&buf, "    %s", tgdef);
-
-                               footers[count_footers++] = pg_strdup(buf.data);
+                               have_heading = false;
+                               for (i = 0; i < trigger_count; i++)
+                               {
+                                       bool            list_trigger;
+                                       const char *tgdef;
+                                       const char *usingpos;
+                                       const char *tgenabled;
+
+                                       /* Check if this trigger falls into the current category */
+                                       tgenabled = PQgetvalue(result4, i, 2);
+                                       list_trigger = false;
+                                       switch (category)
+                                       {
+                                               case 0:         if (*tgenabled == 'O' || *tgenabled == 't')
+                                                                               list_trigger = true;
+                                                                       break;
+                                               case 1:         if (*tgenabled == 'D' || *tgenabled == 'f')
+                                                                               list_trigger = true;
+                                                                       break;
+                                               case 2:         if (*tgenabled == 'A')
+                                                                               list_trigger = true;
+                                                                       break;
+                                               case 3:         if (*tgenabled == 'R')
+                                                                               list_trigger = true;
+                                                                       break;
+                                       }
+                                       if (list_trigger == false)
+                                               continue;
+
+                                       /* Print the category heading once */
+                                       if (have_heading == false)
+                                       {
+                                               switch (category)
+                                               {
+                                                       case 0:
+                                                               printfPQExpBuffer(&buf, _("Triggers:"));
+                                                               break;
+                                                       case 1:
+                                                               printfPQExpBuffer(&buf, _("Disabled Triggers:"));
+                                                               break;
+                                                       case 2:
+                                                               printfPQExpBuffer(&buf, _("Triggers firing always:"));
+                                                               break;
+                                                       case 3:
+                                                               printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
+                                                               break;
+                                                               
+                                               }
+                                               footers[count_footers++] = pg_strdup(buf.data);
+                                               have_heading = true;
+                                       }
+
+                                       /* Everything after "TRIGGER" is echoed verbatim */
+                                       tgdef = PQgetvalue(result4, i, 1);
+                                       usingpos = strstr(tgdef, " TRIGGER ");
+                                       if (usingpos)
+                                               tgdef = usingpos + 9;
+
+                                       printfPQExpBuffer(&buf, "    %s", tgdef);
+                                       footers[count_footers++] = pg_strdup(buf.data);
+                               }
                        }
                }
 
@@ -1392,7 +1460,6 @@ describeOneTableDetails(const char *schemaname,
                PQclear(result4);
                PQclear(result5);
                PQclear(result6);
-               PQclear(result7);
        }
 
        printTable(title.data, headers,
index 91afb1419901fa5aa24ac61917470a5849030667..9996a67e4078aa8a039c5b15133be03d7573811d 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_rewrite.h,v 1.27 2007/01/05 22:19:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_rewrite.h,v 1.28 2007/03/19 23:38:31 wieck Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -42,6 +42,7 @@ CATALOG(pg_rewrite,2618)
        Oid                     ev_class;
        int2            ev_attr;
        char            ev_type;
+       char            ev_enabled;
        bool            is_instead;
 
        /* NB: remaining fields must be accessed via heap_getattr */
@@ -60,13 +61,14 @@ typedef FormData_pg_rewrite *Form_pg_rewrite;
  *             compiler constants for pg_rewrite
  * ----------------
  */
-#define Natts_pg_rewrite                               7
+#define Natts_pg_rewrite                               8
 #define Anum_pg_rewrite_rulename               1
 #define Anum_pg_rewrite_ev_class               2
 #define Anum_pg_rewrite_ev_attr                        3
 #define Anum_pg_rewrite_ev_type                        4
-#define Anum_pg_rewrite_is_instead             5
-#define Anum_pg_rewrite_ev_qual                        6
-#define Anum_pg_rewrite_ev_action              7
+#define Anum_pg_rewrite_ev_enabled             5
+#define Anum_pg_rewrite_is_instead             6
+#define Anum_pg_rewrite_ev_qual                        7
+#define Anum_pg_rewrite_ev_action              8
 
 #endif   /* PG_REWRITE_H */
index df22089e3107677cae40a8dede04fbef63e3e11e..b7a71b2f0709ae65d502e2820bbf3a7cd033e9a3 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_trigger.h,v 1.27 2007/02/14 01:58:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_trigger.h,v 1.28 2007/03/19 23:38:31 wieck Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -46,7 +46,8 @@ CATALOG(pg_trigger,2620)
        Oid                     tgfoid;                 /* OID of function to be called */
        int2            tgtype;                 /* BEFORE/AFTER UPDATE/DELETE/INSERT
                                                                 * ROW/STATEMENT; see below */
-       bool            tgenabled;              /* trigger is enabled/disabled */
+       char            tgenabled;              /* trigger's firing configuration
+                                                                * WRT session_replication_role */
        bool            tgisconstraint; /* trigger is a constraint trigger */
        NameData        tgconstrname;   /* constraint name */
        Oid                     tgconstrrelid;  /* constraint's FROM table, if any */
index ac9eb7296d12e7bf5ab75c9db20ebaac58849c55..8fcd0bb6aa7e8144afd33fbdc20bd4ae1c38b318 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.61 2007/02/14 01:58:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.62 2007/03/19 23:38:31 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -78,6 +78,18 @@ typedef struct TriggerData
 #define TRIGGER_FIRED_AFTER(event)                             \
                (!TRIGGER_FIRED_BEFORE (event))
 
+/*
+ * Definitions for the replication role based firing.
+ */
+#define SESSION_REPLICATION_ROLE_ORIGIN                0
+#define SESSION_REPLICATION_ROLE_REPLICA       1
+#define SESSION_REPLICATION_ROLE_LOCAL         2
+extern int     SessionReplicationRole;
+
+#define        TRIGGER_FIRES_ON_ORIGIN                         'O'
+#define        TRIGGER_FIRES_ALWAYS                            'A'
+#define        TRIGGER_FIRES_ON_REPLICA                        'R'
+#define        TRIGGER_DISABLED                                        'D'
 
 extern Oid     CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid);
 
@@ -88,7 +100,7 @@ extern void RemoveTriggerById(Oid trigOid);
 extern void renametrig(Oid relid, const char *oldname, const char *newname);
 
 extern void EnableDisableTrigger(Relation rel, const char *tgname,
-                                        bool enable, bool skip_system);
+                                        char fires_when, bool skip_system);
 
 extern void RelationBuildTriggers(Relation relation);
 
index e24b57e8a2326a1c4c4017104eef8923401193b2..c3a2bebca68b54e3e3d333fe83ea1dca21d98674 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.342 2007/03/13 00:33:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.343 2007/03/19 23:38:32 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -897,11 +897,17 @@ typedef enum AlterTableType
        AT_SetRelOptions,                       /* SET (...) -- AM specific parameters */
        AT_ResetRelOptions,                     /* RESET (...) -- AM specific parameters */
        AT_EnableTrig,                          /* ENABLE TRIGGER name */
+       AT_EnableAlwaysTrig,            /* ENABLE ALWAYS TRIGGER name */
+       AT_EnableReplicaTrig,           /* ENABLE REPLICA TRIGGER name */
        AT_DisableTrig,                         /* DISABLE TRIGGER name */
        AT_EnableTrigAll,                       /* ENABLE TRIGGER ALL */
        AT_DisableTrigAll,                      /* DISABLE TRIGGER ALL */
        AT_EnableTrigUser,                      /* ENABLE TRIGGER USER */
        AT_DisableTrigUser,                     /* DISABLE TRIGGER USER */
+       AT_EnableRule,                          /* ENABLE RULE name */
+       AT_EnableAlwaysRule,            /* ENABLE ALWAYS RULE name */
+       AT_EnableReplicaRule,           /* ENABLE REPLICA RULE name */
+       AT_DisableRule,                         /* DISABLE RULE name */
        AT_AddInherit,                          /* INHERIT parent */
        AT_DropInherit                          /* NO INHERIT parent */
 } AlterTableType;
index d7ebbbe6bc107d46fd0901d1d1e1961a8e9bd754..17d045053e6ef19293f2fb70a656d0d9ae98092d 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/rewrite/prs2lock.h,v 1.22 2007/01/05 22:19:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/prs2lock.h,v 1.23 2007/03/19 23:38:32 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,7 @@ typedef struct RewriteRule
        AttrNumber      attrno;
        Node       *qual;
        List       *actions;
+       char            enabled;
        bool            isInstead;
 } RewriteRule;
 
index d4673f82a6c048098900eccd91a2485169a6618e..5b21cf8e797b9970d1e8537b1f3186dfe24f913d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.24 2007/03/13 00:33:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.25 2007/03/19 23:38:32 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "nodes/parsenodes.h"
 
+#define        RULE_FIRES_ON_ORIGIN    'O'
+#define        RULE_FIRES_ALWAYS               'A'
+#define        RULE_FIRES_ON_REPLICA   'R'
+#define        RULE_DISABLED                   'D'
+
 extern void DefineRule(RuleStmt *stmt, const char *queryString);
 
 extern void DefineQueryRewrite(char *rulename,
@@ -31,4 +36,7 @@ extern void RenameRewriteRule(Oid owningRel, const char *oldName,
 
 extern void setRuleCheckAsUser(Node *node, Oid userid);
 
+extern void EnableDisableRule(Relation rel, const char *rulename,
+                                 char fires_when);
+
 #endif   /* REWRITEDEFINE_H */
index 4f03cd9e0a2c5fa36f963432487664499d330739..91101a318d719fc1b81d82e182fbd16bd023e113 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/plancache.h,v 1.2 2007/03/15 23:12:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/plancache.h,v 1.3 2007/03/19 23:38:32 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -102,5 +102,6 @@ extern CachedPlan *RevalidateCachedPlan(CachedPlanSource *plansource,
                                                                                bool useResOwner);
 extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
 extern TupleDesc PlanCacheComputeResultDesc(List *stmt_list);
+extern bool HaveCachedPlans(void);
 
 #endif   /* PLANCACHE_H */
index 4065eced8211d896e1d7836d9253fbffc0689846..2963cc6616aae31030224a7fdf17869ed80aab71 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.98 2007/02/27 23:48:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.99 2007/03/19 23:38:32 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,7 +53,7 @@ typedef struct Trigger
        char       *tgname;
        Oid                     tgfoid;
        int16           tgtype;
-       bool            tgenabled;
+       char            tgenabled;
        bool            tgisconstraint;
        Oid                     tgconstrrelid;
        Oid                     tgconstraint;