Re: As proposed the complete changes to pg_trigger and pg_rewrite - Mailing list pgsql-patches

From Jan Wieck
Subject Re: As proposed the complete changes to pg_trigger and pg_rewrite
Date
Msg-id 45FA95A9.1030301@Yahoo.com
Whole thread Raw
In response to Re: As proposed the complete changes to pg_trigger and pg_rewrite  (Jan Wieck <JanWieck@Yahoo.com>)
Responses Re: As proposed the complete changes to pg_trigger and pg_rewrite
List pgsql-patches
On 3/16/2007 12:12 AM, Jan Wieck wrote:
> On 3/15/2007 11:16 PM, Tom Lane wrote:
>> The SPI_savedplans part of this is pretty bletcherous, and has been
>> overtaken by events anyway.  I'd suggest testing whether plancache.c
>> has anything in its list.
>
> [...]
>
> After a quick look it seems that another little function in there,
> checking if (cached_plans_list == NIL), would do exactly that.

Changed patch is attached.


Jan

--
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.217
diff -c -r1.217 tablecmds.c
*** src/backend/commands/tablecmds.c    13 Mar 2007 00:33:39 -0000    1.217
--- src/backend/commands/tablecmds.c    16 Mar 2007 12:06:33 -0000
***************
*** 53,58 ****
--- 53,59 ----
  #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,259 ****
  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);
  static void ATExecAddInherit(Relation rel, RangeVar *parent);
  static void ATExecDropInherit(Relation rel, RangeVar *parent);
  static void copy_relation_data(Relation rel, SMgrRelation dst);
--- 254,262 ----
  static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
  static void ATExecSetRelOptions(Relation rel, List *defList, bool isReset);
  static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
!                            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,1965 ****
--- 1958,1974 ----
              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,2150 ****
          case AT_ResetRelOptions:        /* RESET (...) */
              ATExecSetRelOptions(rel, (List *) cmd->def, true);
              break;
!         case AT_EnableTrig:        /* ENABLE TRIGGER name */
!             ATExecEnableDisableTrigger(rel, cmd->name, true, false);
              break;
          case AT_DisableTrig:    /* DISABLE TRIGGER name */
!             ATExecEnableDisableTrigger(rel, cmd->name, false, false);
              break;
          case AT_EnableTrigAll:    /* ENABLE TRIGGER ALL */
!             ATExecEnableDisableTrigger(rel, NULL, true, false);
              break;
          case AT_DisableTrigAll:    /* DISABLE TRIGGER ALL */
!             ATExecEnableDisableTrigger(rel, NULL, false, false);
              break;
          case AT_EnableTrigUser:    /* ENABLE TRIGGER USER */
!             ATExecEnableDisableTrigger(rel, NULL, true, true);
              break;
          case AT_DisableTrigUser:        /* DISABLE TRIGGER USER */
!             ATExecEnableDisableTrigger(rel, NULL, false, true);
              break;
          case AT_AddInherit:
              ATExecAddInherit(rel, (RangeVar *) cmd->def);
              break;
--- 2136,2192 ----
          case AT_ResetRelOptions:        /* RESET (...) */
              ATExecSetRelOptions(rel, (List *) cmd->def, true);
              break;
!
!         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,
!                     TRIGGER_DISABLED, false);
              break;
          case AT_EnableTrigAll:    /* ENABLE TRIGGER ALL */
!             ATExecEnableDisableTrigger(rel, NULL,
!                     TRIGGER_FIRES_ON_ORIGIN, false);
              break;
          case AT_DisableTrigAll:    /* DISABLE TRIGGER ALL */
!             ATExecEnableDisableTrigger(rel, NULL,
!                     TRIGGER_DISABLED, false);
              break;
          case AT_EnableTrigUser:    /* ENABLE TRIGGER USER */
!             ATExecEnableDisableTrigger(rel, NULL,
!                     TRIGGER_FIRES_ON_ORIGIN, true);
              break;
          case AT_DisableTrigUser:        /* DISABLE TRIGGER USER */
!             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,4386 ****
      MemSet(&trig, 0, sizeof(trig));
      trig.tgoid = InvalidOid;
      trig.tgname = fkconstraint->constr_name;
!     trig.tgenabled = TRUE;
      trig.tgisconstraint = TRUE;
      trig.tgconstrrelid = RelationGetRelid(pkrel);
      trig.tgconstraint = constraintOid;
