From 4bd1ded2c80d1c1294af5e6a190debafd4866ceb Mon Sep 17 00:00:00 2001
From: Amit Langote <amitlan@postgresql.org>
Date: Thu, 9 Apr 2026 13:46:45 +0900
Subject: [PATCH v4 2/3] Move afterTriggerFiringDepth into AfterTriggersData

The static variable afterTriggerFiringDepth introduced by commit
5c54c3ed1b9 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.  Also update its
comment to accurately reflect its sole remaining purpose: signaling
to AfterTriggerIsActive() that after-trigger firing is active.

Discussion: https://postgr.es/m/CA+HiwqFt4NGTNk7BinOsHHM48E9zGAa852vCfGoSe1bbL=JNFQ@mail.gmail.com
---
 src/backend/commands/trigger.c | 36 +++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 9c6125623e0..28187fe8c06 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -3898,6 +3898,13 @@ typedef struct AfterTriggersData
 									 * for deferred constraints */
 	bool		firing_batch_callbacks;	/* true when in
 										 * FireAfterTriggersBatchCallbacks() */
+
+	/*
+	 * Incremented around the trigger-firing loops in AfterTriggerEndQuery,
+	 * AfterTriggerFireDeferred, and AfterTriggerSetState.  Used by
+	 * AfterTriggerIsActive() to signal that after-trigger firing is active.
+	 */
+	int			firing_depth;
 } AfterTriggersData;
 
 struct AfterTriggersQueryData
@@ -3944,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,
@@ -5110,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;
 	afterTriggers.firing_batch_callbacks = false;
 
@@ -5125,7 +5126,6 @@ AfterTriggerBeginXact(void)
 	Assert(afterTriggers.events.head == NULL);
 	Assert(afterTriggers.trans_stack == NULL);
 	Assert(afterTriggers.maxtransdepth == 0);
-	Assert(afterTriggerFiringDepth == 0);
 }
 
 
@@ -5197,7 +5197,7 @@ AfterTriggerEndQuery(EState *estate)
 	 */
 	qs = &afterTriggers.query_stack[afterTriggers.query_depth];
 
-	afterTriggerFiringDepth++;
+	afterTriggers.firing_depth++;
 	for (;;)
 	{
 		if (afterTriggerMarkEvents(&qs->events, &afterTriggers.events, true))
@@ -5246,7 +5246,7 @@ AfterTriggerEndQuery(EState *estate)
 	AfterTriggerFreeQuery(&afterTriggers.query_stack[afterTriggers.query_depth]);
 
 	afterTriggers.query_depth--;
-	afterTriggerFiringDepth--;
+	afterTriggers.firing_depth--;
 }
 
 
@@ -5345,7 +5345,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++;
@@ -5357,7 +5357,7 @@ AfterTriggerFireDeferred(void)
 	/* Flush any fast-path batches accumulated by the triggers just fired. */
 	FireAfterTriggerBatchCallbacks(afterTriggers.batch_callbacks);
 
-	afterTriggerFiringDepth--;
+	afterTriggers.firing_depth--;
 
 	/*
 	 * We don't bother freeing the event list or batch_callbacks, since
@@ -5425,7 +5425,7 @@ AfterTriggerEndXact(bool isCommit)
 	/* No more afterTriggers manipulation until next transaction starts. */
 	afterTriggers.query_depth = -1;
 
-	afterTriggerFiringDepth = 0;
+	afterTriggers.firing_depth = 0;
 
 	list_free_deep(afterTriggers.batch_callbacks);
 	afterTriggers.batch_callbacks = NIL;
@@ -6083,7 +6083,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++;
@@ -6117,7 +6117,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
 		 * Flush any fast-path batches accumulated by the triggers just fired.
 		 */
 		FireAfterTriggerBatchCallbacks(afterTriggers.batch_callbacks);
-		afterTriggerFiringDepth--;
+		afterTriggers.firing_depth--;
 		list_free_deep(afterTriggers.batch_callbacks);
 		afterTriggers.batch_callbacks = NIL;
 
@@ -6843,7 +6843,7 @@ 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);
 	Assert(!afterTriggers.firing_batch_callbacks);
 	oldcxt = MemoryContextSwitchTo(TopTransactionContext);
 	item = palloc(sizeof(AfterTriggerCallbackItem));
@@ -6874,7 +6874,7 @@ FireAfterTriggerBatchCallbacks(List *callbacks)
 {
 	ListCell   *lc;
 
-	Assert(afterTriggerFiringDepth > 0);
+	Assert(afterTriggers.firing_depth > 0);
 	afterTriggers.firing_batch_callbacks = true;
 	foreach(lc, callbacks)
 	{
@@ -6896,5 +6896,5 @@ FireAfterTriggerBatchCallbacks(List *callbacks)
 bool
 AfterTriggerIsActive(void)
 {
-	return afterTriggerFiringDepth > 0;
+	return afterTriggers.firing_depth > 0;
 }
-- 
2.47.3

