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;