--- 4422,4428 ----
      MemSet(&trig, 0, sizeof(trig));
      trig.tgoid = InvalidOid;
      trig.tgname = fkconstraint->constr_name;
!     trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
      trig.tgisconstraint = TRUE;
      trig.tgconstrrelid = RelationGetRelid(pkrel);
      trig.tgconstraint = constraintOid;
***************
*** 5877,5885 ****
   */
  static void
  ATExecEnableDisableTrigger(Relation rel, char *trigname,
!                            bool enable, bool skip_system)
  {
!     EnableDisableTrigger(rel, trigname, enable, skip_system);
  }

  /*
--- 5919,5939 ----
   */
  static void
  ATExecEnableDisableTrigger(Relation rel, char *trigname,
!                            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)
  {
!     EnableDisableRule(rel, trigname, fires_when);
  }

  /*
Index: src/backend/commands/trigger.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/commands/trigger.c,v
retrieving revision 1.213
diff -c -r1.213 trigger.c
*** src/backend/commands/trigger.c    14 Feb 2007 01:58:56 -0000    1.213
--- src/backend/commands/trigger.c    16 Mar 2007 12:06:33 -0000
***************
*** 54,59 ****
--- 54,66 ----
  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,276 ****
                                                    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_tgisconstraint - 1] = BoolGetDatum(stmt->isconstraint);
      values[Anum_pg_trigger_tgconstrname - 1] = DirectFunctionCall1(namein,
                                                  CStringGetDatum(constrname));
--- 277,283 ----
                                                    CStringGetDatum(trigname));
      values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
      values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
!     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,711 ****
   * EnableDisableTrigger()
   *
   *    Called by ALTER TABLE ENABLE/DISABLE TRIGGER
!  *    to change 'tgenabled' flag 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
   * skip_system: if true, skip "system" triggers (constraint triggers)
   *
   * Caller should have checked permissions for the table; here we also
--- 708,718 ----
   * EnableDisableTrigger()
   *
   *    Called by ALTER TABLE ENABLE/DISABLE TRIGGER
!  *    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 field
   * skip_system: if true, skip "system" triggers (constraint triggers)
   *
   * Caller should have checked permissions for the table; here we also
***************
*** 714,720 ****
   */
  void
  EnableDisableTrigger(Relation rel, const char *tgname,
!                      bool enable, bool skip_system)
  {
      Relation    tgrel;
      int            nkeys;
--- 721,727 ----
   */
  void
  EnableDisableTrigger(Relation rel, const char *tgname,
!                      char fires_when, bool skip_system)
  {
      Relation    tgrel;
      int            nkeys;
***************
*** 765,777 ****

          found = true;

!         if (oldtrig->tgenabled != enable)
          {
              /* 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;

              simple_heap_update(tgrel, &newtup->t_self, newtup);

--- 772,784 ----

          found = true;

!         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 = fires_when;

              simple_heap_update(tgrel, &newtup->t_self, newtup);

***************
*** 1333,1340 ****
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
          HeapTuple    newtuple;

!         if (!trigger->tgenabled)
!             continue;
          LocTriggerData.tg_trigger = trigger;
          newtuple = ExecCallTriggerFunc(&LocTriggerData,
                                         tgindx[i],
--- 1340,1357 ----
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
          HeapTuple    newtuple;

!         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,1389 ****
      {
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];

!         if (!trigger->tgenabled)
!             continue;
          LocTriggerData.tg_trigtuple = oldtuple = newtuple;
          LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
          LocTriggerData.tg_trigger = trigger;
--- 1399,1416 ----
      {
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];

!         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,1451 ****
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
          HeapTuple    newtuple;

!         if (!trigger->tgenabled)
!             continue;
          LocTriggerData.tg_trigger = trigger;
          newtuple = ExecCallTriggerFunc(&LocTriggerData,
                                         tgindx[i],
--- 1471,1488 ----
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
          HeapTuple    newtuple;

!         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,1507 ****
      {
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];

!         if (!trigger->tgenabled)
!             continue;
          LocTriggerData.tg_trigtuple = trigtuple;
          LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
          LocTriggerData.tg_trigger = trigger;
--- 1537,1554 ----
      {
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];

!         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,1582 ****
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
          HeapTuple    newtuple;

!         if (!trigger->tgenabled)
!             continue;
          LocTriggerData.tg_trigger = trigger;
          newtuple = ExecCallTriggerFunc(&LocTriggerData,
                                         tgindx[i],
--- 1622,1639 ----
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];
          HeapTuple    newtuple;

!         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,1643 ****
      {
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];

!         if (!trigger->tgenabled)
!             continue;
          LocTriggerData.tg_trigtuple = trigtuple;
          LocTriggerData.tg_newtuple = oldtuple = newtuple;
          LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
--- 1693,1710 ----
      {
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];

!         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,3274 ****
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];

          /* Ignore disabled triggers */
!         if (!trigger->tgenabled)
!             continue;

          /*
           * If this is an UPDATE of a PK table or FK table that does not change
--- 3334,3351 ----
          Trigger    *trigger = &trigdesc->triggers[tgindx[i]];

          /* Ignore disabled triggers */
!         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: src/backend/parser/gram.y
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.581
diff -c -r2.581 gram.y
*** src/backend/parser/gram.y    13 Mar 2007 00:33:41 -0000    2.581
--- src/backend/parser/gram.y    16 Mar 2007 12:06:33 -0000
***************
*** 365,371 ****

  /* 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
      ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION

      BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
--- 365,371 ----

  /* ordinary key words in alphabetical order */
  %token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
!     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,429 ****
      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

      SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
      SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
--- 422,429 ----
      QUOTE

      READ REAL REASSIGN RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME
!     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,1485 ****
--- 1480,1501 ----
                      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,1521 ****
--- 1532,1569 ----
                      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
                  {
***************
*** 8667,8672 ****
--- 8715,8721 ----
              | AGGREGATE
              | ALSO
              | ALTER
+             | ALWAYS
              | ASSERTION
              | ASSIGNMENT
              | AT
***************
*** 8812,8817 ****
--- 8861,8867 ----
              | RENAME
              | REPEATABLE
              | REPLACE
+             | REPLICA
              | RESET
              | RESTART
              | RESTRICT
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.184
diff -c -r1.184 keywords.c
*** src/backend/parser/keywords.c    25 Jan 2007 11:53:51 -0000    1.184
--- src/backend/parser/keywords.c    16 Mar 2007 12:06:33 -0000
***************
*** 42,47 ****
--- 42,48 ----
      {"all", ALL},
      {"also", ALSO},
      {"alter", ALTER},
+     {"always", ALWAYS},
      {"analyse", ANALYSE},        /* British spelling */
      {"analyze", ANALYZE},
      {"and", AND},
***************
*** 289,294 ****
--- 290,296 ----
      {"rename", RENAME},
      {"repeatable", REPEATABLE},
      {"replace", REPLACE},
+     {"replica", REPLICA},
      {"reset", RESET},
      {"restart", RESTART},
      {"restrict", RESTRICT},
Index: src/backend/rewrite/rewriteDefine.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/rewrite/rewriteDefine.c,v
retrieving revision 1.118
diff -c -r1.118 rewriteDefine.c
*** src/backend/rewrite/rewriteDefine.c    13 Mar 2007 00:33:42 -0000    1.118
--- src/backend/rewrite/rewriteDefine.c    16 Mar 2007 12:06:33 -0000
***************
*** 30,35 ****
--- 30,36 ----
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
+ #include "utils/inval.h"


  static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
***************
*** 79,84 ****
--- 80,86 ----
      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 */
***************
*** 629,634 ****
--- 631,702 ----


  /*
+  * 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.
   *
   * This is unused code at the moment.
Index: src/backend/rewrite/rewriteHandler.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/rewrite/rewriteHandler.c,v
retrieving revision 1.171
diff -c -r1.171 rewriteHandler.c
*** src/backend/rewrite/rewriteHandler.c    1 Mar 2007 18:50:28 -0000    1.171
--- src/backend/rewrite/rewriteHandler.c    16 Mar 2007 12:06:33 -0000
***************
*** 21,30 ****
--- 21,32 ----
  #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 */
***************
*** 1033,1038 ****
--- 1035,1063 ----
      {
          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: src/backend/utils/cache/plancache.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/utils/cache/plancache.c,v
retrieving revision 1.2
diff -c -r1.2 plancache.c
*** src/backend/utils/cache/plancache.c    15 Mar 2007 23:12:06 -0000    1.2
--- src/backend/utils/cache/plancache.c    16 Mar 2007 12:38:58 -0000
***************
*** 860,862 ****
--- 860,873 ----
      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: src/backend/utils/cache/relcache.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/utils/cache/relcache.c,v
retrieving revision 1.257
diff -c -r1.257 relcache.c
*** src/backend/utils/cache/relcache.c    3 Mar 2007 20:08:41 -0000    1.257
--- src/backend/utils/cache/relcache.c    16 Mar 2007 12:06:33 -0000
***************
*** 651,656 ****
--- 651,657 ----

          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: src/backend/utils/misc/guc.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.382
diff -c -r1.382 guc.c
*** src/backend/utils/misc/guc.c    13 Mar 2007 14:32:25 -0000    1.382
--- src/backend/utils/misc/guc.c    16 Mar 2007 12:18:34 -0000
***************
*** 34,39 ****
--- 34,40 ----
  #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,64 ****
--- 60,66 ----
  #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,129 ****
--- 126,133 ----

  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,231 ****
--- 230,236 ----
  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;
***************
*** 1929,1934 ****
--- 1934,1949 ----
      },

      {
+         {"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."),
              gettext_noop("If a dynamically loadable module needs to be opened and "
***************
*** 6116,6121 ****
--- 6131,6163 ----
  }

  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: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.460
diff -c -r1.460 pg_dump.c
*** src/bin/pg_dump/pg_dump.c    14 Feb 2007 01:58:57 -0000    1.460
--- src/bin/pg_dump/pg_dump.c    16 Mar 2007 12:06:33 -0000
***************
*** 3699,3713 ****
      int            i_ruletable;
      int            i_ev_type;
      int            i_is_instead;

      /* Make sure we are in proper schema */
      selectSourceSchema("pg_catalog");

!     if (g_fout->remoteVersion >= 70100)
      {
          appendPQExpBuffer(query, "SELECT "
                            "tableoid, oid, rulename, "
!                           "ev_class as ruletable, ev_type, is_instead "
                            "FROM pg_rewrite "
                            "ORDER BY oid");
      }
--- 3699,3724 ----
      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 >= 80300)
!     {
!         appendPQExpBuffer(query, "SELECT "
!                           "tableoid, oid, rulename, "
!                           "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,3722 ****
          appendPQExpBuffer(query, "SELECT "
                            "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
                            "oid, rulename, "
!                           "ev_class as ruletable, ev_type, is_instead "
                            "FROM pg_rewrite "
                            "ORDER BY oid");
      }
--- 3727,3734 ----
          appendPQExpBuffer(query, "SELECT "
                            "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
                            "oid, rulename, "
!                           "ev_class as ruletable, ev_type, is_instead, "
!                           "'O'::char as ev_enabled "
                            "FROM pg_rewrite "
                            "ORDER BY oid");
      }
***************
*** 3736,3741 ****
--- 3748,3754 ----
      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,3764 ****
--- 3772,3778 ----
          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,3962 ****
              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].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
              tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';

--- 3970,3976 ----
              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));
              tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
              tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';

***************
*** 8824,8834 ****
      }
      appendPQExpBuffer(query, ");\n");

