aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/trigger.c
diff options
context:
space:
mode:
authorNeil Conway <neilc@samurai.com>2005-05-30 07:20:59 +0000
committerNeil Conway <neilc@samurai.com>2005-05-30 07:20:59 +0000
commitadfeef55cbcc5dc72a772777f88c1be05a70dfee (patch)
treeb7d0a756c03241faa60c0ea416d68040741be4d0 /src/backend/commands/trigger.c
parentf99b75b0a0ee642a87a10726ba8f6831c1c95cc7 (diff)
downloadpostgresql-adfeef55cbcc5dc72a772777f88c1be05a70dfee.tar.gz
postgresql-adfeef55cbcc5dc72a772777f88c1be05a70dfee.zip
When enqueueing after-row triggers for updates of a table with a foreign
key, compare the new and old row versions. If the foreign key column has not changed, we needn't enqueue the trigger, since the update cannot violate the foreign key. This optimization was previously applied in the RI trigger function, but it is more efficient to avoid firing the trigger altogether. Per recent discussion on pgsql-hackers. Also add a regression test for some unintuitive foreign key behavior, and refactor some code that deals with the OIDs of the various RI trigger functions.
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r--src/backend/commands/trigger.c75
1 files changed, 34 insertions, 41 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index a78ad890b3c..e0cfd334855 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.188 2005/05/06 17:24:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.189 2005/05/30 07:20:58 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2994,54 +2994,47 @@ AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
continue;
/*
- * If it is an RI UPDATE trigger, and the referenced keys have
- * not changed, short-circuit queuing of the event; there's no
- * need to fire the trigger.
+ * If this is an UPDATE of a PK table or FK table that does
+ * not change the PK or FK respectively, we can skip queuing
+ * the event: there is no need to fire the trigger.
*/
if ((event & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_UPDATE)
{
- bool is_ri_trigger;
-
- switch (trigger->tgfoid)
+ switch (RI_FKey_trigger_type(trigger->tgfoid))
{
- case F_RI_FKEY_NOACTION_UPD:
- case F_RI_FKEY_CASCADE_UPD:
- case F_RI_FKEY_RESTRICT_UPD:
- case F_RI_FKEY_SETNULL_UPD:
- case F_RI_FKEY_SETDEFAULT_UPD:
- is_ri_trigger = true;
+ case RI_TRIGGER_PK:
+ /* Update on PK table */
+ if (RI_FKey_keyequal_upd_pk(trigger, rel, oldtup, newtup))
+ {
+ /* key unchanged, so skip queuing this event */
+ continue;
+ }
break;
- default:
- is_ri_trigger = false;
+ case RI_TRIGGER_FK:
+ /*
+ * Update on FK table
+ *
+ * There is one exception when updating FK tables:
+ * if the updated row was inserted by our own
+ * transaction and the FK is deferred, we still
+ * need to fire the trigger. This is because our
+ * UPDATE will invalidate the INSERT so the
+ * end-of-transaction INSERT RI trigger will not
+ * do anything, so we have to do the check for the
+ * UPDATE anyway.
+ */
+ if (HeapTupleHeaderGetXmin(oldtup->t_data) !=
+ GetCurrentTransactionId() &&
+ RI_FKey_keyequal_upd_fk(trigger, rel, oldtup, newtup))
+ {
+ continue;
+ }
break;
- }
- if (is_ri_trigger)
- {
- TriggerData LocTriggerData;
-
- LocTriggerData.type = T_TriggerData;
- LocTriggerData.tg_event =
- TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_ROW;
- LocTriggerData.tg_relation = rel;
- LocTriggerData.tg_trigtuple = oldtup;
- LocTriggerData.tg_newtuple = newtup;
- LocTriggerData.tg_trigger = trigger;
- /*
- * We do not currently know which buffers the passed tuples
- * are in, but it does not matter because RI_FKey_keyequal_upd
- * does not care. We could expand the API of this function
- * if it becomes necessary to set these fields accurately.
- */
- LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
- LocTriggerData.tg_newtuplebuf = InvalidBuffer;
-
- if (RI_FKey_keyequal_upd(&LocTriggerData))
- {
- /* key unchanged, so skip queuing this event */
- continue;
- }
+ case RI_TRIGGER_NONE:
+ /* Not an FK trigger */
+ break;
}
}