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 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 ENABLE ALWAYS TRIGGER */ + | ENABLE_P ALWAYS TRIGGER name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableAlwaysTrig; + n->name = $4; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE REPLICA TRIGGER */ + | ENABLE_P REPLICA TRIGGER name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableReplicaTrig; + n->name = $4; + $$ = (Node *)n; + } /* ALTER TABLE ENABLE TRIGGER ALL */ | ENABLE_P TRIGGER ALL { @@ -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;