!     if (!tginfo->tgenabled)
      {
          appendPQExpBuffer(query, "\nALTER TABLE %s ",
                            fmtId(tbinfo->dobj.name));
!         appendPQExpBuffer(query, "DISABLE TRIGGER %s;\n",
                            fmtId(tginfo->dobj.name));
      }

--- 8838,8864 ----
      }
      appendPQExpBuffer(query, ");\n");

!     if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
      {
          appendPQExpBuffer(query, "\nALTER TABLE %s ",
                            fmtId(tbinfo->dobj.name));
!         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));
      }

***************
*** 8915,8920 ****
--- 8945,8977 ----
      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
       */
      appendPQExpBuffer(delcmd, "DROP RULE %s ",
Index: src/bin/pg_dump/pg_dump.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/bin/pg_dump/pg_dump.h,v
retrieving revision 1.133
diff -c -r1.133 pg_dump.h
*** src/bin/pg_dump/pg_dump.h    19 Feb 2007 15:05:06 -0000    1.133
--- src/bin/pg_dump/pg_dump.h    16 Mar 2007 12:06:33 -0000
***************
*** 314,319 ****
--- 314,320 ----
      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,336 ****
      char       *tgconstrname;
      Oid            tgconstrrelid;
      char       *tgconstrrelname;
!     bool        tgenabled;
      bool        tgdeferrable;
      bool        tginitdeferred;
  } TriggerInfo;
