Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.145
diff -c -r2.145 catalogs.sgml
*** doc/src/sgml/catalogs.sgml 14 Feb 2007 01:58:55 -0000 2.145
--- doc/src/sgml/catalogs.sgml 17 Mar 2007 20:04:50 -0000
***************
*** 3640,3645 ****
--- 3640,3659 ----
+ ev_enabled
+ char
+
+
+ Controls in which modes
+ the rule fires.
+ O> = rule fires in origin> and local> modes,
+ D> = rule is disabled,
+ R> = rule fires in replica> mode,
+ A> = rule fires always.
+
+
+
+
is_instead
bool
***************
*** 4178,4186 ****
tgenabled
! bool
! True if trigger is enabled
--- 4192,4207 ----
tgenabled
! char
!
! Controls in which modes
! the trigger fires.
! O> = trigger fires in origin> and local> modes,
! D> = trigger is disabled,
! R> = trigger fires in replica> mode,
! A> = trigger fires always.
!
Index: doc/src/sgml/config.sgml
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/doc/src/sgml/config.sgml,v
retrieving revision 1.115
diff -c -r1.115 config.sgml
*** doc/src/sgml/config.sgml 6 Mar 2007 02:06:12 -0000 1.115
--- doc/src/sgml/config.sgml 17 Mar 2007 20:49:32 -0000
***************
*** 3523,3528 ****
--- 3523,3545 ----
+
+ session_replication_role (string)
+
+ session_replication_role> configuration parameter
+
+
+
+ Controls the trigger and rule firing for the current session.
+ See 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 origin>,
+ replica> and local>.
+
+
+
+
vacuum_freeze_min_age (integer)
Index: doc/src/sgml/ref/alter_table.sgml
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/doc/src/sgml/ref/alter_table.sgml,v
retrieving revision 1.94
diff -c -r1.94 alter_table.sgml
*** doc/src/sgml/ref/alter_table.sgml 1 Feb 2007 00:28:18 -0000 1.94
--- doc/src/sgml/ref/alter_table.sgml 17 Mar 2007 20:57:25 -0000
***************
*** 43,48 ****
--- 43,54 ----
DROP CONSTRAINT constraint_name [ RESTRICT | CASCADE ]
DISABLE TRIGGER [ trigger_name | ALL | USER ]
ENABLE TRIGGER [ trigger_name | ALL | USER ]
+ ENABLE REPLICA TRIGGER trigger_name
+ ENABLE ALWAYS TRIGGER trigger_name
+ DISABLE RULE rewrite_rule_name
+ ENABLE RULE rewrite_rule_name
+ ENABLE REPLICA RULE rewrite_rule_name
+ ENABLE ALWAYS RULE rewrite_rule_name
CLUSTER ON index_name
SET WITHOUT CLUSTER
SET WITHOUT OIDS
***************
*** 193,202 ****
! DISABLE/ENABLE TRIGGER
! These forms disable or enable 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
--- 199,208 ----
! DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER
! 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,212 ****
--- 213,239 ----
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 . Simply ENABLEd
+ triggers will fire when the replication role is origin>
+ (the default) or local>. Triggers configured ENABLE REPLICA
+ will only fire if the session is in replica> mode and triggers
+ configured ENABLE ALWAYS will fire regardless of the current replication
+ mode.
+
+
+
+
+
+ DISABLE/ENABLE [ REPLICA | ALWAYS ] RULE
+
+
+ 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.
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.582
diff -c -r2.582 gram.y
*** src/backend/parser/gram.y 17 Mar 2007 19:27:12 -0000 2.582
--- src/backend/parser/gram.y 17 Mar 2007 21:14:04 -0000
***************
*** 365,371 ****
/* ordinary key words in alphabetical order */
%token 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 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 ENABLE ALWAYS TRIGGER */
+ | ENABLE_P ALWAYS TRIGGER name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableAlwaysTrig;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE ENABLE REPLICA TRIGGER */
+ | ENABLE_P REPLICA TRIGGER name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableReplicaTrig;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
/* ALTER TABLE ENABLE TRIGGER ALL */
| ENABLE_P TRIGGER ALL
{
***************
*** 1516,1521 ****
--- 1532,1569 ----
n->subtype = AT_DisableTrigUser;
$$ = (Node *)n;
}
+ /* ALTER TABLE ENABLE RULE */
+ | ENABLE_P RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableRule;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE ENABLE ALWAYS RULE */
+ | ENABLE_P ALWAYS RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableAlwaysRule;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE ENABLE REPLICA RULE */
+ | ENABLE_P REPLICA RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableReplicaRule;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE DISABLE RULE */
+ | DISABLE_P RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DisableRule;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
/* ALTER TABLE INHERIT */
| INHERIT qualified_name
{
***************
*** 8651,8656 ****
--- 8699,8705 ----
| AGGREGATE
| ALSO
| ALTER
+ | ALWAYS
| ASSERTION
| ASSIGNMENT
| AT
***************
*** 8796,8801 ****
--- 8845,8851 ----
| 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.172
diff -c -r1.172 rewriteHandler.c
*** src/backend/rewrite/rewriteHandler.c 17 Mar 2007 00:11:04 -0000 1.172
--- src/backend/rewrite/rewriteHandler.c 17 Mar 2007 17:53:44 -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 */
***************
*** 1035,1040 ****
--- 1037,1065 ----
{
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/backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.212
diff -c -r1.212 postgresql.conf.sample
*** src/backend/utils/misc/postgresql.conf.sample 6 Mar 2007 02:06:14 -0000 1.212
--- src/backend/utils/misc/postgresql.conf.sample 17 Mar 2007 19:42:02 -0000
***************
*** 408,413 ****
--- 408,414 ----
#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: 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;