summaryrefslogtreecommitdiff
path: root/src/backend/commands/trigger.c
diff options
context:
space:
mode:
authorTom Lane2005-04-11 19:51:16 +0000
committerTom Lane2005-04-11 19:51:16 +0000
commitc3294f1cbfe02293b4a7c6b2e58ca4c09a7e541f (patch)
treed4d422b08f15bce2b32867ae3cc8e722e08e9df2 /src/backend/commands/trigger.c
parent0c400f1bbc3231ed75e11d3ab0ec7a4a9d3c8486 (diff)
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.c44
1 files changed, 20 insertions, 24 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index ef00943055f..8c8ed9e21ca 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.183 2005/03/29 03:01:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.184 2005/04/11 19:51:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2441,14 +2441,18 @@ AfterTriggerEndQuery(EState *estate)
/* ----------
- * 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;
@@ -2463,14 +2467,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++;
@@ -2478,35 +2482,27 @@ AfterTriggerEndXact(void)
afterTriggerInvokeEvents(events, firing_id, NULL, 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