--- 331,337 ----
      char       *tgconstrname;
      Oid            tgconstrrelid;
      char       *tgconstrrelname;
!     char        tgenabled;
      bool        tgdeferrable;
      bool        tginitdeferred;
  } TriggerInfo;
Index: src/bin/psql/describe.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.153
diff -c -r1.153 describe.c
*** src/bin/psql/describe.c    16 Mar 2007 08:28:01 -0000    1.153
--- src/bin/psql/describe.c    16 Mar 2007 12:44:05 -0000
***************
*** 1055,1068 ****
                     *result3 = NULL,
                     *result4 = NULL,
                     *result5 = NULL,
!                    *result6 = NULL,
!                    *result7 = 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;

--- 1055,1066 ----
                     *result3 = NULL,
                     *result4 = NULL,
                     *result5 = NULL,
!                    *result6 = NULL;
          int            check_count = 0,
                      index_count = 0,
                      foreignkey_count = 0,
                      rule_count = 0,
                      trigger_count = 0,
                      inherits_count = 0;
          int            count_footers = 0;

***************
*** 1105,1115 ****
          /* count rules */
          if (tableinfo.hasrules)
          {
!             printfPQExpBuffer(&buf,
!                               "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
                                "FROM pg_catalog.pg_rewrite r\n"
                                "WHERE r.ev_class = '%s' ORDER BY 1",
                                oid);
              result3 = PSQLexec(buf.data, false);
              if (!result3)
              {
--- 1103,1126 ----
          /* count rules */
          if (tableinfo.hasrules)
          {
!             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,1134 ****
          if (tableinfo.triggers)
          {
              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 t.tgenabled "
                                "AND t.tgconstraint = 0\n"
                                "ORDER BY 1",
                                oid);
--- 1136,1145 ----
          if (tableinfo.triggers)
          {
              printfPQExpBuffer(&buf,
!                      "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.tgconstraint = 0\n"
                                "ORDER BY 1",
                                oid);
***************
*** 1142,1168 ****
              }
              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) */
--- 1153,1158 ----
***************
*** 1181,1187 ****
                  PQclear(result2);
                  PQclear(result3);
                  PQclear(result4);
-                 PQclear(result7);
                  goto error_return;
              }
              else
--- 1171,1176 ----
***************
*** 1199,1205 ****
              PQclear(result3);
              PQclear(result4);
              PQclear(result5);
-             PQclear(result7);
              goto error_return;
          }
          else
