v5-0006-Reuse-FK-tuple-slot-across-fast-path-batches.patch

application/octet-stream

Filename: v5-0006-Reuse-FK-tuple-slot-across-fast-path-batches.patch
Type: application/octet-stream
Part: 1
Message: Re: Eliminating SPI / SQL from some RI triggers - take 3

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 v5-0006
Subject: Reuse FK tuple slot across fast-path batches
File+
src/backend/utils/adt/ri_triggers.c 10 11
From 7619357adf748e4396f418652adf40e9d77941fc Mon Sep 17 00:00:00 2001
From: Junwang Zhao <zhjwpku@gmail.com>
Date: Tue, 10 Mar 2026 18:06:21 +0800
Subject: [PATCH v5 6/6] Reuse FK tuple slot across fast-path batches

---
 src/backend/utils/adt/ri_triggers.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index eb112aabc98..ae1765a37f4 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -213,8 +213,9 @@ typedef struct RI_FastPathEntry
 	Relation	idx_rel;
 	IndexScanDesc scandesc;
 	TupleTableSlot *slot;
+	TupleTableSlot *fk_slot;
 	Snapshot	snapshot;		/* registered snapshot for the scan */
- 
+
 	/* For when IsolationUsesXactSnapshot() is true */
 	Snapshot	xact_snap;
 	IndexScanDesc xact_scan;
@@ -314,7 +315,7 @@ pg_noreturn static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
 										   Relation pk_rel, Relation fk_rel,
 										   TupleTableSlot *violatorslot, TupleDesc tupdesc,
 										   int queryno, bool is_restrict, bool partgone);
-static RI_FastPathEntry *ri_FastPathGetEntry(const RI_ConstraintInfo *riinfo);
+static RI_FastPathEntry *ri_FastPathGetEntry(const RI_ConstraintInfo *riinfo, Relation fk_rel);
 static void ri_FastPathEndBatch(void *arg);
 static void ri_FastPathTeardown(void);
 static void ri_FastPathBatchAdd(const RI_ConstraintInfo *riinfo,
@@ -3851,6 +3852,8 @@ ri_FastPathTeardown(void)
 			table_close(entry->pk_rel, NoLock);
 		if (entry->slot)
 			ExecDropSingleTupleTableSlot(entry->slot);
+		if (entry->fk_slot)
+			ExecDropSingleTupleTableSlot(entry->fk_slot);
 		if (entry->snapshot)
 			UnregisterSnapshot(entry->snapshot);
 		if (entry->xact_snap)
@@ -3909,7 +3912,7 @@ ri_FastPathSubXactCallback(SubXactEvent event, SubTransactionId mySubid,
  * index_rescan() with new keys.
  */
 static RI_FastPathEntry *
-ri_FastPathGetEntry(const RI_ConstraintInfo *riinfo)
+ri_FastPathGetEntry(const RI_ConstraintInfo *riinfo, Relation fk_rel)
 {
 	RI_FastPathEntry *entry;
 	bool		found;
@@ -3974,6 +3977,8 @@ ri_FastPathGetEntry(const RI_ConstraintInfo *riinfo)
 		entry->snapshot = RegisterSnapshot(GetLatestSnapshot());
 
 		entry->slot = table_slot_create(entry->pk_rel, NULL);
+		entry->fk_slot = MakeSingleTupleTableSlot(RelationGetDescr(fk_rel),
+												  &TTSOpsHeapTuple);
 
 		entry->scandesc = index_beginscan(entry->pk_rel, entry->idx_rel,
 										  entry->snapshot, NULL,
@@ -4238,7 +4243,7 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel)
 	Relation	pk_rel = fpentry->pk_rel;
 	Relation	idx_rel = fpentry->idx_rel;
 	Snapshot	snapshot = fpentry->snapshot;
-	TupleTableSlot *fk_slot;
+	TupleTableSlot *fk_slot = fpentry->fk_slot;
 	Oid			saved_userid;
 	int			saved_sec_context;
 
@@ -4259,9 +4264,6 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel)
 						   SECURITY_LOCAL_USERID_CHANGE |
 						   SECURITY_NOFORCE_RLS);
 
-	fk_slot = MakeSingleTupleTableSlot(RelationGetDescr(fk_rel),
-									   &TTSOpsHeapTuple);
-
 	if (riinfo->nkeys == 1)
 		ri_FastPathFlushArray(fpentry, fk_slot, riinfo, fk_rel);
 	else
@@ -4272,10 +4274,7 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel)
 	/* Free materialized tuples and reset */
 	for (int i = 0; i < fpentry->batch_count; i++)
 		heap_freetuple(fpentry->batch[i]);
-
 	fpentry->batch_count = 0;
-
-	ExecDropSingleTupleTableSlot(fk_slot);
 }
 
 /*
@@ -4297,7 +4296,7 @@ ri_FastPathBatchAdd(const RI_ConstraintInfo *riinfo,
 	RI_FastPathEntry *fpentry;
 	MemoryContext oldcxt;
 
-	fpentry = ri_FastPathGetEntry(riinfo);
+	fpentry = ri_FastPathGetEntry(riinfo, fk_rel);
 
 	oldcxt = MemoryContextSwitchTo(TopTransactionContext);
 	fpentry->batch[fpentry->batch_count] =
-- 
2.41.0