v3-0003-Move-afterTriggerFiringDepth-into-AfterTriggersDa.patch
application/octet-stream
Filename: v3-0003-Move-afterTriggerFiringDepth-into-AfterTriggersDa.patch
Type: application/octet-stream
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v3-0003
Subject: Move afterTriggerFiringDepth into AfterTriggersData
| File | + | − |
|---|---|---|
| src/backend/commands/trigger.c | 22 | 20 |
From 4ed90a5b74c77c5e4a2f5b0a602a06a372aec795 Mon Sep 17 00:00:00 2001
From: Amit Langote <amitlan@postgresql.org>
Date: Wed, 8 Apr 2026 23:22:41 +0900
Subject: [PATCH v3 3/4] Move afterTriggerFiringDepth into AfterTriggersData
The static variable afterTriggerFiringDepth is logically part of the
after-trigger state. Move it into AfterTriggersData as firing_depth,
alongside query_depth and the other per-transaction after-trigger
state.
---
src/backend/commands/trigger.c | 42 ++++++++++++++++++----------------
1 file changed, 22 insertions(+), 20 deletions(-)
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index f59537fe86e..bbc2405cc4a 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -3894,7 +3894,16 @@ typedef struct AfterTriggersData
AfterTriggersTransData *trans_stack; /* array of structs shown below */
int maxtransdepth; /* allocated len of above array */
- List *batch_callbacks; /* List of AfterTriggerCallbackItem */
+ /*
+ * Incremented around the trigger-firing loops in AfterTriggerEndQuery,
+ * AfterTriggerFireDeferred, and AfterTriggerSetState. Used by
+ * AfterTriggerIsActive() and to tag batch callbacks with the depth at
+ * which they should fire.
+ */
+ int firing_depth;
+
+ List *batch_callbacks; /* List of AfterTriggerCallbackItem,
+ * possibly from multiple firing depths */
} AfterTriggersData;
struct AfterTriggersQueryData
@@ -3942,13 +3951,6 @@ typedef struct AfterTriggerCallbackItem
static AfterTriggersData afterTriggers;
-/*
- * Incremented before invoking afterTriggerInvokeEvents(). Used by
- * AfterTriggerIsActive() to determine whether batch callbacks will fire,
- * so that RI trigger functions can take the batched fast path.
- */
-static int afterTriggerFiringDepth = 0;
-
static void AfterTriggerExecute(EState *estate,
AfterTriggerEvent event,
ResultRelInfo *relInfo,
@@ -5108,6 +5110,7 @@ AfterTriggerBeginXact(void)
*/
afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
afterTriggers.query_depth = -1;
+ afterTriggers.firing_depth = 0;
afterTriggers.batch_callbacks = NIL;
/*
@@ -5122,7 +5125,6 @@ AfterTriggerBeginXact(void)
Assert(afterTriggers.events.head == NULL);
Assert(afterTriggers.trans_stack == NULL);
Assert(afterTriggers.maxtransdepth == 0);
- Assert(afterTriggerFiringDepth == 0);
}
@@ -5194,7 +5196,7 @@ AfterTriggerEndQuery(EState *estate)
*/
qs = &afterTriggers.query_stack[afterTriggers.query_depth];
- afterTriggerFiringDepth++;
+ afterTriggers.firing_depth++;
for (;;)
{
if (afterTriggerMarkEvents(&qs->events, &afterTriggers.events, true))
@@ -5245,7 +5247,7 @@ AfterTriggerEndQuery(EState *estate)
AfterTriggerFreeQuery(&afterTriggers.query_stack[afterTriggers.query_depth]);
afterTriggers.query_depth--;
- afterTriggerFiringDepth--;
+ afterTriggers.firing_depth--;
}
@@ -5341,7 +5343,7 @@ AfterTriggerFireDeferred(void)
* Run all the remaining triggers. Loop until they are all gone, in case
* some trigger queues more for us to do.
*/
- afterTriggerFiringDepth++;
+ afterTriggers.firing_depth++;
while (afterTriggerMarkEvents(events, NULL, false))
{
CommandId firing_id = afterTriggers.firing_counter++;
@@ -5353,7 +5355,7 @@ AfterTriggerFireDeferred(void)
/* Flush any fast-path batches accumulated by the triggers just fired. */
FireAfterTriggerBatchCallbacks();
- afterTriggerFiringDepth--;
+ afterTriggers.firing_depth--;
/*
* We don't bother freeing the event list, since it will go away anyway
@@ -5420,7 +5422,7 @@ AfterTriggerEndXact(bool isCommit)
/* No more afterTriggers manipulation until next transaction starts. */
afterTriggers.query_depth = -1;
- afterTriggerFiringDepth = 0;
+ afterTriggers.firing_depth = 0;
Assert(afterTriggers.batch_callbacks == NIL || !isCommit);
@@ -6079,7 +6081,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
AfterTriggerEventList *events = &afterTriggers.events;
bool snapshot_set = false;
- afterTriggerFiringDepth++;
+ afterTriggers.firing_depth++;
while (afterTriggerMarkEvents(events, NULL, true))
{
CommandId firing_id = afterTriggers.firing_counter++;
@@ -6113,7 +6115,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
* Flush any fast-path batches accumulated by the triggers just fired.
*/
FireAfterTriggerBatchCallbacks();
- afterTriggerFiringDepth--;
+ afterTriggers.firing_depth--;
if (snapshot_set)
PopActiveSnapshot();
@@ -6837,11 +6839,11 @@ RegisterAfterTriggerBatchCallback(AfterTriggerBatchCallback callback,
* Must be called while afterTriggers is active; callbacks registered
* outside a trigger-firing context would never fire.
*/
- Assert(afterTriggerFiringDepth > 0);
+ Assert(afterTriggers.firing_depth > 0);
oldcxt = MemoryContextSwitchTo(TopTransactionContext);
item = palloc(sizeof(AfterTriggerCallbackItem));
item->callback = callback;
- item->firing_depth = afterTriggerFiringDepth;
+ item->firing_depth = afterTriggers.firing_depth;
item->arg = arg;
afterTriggers.batch_callbacks =
lappend(afterTriggers.batch_callbacks, item);
@@ -6876,7 +6878,7 @@ FireAfterTriggerBatchCallbacks(void)
{
AfterTriggerCallbackItem *item = lfirst(lc);
- if (item->firing_depth == afterTriggerFiringDepth)
+ if (item->firing_depth == afterTriggers.firing_depth)
to_fire = lappend(to_fire, item);
else
remaining = lappend(remaining, item);
@@ -6908,5 +6910,5 @@ FireAfterTriggerBatchCallbacks(void)
bool
AfterTriggerIsActive(void)
{
- return afterTriggerFiringDepth > 0;
+ return afterTriggers.firing_depth > 0;
}
--
2.47.3