aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c78
-rw-r--r--src/backend/commands/trigger.c119
-rw-r--r--src/backend/parser/gram.y58
-rw-r--r--src/backend/parser/keywords.c4
-rw-r--r--src/backend/rewrite/rewriteDefine.c70
-rw-r--r--src/backend/rewrite/rewriteHandler.c27
-rw-r--r--src/backend/utils/cache/plancache.c13
-rw-r--r--src/backend/utils/cache/relcache.c3
-rw-r--r--src/backend/utils/misc/guc.c44
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample1
-rw-r--r--src/bin/pg_dump/pg_dump.c71
-rw-r--r--src/bin/pg_dump/pg_dump.h5
-rw-r--r--src/bin/psql/describe.c227
-rw-r--r--src/include/catalog/pg_rewrite.h12
-rw-r--r--src/include/catalog/pg_trigger.h5
-rw-r--r--src/include/commands/trigger.h16
-rw-r--r--src/include/nodes/parsenodes.h8
-rw-r--r--src/include/rewrite/prs2lock.h3
-rw-r--r--src/include/rewrite/rewriteDefine.h10
-rw-r--r--src/include/utils/plancache.h3
-rw-r--r--src/include/utils/rel.h4
21 files changed, 634 insertions, 147 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ddc62086f51..25e53a3dc43 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.217 2007/03/13 00:33:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.218 2007/03/19 23:38:29 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,7 @@
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "parser/parser.h"
+#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "storage/smgr.h"
#include "utils/acl.h"
@@ -253,7 +254,9 @@ static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
static void ATExecSetRelOptions(Relation rel, List *defList, bool isReset);
static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
- bool enable, bool skip_system);
+ char fires_when, bool skip_system);
+static void ATExecEnableDisableRule(Relation rel, char *rulename,
+ char fires_when);
static void ATExecAddInherit(Relation rel, RangeVar *parent);
static void ATExecDropInherit(Relation rel, RangeVar *parent);
static void copy_relation_data(Relation rel, SMgrRelation dst);
@@ -1955,11 +1958,17 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
pass = AT_PASS_MISC;
break;
case AT_EnableTrig: /* ENABLE TRIGGER variants */
+ case AT_EnableAlwaysTrig:
+ case AT_EnableReplicaTrig:
case AT_EnableTrigAll:
case AT_EnableTrigUser:
case AT_DisableTrig: /* DISABLE TRIGGER variants */
case AT_DisableTrigAll:
case AT_DisableTrigUser:
+ case AT_EnableRule: /* ENABLE/DISABLE RULE variants */
+ case AT_EnableAlwaysRule:
+ case AT_EnableReplicaRule:
+ case AT_DisableRule:
case AT_AddInherit: /* INHERIT / NO INHERIT */
case AT_DropInherit:
ATSimplePermissions(rel, false);
@@ -2127,24 +2136,57 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd)
case AT_ResetRelOptions: /* RESET (...) */
ATExecSetRelOptions(rel, (List *) cmd->def, true);
break;
- case AT_EnableTrig: /* ENABLE TRIGGER name */
- ATExecEnableDisableTrigger(rel, cmd->name, true, false);
+
+ case AT_EnableTrig: /* ENABLE TRIGGER name */
+ ATExecEnableDisableTrigger(rel, cmd->name,
+ TRIGGER_FIRES_ON_ORIGIN, false);
+ break;
+ case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */
+ ATExecEnableDisableTrigger(rel, cmd->name,
+ TRIGGER_FIRES_ALWAYS, false);
+ break;
+ case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */
+ ATExecEnableDisableTrigger(rel, cmd->name,
+ TRIGGER_FIRES_ON_REPLICA, false);
break;
case AT_DisableTrig: /* DISABLE TRIGGER name */
- ATExecEnableDisableTrigger(rel, cmd->name, false, false);
+ ATExecEnableDisableTrigger(rel, cmd->name,
+ TRIGGER_DISABLED, false);
break;
case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */
- ATExecEnableDisableTrigger(rel, NULL, true, false);
+ ATExecEnableDisableTrigger(rel, NULL,
+ TRIGGER_FIRES_ON_ORIGIN, false);
break;
case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
- ATExecEnableDisableTrigger(rel, NULL, false, false);
+ ATExecEnableDisableTrigger(rel, NULL,
+ TRIGGER_DISABLED, false);
break;
case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
- ATExecEnableDisableTrigger(rel, NULL, true, true);
+ ATExecEnableDisableTrigger(rel, NULL,
+ TRIGGER_FIRES_ON_ORIGIN, true);
break;
case AT_DisableTrigUser: /* DISABLE TRIGGER USER */
- ATExecEnableDisableTrigger(rel, NULL, false, true);
+ ATExecEnableDisableTrigger(rel, NULL,
+ TRIGGER_DISABLED, true);
+ break;
+
+ case AT_EnableRule: /* ENABLE RULE name */
+ ATExecEnableDisableRule(rel, cmd->name,
+ RULE_FIRES_ON_ORIGIN);
+ break;
+ case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */
+ ATExecEnableDisableRule(rel, cmd->name,
+ RULE_FIRES_ALWAYS);
+ break;
+ case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */
+ ATExecEnableDisableRule(rel, cmd->name,
+ RULE_FIRES_ON_REPLICA);
+ break;
+ case AT_DisableRule: /* DISABLE RULE name */
+ ATExecEnableDisableRule(rel, cmd->name,
+ RULE_DISABLED);
break;
+
case AT_AddInherit:
ATExecAddInherit(rel, (RangeVar *) cmd->def);
break;
@@ -4380,7 +4422,7 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint,
MemSet(&trig, 0, sizeof(trig));
trig.tgoid = InvalidOid;
trig.tgname = fkconstraint->constr_name;
- trig.tgenabled = TRUE;
+ trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
trig.tgisconstraint = TRUE;
trig.tgconstrrelid = RelationGetRelid(pkrel);
trig.tgconstraint = constraintOid;
@@ -5877,9 +5919,21 @@ copy_relation_data(Relation rel, SMgrRelation dst)
*/
static void
ATExecEnableDisableTrigger(Relation rel, char *trigname,
- bool enable, bool skip_system)
+ char fires_when, bool skip_system)
+{
+ EnableDisableTrigger(rel, trigname, fires_when, skip_system);
+}
+
+/*
+ * ALTER TABLE ENABLE/DISABLE RULE
+ *
+ * We just pass this off to rewriteDefine.c.
+ */
+static void
+ATExecEnableDisableRule(Relation rel, char *trigname,
+ char fires_when)
{
- EnableDisableTrigger(rel, trigname, enable, skip_system);
+ EnableDisableRule(rel, trigname, fires_when);
}
/*
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index c08525c2e04..e2dadb7a7e2 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.213 2007/02/14 01:58:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.214 2007/03/19 23:38:29 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -54,6 +54,13 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
static void AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event,
bool row_trigger, HeapTuple oldtup, HeapTuple newtup);
+/*
+ * SessionReplicationRole -
+ *
+ * Global variable that controls the trigger firing behaviour based
+ * on pg_trigger.tgenabled. This is maintained from misc/guc.c.
+ */
+int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
/*
* Create a trigger. Returns the OID of the created trigger.
@@ -270,7 +277,7 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
CStringGetDatum(trigname));
values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
- values[Anum_pg_trigger_tgenabled - 1] = BoolGetDatum(true);
+ values[Anum_pg_trigger_tgenabled - 1] = CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
values[Anum_pg_trigger_tgisconstraint - 1] = BoolGetDatum(stmt->isconstraint);
values[Anum_pg_trigger_tgconstrname - 1] = DirectFunctionCall1(namein,
CStringGetDatum(constrname));
@@ -701,11 +708,11 @@ renametrig(Oid relid,
* EnableDisableTrigger()
*
* Called by ALTER TABLE ENABLE/DISABLE TRIGGER
- * to change 'tgenabled' flag for the specified trigger(s)
+ * to change 'tgenabled' field for the specified trigger(s)
*
* rel: relation to process (caller must hold suitable lock on it)
* tgname: trigger to process, or NULL to scan all triggers
- * enable: new value for tgenabled flag
+ * enable: new value for tgenabled field
* skip_system: if true, skip "system" triggers (constraint triggers)
*
* Caller should have checked permissions for the table; here we also
@@ -714,7 +721,7 @@ renametrig(Oid relid,
*/
void
EnableDisableTrigger(Relation rel, const char *tgname,
- bool enable, bool skip_system)
+ char fires_when, bool skip_system)
{
Relation tgrel;
int nkeys;
@@ -765,13 +772,13 @@ EnableDisableTrigger(Relation rel, const char *tgname,
found = true;
- if (oldtrig->tgenabled != enable)
+ if (oldtrig->tgenabled != fires_when)
{
/* need to change this one ... make a copy to scribble on */
HeapTuple newtup = heap_copytuple(tuple);
Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
- newtrig->tgenabled = enable;
+ newtrig->tgenabled = fires_when;
simple_heap_update(tgrel, &newtup->t_self, newtup);
@@ -1333,8 +1340,18 @@ ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
HeapTuple newtuple;
- if (!trigger->tgenabled)
- continue;
+ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
+ else /* ORIGIN or LOCAL role */
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
tgindx[i],
@@ -1382,8 +1399,18 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
{
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
- if (!trigger->tgenabled)
- continue;
+ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
+ else /* ORIGIN or LOCAL role */
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
@@ -1444,8 +1471,18 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
HeapTuple newtuple;
- if (!trigger->tgenabled)
- continue;
+ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
+ else /* ORIGIN or LOCAL role */
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
tgindx[i],
@@ -1500,8 +1537,18 @@ ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
{
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
- if (!trigger->tgenabled)
- continue;
+ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
+ else /* ORIGIN or LOCAL role */
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
@@ -1575,8 +1622,18 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
HeapTuple newtuple;
- if (!trigger->tgenabled)
- continue;
+ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
+ else /* ORIGIN or LOCAL role */
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
tgindx[i],
@@ -1636,8 +1693,18 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
{
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
- if (!trigger->tgenabled)
- continue;
+ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
+ else /* ORIGIN or LOCAL role */
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_newtuple = oldtuple = newtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
@@ -3267,8 +3334,18 @@ AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
/* Ignore disabled triggers */
- if (!trigger->tgenabled)
- continue;
+ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
+ else /* ORIGIN or LOCAL role */
+ {
+ if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
+ trigger->tgenabled == TRIGGER_DISABLED)
+ continue;
+ }
/*
* If this is an UPDATE of a PK table or FK table that does not change
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 22d03f0b234..75404716d5a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.582 2007/03/17 19:27:12 meskes Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.583 2007/03/19 23:38:29 wieck Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -365,7 +365,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
/* ordinary key words in alphabetical order */
%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
- AGGREGATE ALL ALSO ALTER ANALYSE ANALYZE AND ANY ARRAY AS ASC
+ AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION
BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
@@ -422,8 +422,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
QUOTE
READ REAL REASSIGN RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME
- REPEATABLE REPLACE RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT
- ROLE ROLLBACK ROW ROWS RULE
+ REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE
+ RIGHT ROLE ROLLBACK ROW ROWS RULE
SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
@@ -1480,6 +1480,22 @@ alter_table_cmd:
n->name = $3;
$$ = (Node *)n;
}
+ /* ALTER TABLE <name> ENABLE ALWAYS TRIGGER <trig> */
+ | ENABLE_P ALWAYS TRIGGER name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableAlwaysTrig;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE REPLICA TRIGGER <trig> */
+ | ENABLE_P REPLICA TRIGGER name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableReplicaTrig;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
/* ALTER TABLE <name> ENABLE TRIGGER ALL */
| ENABLE_P TRIGGER ALL
{
@@ -1516,6 +1532,38 @@ alter_table_cmd:
n->subtype = AT_DisableTrigUser;
$$ = (Node *)n;
}
+ /* ALTER TABLE <name> ENABLE RULE <rule> */
+ | ENABLE_P RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableRule;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE ALWAYS RULE <rule> */
+ | ENABLE_P ALWAYS RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableAlwaysRule;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE REPLICA RULE <rule> */
+ | ENABLE_P REPLICA RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableReplicaRule;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DISABLE RULE <rule> */
+ | DISABLE_P RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DisableRule;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
/* ALTER TABLE <name> INHERIT <parent> */
| INHERIT qualified_name
{
@@ -8651,6 +8699,7 @@ unreserved_keyword:
| AGGREGATE
| ALSO
| ALTER
+ | ALWAYS
| ASSERTION
| ASSIGNMENT
| AT
@@ -8796,6 +8845,7 @@ unreserved_keyword:
| RENAME
| REPEATABLE
| REPLACE
+ | REPLICA
| RESET
| RESTART
| RESTRICT
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 368f3e06947..9be91e7e6e6 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.184 2007/01/25 11:53:51 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.185 2007/03/19 23:38:29 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,6 +42,7 @@ static const ScanKeyword ScanKeywords[] = {
{"all", ALL},
{"also", ALSO},
{"alter", ALTER},
+ {"always", ALWAYS},
{"analyse", ANALYSE}, /* British spelling */
{"analyze", ANALYZE},
{"and", AND},
@@ -289,6 +290,7 @@ static const ScanKeyword ScanKeywords[] = {
{"rename", RENAME},
{"repeatable", REPEATABLE},
{"replace", REPLACE},
+ {"replica", REPLICA},
{"reset", RESET},
{"restart", RESTART},
{"restrict", RESTRICT},
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 64a2a96f0e9..864b00f1e73 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.118 2007/03/13 00:33:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.119 2007/03/19 23:38:29 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,6 +30,7 @@
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+#include "utils/inval.h"
static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
@@ -79,6 +80,7 @@ InsertRule(char *rulname,
values[i++] = ObjectIdGetDatum(eventrel_oid); /* ev_class */
values[i++] = Int16GetDatum(evslot_index); /* ev_attr */
values[i++] = CharGetDatum(evtype + '0'); /* ev_type */
+ values[i++] = CharGetDatum(RULE_FIRES_ON_ORIGIN); /* ev_enabled */
values[i++] = BoolGetDatum(evinstead); /* is_instead */
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(evqual)); /* ev_qual */
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(actiontree)); /* ev_action */
@@ -629,6 +631,72 @@ setRuleCheckAsUser_Query(Query *qry, Oid userid)
/*
+ * Change the firing semantics of an existing rule.
+ *
+ */
+void
+EnableDisableRule(Relation rel, const char *rulename,
+ char fires_when)
+{
+ Relation pg_rewrite_desc;
+ Oid owningRel = RelationGetRelid(rel);
+ Oid eventRelationOid;
+ HeapTuple ruletup;
+ bool changed = false;
+
+ /*
+ * Find the rule tuple to change.
+ */
+ pg_rewrite_desc = heap_open(RewriteRelationId, RowExclusiveLock);
+ ruletup = SearchSysCacheCopy(RULERELNAME,
+ ObjectIdGetDatum(owningRel),
+ PointerGetDatum(rulename),
+ 0, 0);
+ if (!HeapTupleIsValid(ruletup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("rule \"%s\" for relation \"%s\" does not exist",
+ rulename, get_rel_name(owningRel))));
+
+ /*
+ * Verify that the user has appropriate permissions.
+ */
+ eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_class;
+ Assert(eventRelationOid == owningRel);
+ if (!pg_class_ownercheck(eventRelationOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+ get_rel_name(eventRelationOid));
+
+ /*
+ * Change ev_enabled if it is different from the desired new state.
+ */
+ if (DatumGetChar(((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_enabled) !=
+ fires_when)
+ {
+ ((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_enabled =
+ CharGetDatum(fires_when);
+ simple_heap_update(pg_rewrite_desc, &ruletup->t_self, ruletup);
+
+ /* keep system catalog indexes current */
+ CatalogUpdateIndexes(pg_rewrite_desc, ruletup);
+
+ changed = true;
+ }
+
+ heap_freetuple(ruletup);
+ heap_close(pg_rewrite_desc, RowExclusiveLock);
+
+ /*
+ * If we changed anything, broadcast a SI inval message to force each
+ * backend (including our own!) to rebuild relation's relcache entry.
+ * Otherwise they will fail to apply the change promptly.
+ */
+ if (changed)
+ CacheInvalidateRelcache(rel);
+}
+
+
+/*
* Rename an existing rewrite rule.
*
* This is unused code at the moment.
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index e5a1d4c7472..cd1cb54e9af 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.172 2007/03/17 00:11:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.173 2007/03/19 23:38:29 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,10 +21,12 @@
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parsetree.h"
+#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
+#include "commands/trigger.h"
/* We use a list of these to detect recursion in RewriteQuery */
@@ -1035,6 +1037,29 @@ matchLocks(CmdType event,
{
RewriteRule *oneLock = rulelocks->rules[i];
+ /*
+ * Suppress ON INSERT/UPDATE/DELETE rules that are disabled
+ * or configured to not fire during the current sessions
+ * replication role. ON SELECT rules will always be applied
+ * in order to keep views working even in LOCAL or REPLICA
+ * role.
+ */
+ if (oneLock->event != CMD_SELECT)
+ {
+ if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
+ {
+ if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
+ oneLock->enabled == RULE_DISABLED)
+ continue;
+ }
+ else /* ORIGIN or LOCAL ROLE */
+ {
+ if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
+ oneLock->enabled == RULE_DISABLED)
+ continue;
+ }
+ }
+
if (oneLock->event == event)
{
if (parsetree->commandType != CMD_SELECT ||
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 61a576d35d9..4648b05803e 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -33,7 +33,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.2 2007/03/15 23:12:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.3 2007/03/19 23:38:29 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -860,3 +860,14 @@ InvalRelid(Oid relid, LOCKMODE lockmode, InvalRelidContext *context)
if (relid == context->inval_relid)
context->plan->dead = true;
}
+
+/*
+ * HaveCachedPlans
+ * Check if the plancache has stored any plans at all.
+ */
+bool
+HaveCachedPlans(void)
+{
+ return (cached_plans_list != NIL);
+}
+
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 4ce955917a5..91b7f146b43 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.257 2007/03/03 20:08:41 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.258 2007/03/19 23:38:29 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -651,6 +651,7 @@ RelationBuildRuleLock(Relation relation)
rule->event = rewrite_form->ev_type - '0';
rule->attrno = rewrite_form->ev_attr;
+ rule->enabled = rewrite_form->ev_enabled;
rule->isInstead = rewrite_form->is_instead;
/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 8088432bac8..f921c75a60b 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.382 2007/03/13 14:32:25 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.383 2007/03/19 23:38:30 wieck Exp $
*
*--------------------------------------------------------------------
*/
@@ -34,6 +34,7 @@
#include "commands/async.h"
#include "commands/vacuum.h"
#include "commands/variable.h"
+#include "commands/trigger.h"
#include "funcapi.h"
#include "libpq/auth.h"
#include "libpq/pqformat.h"
@@ -59,6 +60,7 @@
#include "utils/guc_tables.h"
#include "utils/memutils.h"
#include "utils/pg_locale.h"
+#include "utils/plancache.h"
#include "utils/ps_status.h"
#include "utils/tzparser.h"
#include "utils/xml.h"
@@ -124,6 +126,8 @@ static const char *assign_syslog_ident(const char *ident,
static const char *assign_defaultxactisolevel(const char *newval, bool doit,
GucSource source);
+static const char *assign_session_replication_role(const char *newval, bool doit,
+ GucSource source);
static const char *assign_log_min_messages(const char *newval, bool doit,
GucSource source);
static const char *assign_client_min_messages(const char *newval,
@@ -226,6 +230,7 @@ static char *backslash_quote_string;
static char *client_encoding_string;
static char *datestyle_string;
static char *default_iso_level_string;
+static char *session_replication_role_string;
static char *locale_collate;
static char *locale_ctype;
static char *regex_flavor_string;
@@ -1929,6 +1934,16 @@ static struct config_string ConfigureNamesString[] =
},
{
+ {"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,6 +6131,33 @@ assign_defaultxactisolevel(const char *newval, bool doit, GucSource source)
}
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)
{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index cf2dfdc099e..22f9685bbdc 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -408,6 +408,7 @@
#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'
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index eef9a4c875a..90e78c36d15 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.460 2007/02/14 01:58:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.461 2007/03/19 23:38:30 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3699,15 +3699,26 @@ getRules(int *numRules)
int i_ruletable;
int i_ev_type;
int i_is_instead;
+ int i_ev_enabled;
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
- if (g_fout->remoteVersion >= 70100)
+ if (g_fout->remoteVersion >= 80300)
{
appendPQExpBuffer(query, "SELECT "
"tableoid, oid, rulename, "
- "ev_class as ruletable, ev_type, is_instead "
+ "ev_class as ruletable, ev_type, is_instead, "
+ "ev_enabled "
+ "FROM pg_rewrite "
+ "ORDER BY oid");
+ }
+ else if (g_fout->remoteVersion >= 70100)
+ {
+ appendPQExpBuffer(query, "SELECT "
+ "tableoid, oid, rulename, "
+ "ev_class as ruletable, ev_type, is_instead, "
+ "'O'::char as ev_enabled "
"FROM pg_rewrite "
"ORDER BY oid");
}
@@ -3716,7 +3727,8 @@ getRules(int *numRules)
appendPQExpBuffer(query, "SELECT "
"(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
"oid, rulename, "
- "ev_class as ruletable, ev_type, is_instead "
+ "ev_class as ruletable, ev_type, is_instead, "
+ "'O'::char as ev_enabled "
"FROM pg_rewrite "
"ORDER BY oid");
}
@@ -3736,6 +3748,7 @@ getRules(int *numRules)
i_ruletable = PQfnumber(res, "ruletable");
i_ev_type = PQfnumber(res, "ev_type");
i_is_instead = PQfnumber(res, "is_instead");
+ i_ev_enabled = PQfnumber(res, "ev_enabled");
for (i = 0; i < ntups; i++)
{
@@ -3759,6 +3772,7 @@ getRules(int *numRules)
ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
+ ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
if (ruleinfo[i].ruletable)
{
/*
@@ -3956,7 +3970,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
- tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled)) == 't';
+ tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
@@ -8824,11 +8838,27 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
}
appendPQExpBuffer(query, ");\n");
- if (!tginfo->tgenabled)
+ if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
{
appendPQExpBuffer(query, "\nALTER TABLE %s ",
fmtId(tbinfo->dobj.name));
- appendPQExpBuffer(query, "DISABLE TRIGGER %s;\n",
+ switch (tginfo->tgenabled)
+ {
+ case 'D':
+ case 'f':
+ appendPQExpBuffer(query, "DISABLE");
+ break;
+ case 'A':
+ appendPQExpBuffer(query, "ENABLE ALWAYS");
+ break;
+ case 'R':
+ appendPQExpBuffer(query, "ENABLE REPLICA");
+ break;
+ default:
+ appendPQExpBuffer(query, "ENABLE");
+ break;
+ }
+ appendPQExpBuffer(query, " TRIGGER %s;\n",
fmtId(tginfo->dobj.name));
}
@@ -8915,6 +8945,33 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
/*
+ * Add the command to alter the rules replication firing semantics
+ * if it differs from the default.
+ */
+ if (rinfo->ev_enabled != 'O')
+ {
+ appendPQExpBuffer(cmd, "ALTER TABLE %s.",
+ fmtId(tbinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(cmd, "%s ",
+ fmtId(tbinfo->dobj.name));
+ switch (rinfo->ev_enabled)
+ {
+ case 'A':
+ appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
+ fmtId(rinfo->dobj.name));
+ break;
+ case 'R':
+ appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
+ fmtId(rinfo->dobj.name));
+ break;
+ case 'D':
+ appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
+ fmtId(rinfo->dobj.name));
+ break;
+ }
+ }
+
+ /*
* DROP must be fully qualified in case same name appears in pg_catalog
*/
appendPQExpBuffer(delcmd, "DROP RULE %s ",
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index b584ab1fe01..8694376b529 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.133 2007/02/19 15:05:06 mha Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.134 2007/03/19 23:38:30 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -314,6 +314,7 @@ typedef struct _ruleInfo
TableInfo *ruletable; /* link to table the rule is for */
char ev_type;
bool is_instead;
+ char ev_enabled;
bool separate; /* TRUE if must dump as separate item */
/* separate is always true for non-ON SELECT rules */
} RuleInfo;
@@ -330,7 +331,7 @@ typedef struct _triggerInfo
char *tgconstrname;
Oid tgconstrrelid;
char *tgconstrrelname;
- bool tgenabled;
+ char tgenabled;
bool tgdeferrable;
bool tginitdeferred;
} TriggerInfo;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 5dfaf9367a1..13d3be678e8 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2007, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.154 2007/03/18 16:50:44 neilc Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.155 2007/03/19 23:38:31 wieck Exp $
*/
#include "postgres_fe.h"
#include "describe.h"
@@ -1055,14 +1055,12 @@ describeOneTableDetails(const char *schemaname,
*result3 = NULL,
*result4 = NULL,
*result5 = NULL,
- *result6 = NULL,
- *result7 = NULL;
+ *result6 = NULL;
int check_count = 0,
index_count = 0,
foreignkey_count = 0,
rule_count = 0,
trigger_count = 0,
- disabled_trigger_count = 0,
inherits_count = 0;
int count_footers = 0;
@@ -1105,11 +1103,24 @@ describeOneTableDetails(const char *schemaname,
/* count rules */
if (tableinfo.hasrules)
{
- printfPQExpBuffer(&buf,
- "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
+ if (pset.sversion < 80300)
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+ "'O'::char AS ev_enabled\n"
"FROM pg_catalog.pg_rewrite r\n"
"WHERE r.ev_class = '%s' ORDER BY 1",
oid);
+ }
+ else
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+ "ev_enabled\n"
+ "FROM pg_catalog.pg_rewrite r\n"
+ "WHERE r.ev_class = '%s' ORDER BY 1",
+ oid);
+ }
result3 = PSQLexec(buf.data, false);
if (!result3)
{
@@ -1125,10 +1136,10 @@ describeOneTableDetails(const char *schemaname,
if (tableinfo.triggers)
{
printfPQExpBuffer(&buf,
- "SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid)\n"
+ "SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid), "
+ "t.tgenabled\n"
"FROM pg_catalog.pg_trigger t\n"
"WHERE t.tgrelid = '%s' "
- "AND t.tgenabled "
"AND t.tgconstraint = 0\n"
"ORDER BY 1",
oid);
@@ -1142,27 +1153,6 @@ describeOneTableDetails(const char *schemaname,
}
else
trigger_count = PQntuples(result4);
-
- /* acquire disabled triggers as a separate list */
- printfPQExpBuffer(&buf,
- "SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid)\n"
- "FROM pg_catalog.pg_trigger t\n"
- "WHERE t.tgrelid = '%s' "
- "AND NOT t.tgenabled "
- "AND t.tgconstraint = 0\n"
- "ORDER BY 1",
- oid);
- result7 = PSQLexec(buf.data, false);
- if (!result7)
- {
- PQclear(result1);
- PQclear(result2);
- PQclear(result3);
- PQclear(result4);
- goto error_return;
- }
- else
- disabled_trigger_count = PQntuples(result7);
}
/* count foreign-key constraints (there are none if no triggers) */
@@ -1181,7 +1171,6 @@ describeOneTableDetails(const char *schemaname,
PQclear(result2);
PQclear(result3);
PQclear(result4);
- PQclear(result7);
goto error_return;
}
else
@@ -1199,7 +1188,6 @@ describeOneTableDetails(const char *schemaname,
PQclear(result3);
PQclear(result4);
PQclear(result5);
- PQclear(result7);
goto error_return;
}
else
@@ -1297,63 +1285,143 @@ describeOneTableDetails(const char *schemaname,
/* print rules */
if (rule_count > 0)
{
- printfPQExpBuffer(&buf, _("Rules:"));
- footers[count_footers++] = pg_strdup(buf.data);
- for (i = 0; i < rule_count; i++)
- {
- const char *ruledef;
-
- /* Everything after "CREATE RULE" is echoed verbatim */
- ruledef = PQgetvalue(result3, i, 1);
- ruledef += 12;
+ bool have_heading;
+ int category;
- printfPQExpBuffer(&buf, " %s", ruledef);
+ for (category = 0; category < 4; category++)
+ {
+ have_heading = false;
- footers[count_footers++] = pg_strdup(buf.data);
+ for (i = 0; i < rule_count; i++)
+ {
+ const char *ruledef;
+ bool list_rule = false;
+
+ switch (category)
+ {
+ case 0:
+ if (*PQgetvalue(result3, i, 2) == 'O')
+ list_rule = true;
+ break;
+ case 1:
+ if (*PQgetvalue(result3, i, 2) == 'D')
+ list_rule = true;
+ break;
+ case 2:
+ if (*PQgetvalue(result3, i, 2) == 'A')
+ list_rule = true;
+ break;
+ case 3:
+ if (*PQgetvalue(result3, i, 2) == 'R')
+ list_rule = true;
+ break;
+ }
+ if (!list_rule)
+ continue;
+
+ if (!have_heading)
+ {
+ switch (category)
+ {
+ case 0:
+ printfPQExpBuffer(&buf, _("Rules:"));
+ break;
+ case 1:
+ printfPQExpBuffer(&buf, _("Disabled Rules:"));
+ break;
+ case 2:
+ printfPQExpBuffer(&buf, _("Rules firing always:"));
+ break;
+ case 3:
+ printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
+ break;
+ }
+ footers[count_footers++] = pg_strdup(buf.data);
+ have_heading = true;
+ }
+
+ /* Everything after "CREATE RULE" is echoed verbatim */
+ ruledef = PQgetvalue(result3, i, 1);
+ ruledef += 12;
+ printfPQExpBuffer(&buf, " %s", ruledef);
+ footers[count_footers++] = pg_strdup(buf.data);
+ }
}
}
/* print triggers */
if (trigger_count > 0)
{
- printfPQExpBuffer(&buf, _("Triggers:"));
- footers[count_footers++] = pg_strdup(buf.data);
- for (i = 0; i < trigger_count; i++)
- {
- const char *tgdef;
- const char *usingpos;
-
- /* Everything after "TRIGGER" is echoed verbatim */
- tgdef = PQgetvalue(result4, i, 1);
- usingpos = strstr(tgdef, " TRIGGER ");
- if (usingpos)
- tgdef = usingpos + 9;
-
- printfPQExpBuffer(&buf, " %s", tgdef);
-
- footers[count_footers++] = pg_strdup(buf.data);
- }
- }
-
- /* print disabled triggers */
- if (disabled_trigger_count > 0)
- {
- printfPQExpBuffer(&buf, _("Disabled triggers:"));
- footers[count_footers++] = pg_strdup(buf.data);
- for (i = 0; i < disabled_trigger_count; i++)
+ bool have_heading;
+ int category;
+
+ /* split the output into 4 different categories.
+ * Enabled triggers, disabled triggers and the two
+ * special ALWAYS and REPLICA configurations.
+ */
+ for (category = 0; category < 4; category++)
{
- const char *tgdef;
- const char *usingpos;
-
- /* Everything after "TRIGGER" is echoed verbatim */
- tgdef = PQgetvalue(result7, i, 1);
- usingpos = strstr(tgdef, " TRIGGER ");
- if (usingpos)
- tgdef = usingpos + 9;
-
- printfPQExpBuffer(&buf, " %s", tgdef);
-
- footers[count_footers++] = pg_strdup(buf.data);
+ have_heading = false;
+ for (i = 0; i < trigger_count; i++)
+ {
+ bool list_trigger;
+ const char *tgdef;
+ const char *usingpos;
+ const char *tgenabled;
+
+ /* Check if this trigger falls into the current category */
+ tgenabled = PQgetvalue(result4, i, 2);
+ list_trigger = false;
+ switch (category)
+ {
+ case 0: if (*tgenabled == 'O' || *tgenabled == 't')
+ list_trigger = true;
+ break;
+ case 1: if (*tgenabled == 'D' || *tgenabled == 'f')
+ list_trigger = true;
+ break;
+ case 2: if (*tgenabled == 'A')
+ list_trigger = true;
+ break;
+ case 3: if (*tgenabled == 'R')
+ list_trigger = true;
+ break;
+ }
+ if (list_trigger == false)
+ continue;
+
+ /* Print the category heading once */
+ if (have_heading == false)
+ {
+ switch (category)
+ {
+ case 0:
+ printfPQExpBuffer(&buf, _("Triggers:"));
+ break;
+ case 1:
+ printfPQExpBuffer(&buf, _("Disabled Triggers:"));
+ break;
+ case 2:
+ printfPQExpBuffer(&buf, _("Triggers firing always:"));
+ break;
+ case 3:
+ printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
+ break;
+
+ }
+ footers[count_footers++] = pg_strdup(buf.data);
+ have_heading = true;
+ }
+
+ /* Everything after "TRIGGER" is echoed verbatim */
+ tgdef = PQgetvalue(result4, i, 1);
+ usingpos = strstr(tgdef, " TRIGGER ");
+ if (usingpos)
+ tgdef = usingpos + 9;
+
+ printfPQExpBuffer(&buf, " %s", tgdef);
+ footers[count_footers++] = pg_strdup(buf.data);
+ }
}
}
@@ -1392,7 +1460,6 @@ describeOneTableDetails(const char *schemaname,
PQclear(result4);
PQclear(result5);
PQclear(result6);
- PQclear(result7);
}
printTable(title.data, headers,
diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h
index 91afb141990..9996a67e407 100644
--- a/src/include/catalog/pg_rewrite.h
+++ b/src/include/catalog/pg_rewrite.h
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_rewrite.h,v 1.27 2007/01/05 22:19:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_rewrite.h,v 1.28 2007/03/19 23:38:31 wieck Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -42,6 +42,7 @@ CATALOG(pg_rewrite,2618)
Oid ev_class;
int2 ev_attr;
char ev_type;
+ char ev_enabled;
bool is_instead;
/* NB: remaining fields must be accessed via heap_getattr */
@@ -60,13 +61,14 @@ typedef FormData_pg_rewrite *Form_pg_rewrite;
* compiler constants for pg_rewrite
* ----------------
*/
-#define Natts_pg_rewrite 7
+#define Natts_pg_rewrite 8
#define Anum_pg_rewrite_rulename 1
#define Anum_pg_rewrite_ev_class 2
#define Anum_pg_rewrite_ev_attr 3
#define Anum_pg_rewrite_ev_type 4
-#define Anum_pg_rewrite_is_instead 5
-#define Anum_pg_rewrite_ev_qual 6
-#define Anum_pg_rewrite_ev_action 7
+#define Anum_pg_rewrite_ev_enabled 5
+#define Anum_pg_rewrite_is_instead 6
+#define Anum_pg_rewrite_ev_qual 7
+#define Anum_pg_rewrite_ev_action 8
#endif /* PG_REWRITE_H */
diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h
index df22089e310..b7a71b2f070 100644
--- a/src/include/catalog/pg_trigger.h
+++ b/src/include/catalog/pg_trigger.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_trigger.h,v 1.27 2007/02/14 01:58:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_trigger.h,v 1.28 2007/03/19 23:38:31 wieck Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -46,7 +46,8 @@ CATALOG(pg_trigger,2620)
Oid tgfoid; /* OID of function to be called */
int2 tgtype; /* BEFORE/AFTER UPDATE/DELETE/INSERT
* ROW/STATEMENT; see below */
- bool tgenabled; /* trigger is enabled/disabled */
+ char tgenabled; /* trigger's firing configuration
+ * WRT session_replication_role */
bool tgisconstraint; /* trigger is a constraint trigger */
NameData tgconstrname; /* constraint name */
Oid tgconstrrelid; /* constraint's FROM table, if any */
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index ac9eb7296d1..8fcd0bb6aa7 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.61 2007/02/14 01:58:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.62 2007/03/19 23:38:31 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -78,6 +78,18 @@ typedef struct TriggerData
#define TRIGGER_FIRED_AFTER(event) \
(!TRIGGER_FIRED_BEFORE (event))
+/*
+ * Definitions for the replication role based firing.
+ */
+#define SESSION_REPLICATION_ROLE_ORIGIN 0
+#define SESSION_REPLICATION_ROLE_REPLICA 1
+#define SESSION_REPLICATION_ROLE_LOCAL 2
+extern int SessionReplicationRole;
+
+#define TRIGGER_FIRES_ON_ORIGIN 'O'
+#define TRIGGER_FIRES_ALWAYS 'A'
+#define TRIGGER_FIRES_ON_REPLICA 'R'
+#define TRIGGER_DISABLED 'D'
extern Oid CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid);
@@ -88,7 +100,7 @@ extern void RemoveTriggerById(Oid trigOid);
extern void renametrig(Oid relid, const char *oldname, const char *newname);
extern void EnableDisableTrigger(Relation rel, const char *tgname,
- bool enable, bool skip_system);
+ char fires_when, bool skip_system);
extern void RelationBuildTriggers(Relation relation);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e24b57e8a23..c3a2bebca68 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.342 2007/03/13 00:33:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.343 2007/03/19 23:38:32 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -897,11 +897,17 @@ typedef enum AlterTableType
AT_SetRelOptions, /* SET (...) -- AM specific parameters */
AT_ResetRelOptions, /* RESET (...) -- AM specific parameters */
AT_EnableTrig, /* ENABLE TRIGGER name */
+ AT_EnableAlwaysTrig, /* ENABLE ALWAYS TRIGGER name */
+ AT_EnableReplicaTrig, /* ENABLE REPLICA TRIGGER name */
AT_DisableTrig, /* DISABLE TRIGGER name */
AT_EnableTrigAll, /* ENABLE TRIGGER ALL */
AT_DisableTrigAll, /* DISABLE TRIGGER ALL */
AT_EnableTrigUser, /* ENABLE TRIGGER USER */
AT_DisableTrigUser, /* DISABLE TRIGGER USER */
+ AT_EnableRule, /* ENABLE RULE name */
+ AT_EnableAlwaysRule, /* ENABLE ALWAYS RULE name */
+ AT_EnableReplicaRule, /* ENABLE REPLICA RULE name */
+ AT_DisableRule, /* DISABLE RULE name */
AT_AddInherit, /* INHERIT parent */
AT_DropInherit /* NO INHERIT parent */
} AlterTableType;
diff --git a/src/include/rewrite/prs2lock.h b/src/include/rewrite/prs2lock.h
index d7ebbbe6bc1..17d045053e6 100644
--- a/src/include/rewrite/prs2lock.h
+++ b/src/include/rewrite/prs2lock.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/rewrite/prs2lock.h,v 1.22 2007/01/05 22:19:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/prs2lock.h,v 1.23 2007/03/19 23:38:32 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,7 @@ typedef struct RewriteRule
AttrNumber attrno;
Node *qual;
List *actions;
+ char enabled;
bool isInstead;
} RewriteRule;
diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h
index d4673f82a6c..5b21cf8e797 100644
--- a/src/include/rewrite/rewriteDefine.h
+++ b/src/include/rewrite/rewriteDefine.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.24 2007/03/13 00:33:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.25 2007/03/19 23:38:32 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,6 +16,11 @@
#include "nodes/parsenodes.h"
+#define RULE_FIRES_ON_ORIGIN 'O'
+#define RULE_FIRES_ALWAYS 'A'
+#define RULE_FIRES_ON_REPLICA 'R'
+#define RULE_DISABLED 'D'
+
extern void DefineRule(RuleStmt *stmt, const char *queryString);
extern void DefineQueryRewrite(char *rulename,
@@ -31,4 +36,7 @@ extern void RenameRewriteRule(Oid owningRel, const char *oldName,
extern void setRuleCheckAsUser(Node *node, Oid userid);
+extern void EnableDisableRule(Relation rel, const char *rulename,
+ char fires_when);
+
#endif /* REWRITEDEFINE_H */
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index 4f03cd9e0a2..91101a318d7 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/plancache.h,v 1.2 2007/03/15 23:12:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/plancache.h,v 1.3 2007/03/19 23:38:32 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -102,5 +102,6 @@ extern CachedPlan *RevalidateCachedPlan(CachedPlanSource *plansource,
bool useResOwner);
extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
extern TupleDesc PlanCacheComputeResultDesc(List *stmt_list);
+extern bool HaveCachedPlans(void);
#endif /* PLANCACHE_H */
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 4065eced821..2963cc6616a 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.98 2007/02/27 23:48:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.99 2007/03/19 23:38:32 wieck Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,7 +53,7 @@ typedef struct Trigger
char *tgname;
Oid tgfoid;
int16 tgtype;
- bool tgenabled;
+ char tgenabled;
bool tgisconstraint;
Oid tgconstrrelid;
Oid tgconstraint;