From fc946e0fd29b00dfacb398589b7c874cc96fa8a6 Mon Sep 17 00:00:00 2001
From: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Date: Mon, 17 Aug 2026 20:50:22 +0900
Subject: [PATCH] Close relations opened for AFTER trigger

---
 src/backend/replication/logical/worker.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 92ea1d0df24..fcc704f8b4a 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -944,12 +944,17 @@ finish_edata(ApplyExecutionData *edata)
 	if (edata->proute)
 		ExecCleanupTupleRouting(edata->mtstate, edata->proute);
 
+	/* Close any relations that were opened for AFTER trigger execution */
+	foreach_ptr(ResultRelInfo, resultRelInfo, estate->es_trig_target_relations)
+		table_close(resultRelInfo->ri_RelationDesc, NoLock);
+
 	/*
 	 * Cleanup.  It might seem that we should call ExecCloseResultRelations()
 	 * here, but we intentionally don't.  It would close the rel we added to
 	 * es_opened_result_relations above, which is wrong because we took no
-	 * corresponding refcount.  We rely on ExecCleanupTupleRouting() to close
-	 * any other relations opened during execution.
+	 * corresponding refcount.  ExecCleanupTupleRouting() closes relations
+	 * opened for tuple routing, while relations opened for AFTER trigger
+	 * execution were closed above.
 	 */
 	ExecResetTupleTable(estate->es_tupleTable, false);
 	FreeExecutorState(estate);
-- 
2.52.0