--- 1188,1193 ----
***************
*** 1297,1359 ****
          /* 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;

!                 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++)
              {
!                 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);
              }
          }

--- 1285,1427 ----
          /* print rules */
          if (rule_count > 0)
          {
!             bool    have_heading;
!             int        category;

!             for (category = 0; category < 4; category++)
!             {
!                 have_heading = false;

!                 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)
          {
!             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++)
              {
!                 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,1398 ****
          PQclear(result4);
          PQclear(result5);
          PQclear(result6);
-         PQclear(result7);
      }

      printTable(title.data, headers,
--- 1460,1465 ----
Index: src/include/catalog/pg_rewrite.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/catalog/pg_rewrite.h,v
retrieving revision 1.27
diff -c -r1.27 pg_rewrite.h
*** src/include/catalog/pg_rewrite.h    5 Jan 2007 22:19:53 -0000    1.27
--- src/include/catalog/pg_rewrite.h    16 Mar 2007 12:06:33 -0000
***************
*** 42,47 ****
--- 42,48 ----
      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,72 ****
   *        compiler constants for pg_rewrite
   * ----------------
   */
! #define Natts_pg_rewrite                7
  #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

  #endif   /* PG_REWRITE_H */
--- 61,74 ----
   *        compiler constants for pg_rewrite
   * ----------------
   */
! #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_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: src/include/catalog/pg_trigger.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/catalog/pg_trigger.h,v
retrieving revision 1.27
diff -c -r1.27 pg_trigger.h
*** src/include/catalog/pg_trigger.h    14 Feb 2007 01:58:58 -0000    1.27
--- src/include/catalog/pg_trigger.h    16 Mar 2007 12:06:33 -0000
***************
*** 46,52 ****
      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 */
      bool        tgisconstraint; /* trigger is a constraint trigger */
      NameData    tgconstrname;    /* constraint name */
      Oid            tgconstrrelid;    /* constraint's FROM table, if any */
--- 46,53 ----
      Oid            tgfoid;            /* OID of function to be called */
      int2        tgtype;            /* BEFORE/AFTER UPDATE/DELETE/INSERT
                                   * ROW/STATEMENT; see below */
!     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: src/include/commands/trigger.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/commands/trigger.h,v
retrieving revision 1.61
diff -c -r1.61 trigger.h
*** src/include/commands/trigger.h    14 Feb 2007 01:58:58 -0000    1.61
--- src/include/commands/trigger.h    16 Mar 2007 12:06:34 -0000
***************
*** 78,83 ****
--- 78,95 ----
  #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,94 ****
  extern void renametrig(Oid relid, const char *oldname, const char *newname);

  extern void EnableDisableTrigger(Relation rel, const char *tgname,
!                      bool enable, bool skip_system);

  extern void RelationBuildTriggers(Relation relation);

--- 100,106 ----
  extern void renametrig(Oid relid, const char *oldname, const char *newname);

  extern void EnableDisableTrigger(Relation rel, const char *tgname,
!                      char fires_when, bool skip_system);

  extern void RelationBuildTriggers(Relation relation);

Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.342
diff -c -r1.342 parsenodes.h
*** src/include/nodes/parsenodes.h    13 Mar 2007 00:33:43 -0000    1.342
--- src/include/nodes/parsenodes.h    16 Mar 2007 12:06:34 -0000
***************
*** 897,907 ****
--- 897,913 ----
      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: src/include/rewrite/prs2lock.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/rewrite/prs2lock.h,v
retrieving revision 1.22
diff -c -r1.22 prs2lock.h
*** src/include/rewrite/prs2lock.h    5 Jan 2007 22:19:57 -0000    1.22
--- src/include/rewrite/prs2lock.h    16 Mar 2007 12:06:34 -0000
***************
*** 28,33 ****
--- 28,34 ----
      AttrNumber    attrno;
      Node       *qual;
      List       *actions;
+     char        enabled;
      bool        isInstead;
  } RewriteRule;

Index: src/include/rewrite/rewriteDefine.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/rewrite/rewriteDefine.h,v
retrieving revision 1.24
diff -c -r1.24 rewriteDefine.h
*** src/include/rewrite/rewriteDefine.h    13 Mar 2007 00:33:43 -0000    1.24
--- src/include/rewrite/rewriteDefine.h    16 Mar 2007 12:06:34 -0000
***************
*** 16,21 ****
--- 16,26 ----

  #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,34 ****
--- 36,42 ----

  extern void setRuleCheckAsUser(Node *node, Oid userid);

+ extern void EnableDisableRule(Relation rel, const char *rulename,
+                   char fires_when);
+
  #endif   /* REWRITEDEFINE_H */
Index: src/include/utils/plancache.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/utils/plancache.h,v
retrieving revision 1.2
diff -c -r1.2 plancache.h
*** src/include/utils/plancache.h    15 Mar 2007 23:12:07 -0000    1.2
--- src/include/utils/plancache.h    16 Mar 2007 12:41:19 -0000
***************
*** 102,106 ****
--- 102,107 ----
                                          bool useResOwner);
  extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
  extern TupleDesc PlanCacheComputeResultDesc(List *stmt_list);
+ extern bool HaveCachedPlans(void);

  #endif   /* PLANCACHE_H */
Index: src/include/utils/rel.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/utils/rel.h,v
retrieving revision 1.98
diff -c -r1.98 rel.h
*** src/include/utils/rel.h    27 Feb 2007 23:48:10 -0000    1.98
--- src/include/utils/rel.h    16 Mar 2007 12:06:34 -0000
***************
*** 53,59 ****
      char       *tgname;
      Oid            tgfoid;
      int16        tgtype;
!     bool        tgenabled;
      bool        tgisconstraint;
      Oid            tgconstrrelid;
      Oid            tgconstraint;
--- 53,59 ----
      char       *tgname;
      Oid            tgfoid;
      int16        tgtype;
!     char        tgenabled;
      bool        tgisconstraint;
      Oid            tgconstrrelid;
      Oid            tgconstraint;

pgsql-patches by date:

Previous
From: Magnus Hagander
Date:
Subject: Re: Have \da in psql show return type
Next
From: Tom Lane
Date:
Subject: Re: Additional global stats