diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/tablecmds.c | 78 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 119 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 58 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 4 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteDefine.c | 70 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 27 | ||||
-rw-r--r-- | src/backend/utils/cache/plancache.c | 13 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 3 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 44 | ||||
-rw-r--r-- | src/backend/utils/misc/postgresql.conf.sample | 1 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 71 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.h | 5 | ||||
-rw-r--r-- | src/bin/psql/describe.c | 227 | ||||
-rw-r--r-- | src/include/catalog/pg_rewrite.h | 12 | ||||
-rw-r--r-- | src/include/catalog/pg_trigger.h | 5 | ||||
-rw-r--r-- | src/include/commands/trigger.h | 16 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 8 | ||||
-rw-r--r-- | src/include/rewrite/prs2lock.h | 3 | ||||
-rw-r--r-- | src/include/rewrite/rewriteDefine.h | 10 | ||||
-rw-r--r-- | src/include/utils/plancache.h | 3 | ||||
-rw-r--r-- | src/include/utils/rel.h | 4 |
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; |