diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-04-11 19:51:32 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-04-11 19:51:32 +0000 |
commit | fa57fd1c0a4b9dee0bbd932c20d773d56a88a78f (patch) | |
tree | 0be076c1a21005086da1bda3b958f7c46af29f82 /src/backend/commands/trigger.c | |
parent | add2c3f4d6b137b35c097354438779aacde2f1d9 (diff) | |
download | postgresql-fa57fd1c0a4b9dee0bbd932c20d773d56a88a78f.tar.gz postgresql-fa57fd1c0a4b9dee0bbd932c20d773d56a88a78f.zip |
Fix interaction between materializing holdable cursors and firing
deferred triggers: either one can create more work for the other,
so we have to loop till it's all gone. Per example from andrew@supernews.
Add a regression test to help spot trouble in this area in future.
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r-- | src/backend/commands/trigger.c | 44 |
1 files changed, 20 insertions, 24 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 3f0bdbc2a8f..41e3b74c471 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.177 2004/12/31 21:59:41 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.177.4.1 2005/04/11 19:51:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2347,14 +2347,18 @@ AfterTriggerEndQuery(void) /* ---------- - * AfterTriggerEndXact() + * AfterTriggerFireDeferred() * * Called just before the current transaction is committed. At this - * time we invoke all DEFERRED triggers and tidy up. + * time we invoke all pending DEFERRED triggers. + * + * It is possible for other modules to queue additional deferred triggers + * during pre-commit processing; therefore xact.c may have to call this + * multiple times. * ---------- */ void -AfterTriggerEndXact(void) +AfterTriggerFireDeferred(void) { AfterTriggerEventList *events; @@ -2369,14 +2373,14 @@ AfterTriggerEndXact(void) * for them to use. (Since PortalRunUtility doesn't set a snap for * COMMIT, we can't assume ActiveSnapshot is valid on entry.) */ - if (afterTriggers->events.head != NULL) + events = &afterTriggers->events; + if (events->head != NULL) ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); /* * Run all the remaining triggers. Loop until they are all gone, * just in case some trigger queues more for us to do. */ - events = &afterTriggers->events; while (afterTriggerMarkEvents(events, NULL, false)) { CommandId firing_id = afterTriggers->firing_counter++; @@ -2384,35 +2388,27 @@ AfterTriggerEndXact(void) afterTriggerInvokeEvents(events, firing_id, true); } - /* - * Forget everything we know about AFTER triggers. - * - * Since all the info is in TopTransactionContext or children thereof, we - * need do nothing special to reclaim memory. - */ - afterTriggers = NULL; + Assert(events->head == NULL); } /* ---------- - * AfterTriggerAbortXact() + * AfterTriggerEndXact() + * + * The current transaction is finishing. * - * The current transaction has entered the abort state. - * All outstanding triggers are canceled so we simply throw + * Any unfired triggers are canceled so we simply throw * away anything we know. + * + * Note: it is possible for this to be called repeatedly in case of + * error during transaction abort; therefore, do not complain if + * already closed down. * ---------- */ void -AfterTriggerAbortXact(void) +AfterTriggerEndXact(bool isCommit) { /* - * Ignore call if we aren't in a transaction. (Need this to survive - * repeat call in case of error during transaction abort.) - */ - if (afterTriggers == NULL) - return; - - /* * Forget everything we know about AFTER triggers. * * Since all the info is in TopTransactionContext or children thereof, we |