Attached is the implementation of the proposed changes as a patch for
discussion.
The chosen syntax is backward compatible and uses
ALTER TABLE <tab> ENABLE TRIGGER <trig> (fires on origin - default)
ALTER TABLE <tab> DISABLE TRIGGER <trig> (disabled)
ALTER TABLE <tab> ENABLE REPLICA TRIGGER <trig> (fires on replica only)
ALTER TABLE <tab> ENABLE ALWAYS TRIGGER <trig> (fires always)
A sessions current role is controlled by the PG_SUSET GUC
session_replication_role. The possible states are origin, replica and
local. The local state is identical to origin with respect to trigger
firing. It is intended to be used to issue statements that do not get
replicated at all.
The commands psql and pg_dump are adjusted in a backward compatible
manner. Although I noticed that psql currently is incompatible with at
least 8.1 databases due to querying indisvalid on \d.
Comments?
Jan
--
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me. #
#================================================== JanWieck@Yahoo.com #
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.213
diff -u -r1.213 tablecmds.c
--- src/backend/commands/tablecmds.c 2 Feb 2007 00:07:02 -0000 1.213
+++ src/backend/commands/tablecmds.c 2 Feb 2007 20:27:47 -0000
@@ -3,7 +3,7 @@
* tablecmds.c
* Commands for creating and altering table structures and settings
*
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2007, PostgreSQL Global DevelopmEnt Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
@@ -252,7 +252,7 @@
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 ATExecAddInherit(Relation rel, RangeVar *parent);
static void ATExecDropInherit(Relation rel, RangeVar *parent);
static void copy_relation_data(Relation rel, SMgrRelation dst);
@@ -2192,6 +2192,8 @@
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 */
@@ -2364,24 +2366,40 @@
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_AddInherit:
ATExecAddInherit(rel, (RangeVar *) cmd->def);
break;
@@ -4549,7 +4567,7 @@
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.tgdeferrable = FALSE;
@@ -6157,9 +6175,9 @@
*/
static void
ATExecEnableDisableTrigger(Relation rel, char *trigname,
- bool enable, bool skip_system)
+ char fires_when, bool skip_system)
{
- EnableDisableTrigger(rel, trigname, enable, skip_system);
+ EnableDisableTrigger(rel, trigname, fires_when, skip_system);
}
/*
Index: src/backend/commands/trigger.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/commands/trigger.c,v
retrieving revision 1.212
diff -u -r1.212 trigger.c
--- src/backend/commands/trigger.c 25 Jan 2007 04:17:46 -0000 1.212
+++ src/backend/commands/trigger.c 2 Feb 2007 19:04:58 -0000
@@ -53,6 +53,13 @@
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.
@@ -305,7 +312,7 @@
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));
@@ -723,11 +730,11 @@
* 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
@@ -736,7 +743,7 @@
*/
void
EnableDisableTrigger(Relation rel, const char *tgname,
- bool enable, bool skip_system)
+ char fires_when, bool skip_system)
{
Relation tgrel;
int nkeys;
@@ -787,13 +794,13 @@
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);
@@ -1352,8 +1359,18 @@
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],
@@ -1401,8 +1418,18 @@
{
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;
@@ -1463,8 +1490,18 @@
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],
@@ -1519,8 +1556,18 @@
{
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;
@@ -1594,8 +1641,18 @@
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],
@@ -1655,8 +1712,18 @@
{
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;
@@ -3286,8 +3353,18 @@
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
Index: src/backend/parser/gram.y
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.579
diff -u -r2.579 gram.y
--- src/backend/parser/gram.y 3 Feb 2007 14:06:54 -0000 2.579
+++ src/backend/parser/gram.y 3 Feb 2007 20:53:24 -0000
@@ -363,7 +363,7 @@
/* 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
@@ -420,8 +420,8 @@
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
@@ -1478,6 +1478,22 @@
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
{
@@ -8654,6 +8670,7 @@
| AGGREGATE
| ALSO
| ALTER
+ | ALWAYS
| ASSERTION
| ASSIGNMENT
| AT
@@ -8799,6 +8816,7 @@
| RENAME
| REPEATABLE
| REPLACE
+ | REPLICA
| RESET
| RESTART
| RESTRICT
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.184
diff -u -r1.184 keywords.c
--- src/backend/parser/keywords.c 25 Jan 2007 11:53:51 -0000 1.184
+++ src/backend/parser/keywords.c 2 Feb 2007 20:22:24 -0000
@@ -42,6 +42,7 @@
{"all", ALL},
{"also", ALSO},
{"alter", ALTER},
+ {"always", ALWAYS},
{"analyse", ANALYSE}, /* British spelling */
{"analyze", ANALYZE},
{"and", AND},
@@ -289,6 +290,7 @@
{"rename", RENAME},
{"repeatable", REPEATABLE},
{"replace", REPLACE},
+ {"replica", REPLICA},
{"reset", RESET},
{"restart", RESTART},
{"restrict", RESTRICT},
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.372
diff -u -r1.372 guc.c
--- src/backend/utils/misc/guc.c 1 Feb 2007 19:10:28 -0000 1.372
+++ src/backend/utils/misc/guc.c 2 Feb 2007 18:03:25 -0000
@@ -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"
@@ -120,6 +121,8 @@
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,
@@ -222,6 +225,7 @@
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;
@@ -1917,6 +1921,16 @@
},
{
+ {"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 "
@@ -6099,6 +6113,29 @@
}
static const char *
+assign_session_replication_role(const char *newval, bool doit, GucSource source)
+{
+ if (pg_strcasecmp(newval, "origin") == 0)
+ {
+ if (doit)
+ SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
+ }
+ else if (pg_strcasecmp(newval, "replica") == 0)
+ {
+ if (doit)
+ SessionReplicationRole = SESSION_REPLICATION_ROLE_REPLICA;
+ }
+ else if (pg_strcasecmp(newval, "local") == 0)
+ {
+ if (doit)
+ SessionReplicationRole = SESSION_REPLICATION_ROLE_LOCAL;
+ }
+ else
+ return NULL;
+ return newval;
+}
+
+static const char *
assign_log_min_messages(const char *newval,
bool doit, GucSource source)
{
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.459
diff -u -r1.459 pg_dump.c
--- src/bin/pg_dump/pg_dump.c 25 Jan 2007 03:30:43 -0000 1.459
+++ src/bin/pg_dump/pg_dump.c 2 Feb 2007 22:34:05 -0000
@@ -3937,7 +3937,7 @@
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';
@@ -8805,11 +8805,27 @@
}
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));
}
Index: src/bin/pg_dump/pg_dump.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/bin/pg_dump/pg_dump.h,v
retrieving revision 1.132
diff -u -r1.132 pg_dump.h
--- src/bin/pg_dump/pg_dump.h 23 Jan 2007 17:54:50 -0000 1.132
+++ src/bin/pg_dump/pg_dump.h 2 Feb 2007 22:27:21 -0000
@@ -312,7 +312,7 @@
char *tgconstrname;
Oid tgconstrrelid;
char *tgconstrrelname;
- bool tgenabled;
+ char tgenabled;
bool tgdeferrable;
bool tginitdeferred;
} TriggerInfo;
Index: src/bin/psql/describe.c
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.150
diff -u -r1.150 describe.c
--- src/bin/psql/describe.c 20 Jan 2007 21:17:30 -0000 1.150
+++ src/bin/psql/describe.c 2 Feb 2007 22:04:52 -0000
@@ -1054,14 +1054,12 @@
*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;
@@ -1124,10 +1122,10 @@
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 (NOT t.tgisconstraint "
" OR NOT EXISTS"
" (SELECT 1 FROM pg_catalog.pg_depend d "
@@ -1145,31 +1143,6 @@
}
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 (NOT t.tgisconstraint "
- " OR NOT EXISTS"
- " (SELECT 1 FROM pg_catalog.pg_depend d "
- " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid =
c.oid)"
- " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype =
'f'))"
- " 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) */
@@ -1188,7 +1161,6 @@
PQclear(result2);
PQclear(result3);
PQclear(result4);
- PQclear(result7);
goto error_return;
}
else
@@ -1206,7 +1178,6 @@
PQclear(result3);
PQclear(result4);
PQclear(result5);
- PQclear(result7);
goto error_return;
}
else
@@ -1323,44 +1294,77 @@
/* 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);
- }
- }
+ bool have_heading;
+ int category;
- /* 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++)
+ /* 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;
+ 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);
+ printfPQExpBuffer(&buf, " %s", tgdef);
- footers[count_footers++] = pg_strdup(buf.data);
+ footers[count_footers++] = pg_strdup(buf.data);
+ }
}
}
@@ -1399,7 +1403,6 @@
PQclear(result4);
PQclear(result5);
PQclear(result6);
- PQclear(result7);
}
printTable(title.data, headers,
Index: src/include/catalog/pg_trigger.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/catalog/pg_trigger.h,v
retrieving revision 1.26
diff -u -r1.26 pg_trigger.h
--- src/include/catalog/pg_trigger.h 5 Jan 2007 22:19:53 -0000 1.26
+++ src/include/catalog/pg_trigger.h 2 Feb 2007 18:15:45 -0000
@@ -37,7 +37,8 @@
Oid tgfoid; /* OID of function to be called */
int2 tgtype; /* BEFORE/AFTER UPDATE/DELETE/INSERT
* ROW/STATEMENT */
- bool tgenabled; /* trigger is enabled/disabled */
+ char tgenabled; /* trigger's firing configuration
+ * WRT session_replication_role */
bool tgisconstraint; /* trigger is a RI constraint */
NameData tgconstrname; /* RI constraint name */
Oid tgconstrrelid; /* RI table of foreign key definition */
Index: src/include/commands/trigger.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/commands/trigger.h,v
retrieving revision 1.60
diff -u -r1.60 trigger.h
--- src/include/commands/trigger.h 5 Jan 2007 22:19:54 -0000 1.60
+++ src/include/commands/trigger.h 2 Feb 2007 18:54:50 -0000
@@ -104,6 +104,15 @@
#define RI_MAX_NUMKEYS INDEX_MAX_KEYS
#define RI_MAX_ARGUMENTS (RI_FIRST_ATTNAME_ARGNO + (RI_MAX_NUMKEYS * 2))
+#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, bool forConstraint);
@@ -114,7 +123,7 @@
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);
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.340
diff -u -r1.340 parsenodes.h
--- src/include/nodes/parsenodes.h 3 Feb 2007 14:06:55 -0000 1.340
+++ src/include/nodes/parsenodes.h 3 Feb 2007 20:55:11 -0000
@@ -936,6 +936,8 @@
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 */
Index: src/include/utils/rel.h
===================================================================
RCS file: /usr/local/pgsql/CvsRoot/pgsql/src/include/utils/rel.h,v
retrieving revision 1.96
diff -u -r1.96 rel.h
--- src/include/utils/rel.h 25 Jan 2007 02:17:26 -0000 1.96
+++ src/include/utils/rel.h 2 Feb 2007 22:13:59 -0000
@@ -53,7 +53,7 @@
char *tgname;
Oid tgfoid;
int16 tgtype;
- bool tgenabled;
+ char tgenabled;
bool tgisconstraint;
Oid tgconstrrelid;
bool tgdeferrable;