From 9252ae65eee9b9718bd62e5804a7783b4b6b9000 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 30 Oct 2018 17:53:07 +0900
Subject: [PATCH v1 2/2] Add a MemoryContext arg to
 check_exclusion_or_unique_constraint

check_exclusion_or_unique_constraint performs an index scan and some
index AMs may use huge amounts of memory that might end up getting
allocated in a possibly long-lived context.  A given caller may call
check_exclusion_or_unique_constraint repeatedly as it's scanning a
heap, for example, where it's desirable to free the memory for each
new tuple.

With that in place, teach IndexCheckExclusion and
ExecIndexInsertTuples to pass a per-tuple context down to
check_exclusion_or_unique_constraint.
---
 src/backend/catalog/index.c         | 12 +++++++++++-
 src/backend/commands/constraint.c   |  2 +-
 src/backend/executor/execIndexing.c | 21 ++++++++++++++-------
 src/include/executor/executor.h     |  3 ++-
 4 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 5885899c9b..ccafceb73a 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2983,6 +2983,7 @@ IndexCheckExclusion(Relation heapRelation,
 	EState	   *estate;
 	ExprContext *econtext;
 	Snapshot	snapshot;
+	MemoryContext index_scan_cxt;
 
 	/*
 	 * If we are reindexing the target index, mark it as no longer being
@@ -3017,11 +3018,20 @@ IndexCheckExclusion(Relation heapRelation,
 								true,	/* buffer access strategy OK */
 								true);	/* syncscan OK */
 
+	/*
+	 * This context contains the allocations needed to scan the index
+	 * for a given heap tuple, reset for every tuple.
+	 */
+	index_scan_cxt = AllocSetContextCreate(CurrentMemoryContext,
+										   "IndexCheckExclusion_cxt",
+										   ALLOCSET_DEFAULT_SIZES);
+
 	while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		CHECK_FOR_INTERRUPTS();
 
 		MemoryContextReset(econtext->ecxt_per_tuple_memory);
+		MemoryContextReset(index_scan_cxt);
 
 		/* Set up for predicate or expression evaluation */
 		ExecStoreHeapTuple(heapTuple, slot, false);
@@ -3050,7 +3060,7 @@ IndexCheckExclusion(Relation heapRelation,
 		check_exclusion_constraint(heapRelation,
 								   indexRelation, indexInfo,
 								   &(heapTuple->t_self), values, isnull,
-								   estate, true);
+								   estate, true, index_scan_cxt);
 	}
 
 	heap_endscan(scan);
diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c
index f472355b48..a4b1e4c112 100644
--- a/src/backend/commands/constraint.c
+++ b/src/backend/commands/constraint.c
@@ -178,7 +178,7 @@ unique_key_recheck(PG_FUNCTION_ARGS)
 		 */
 		check_exclusion_constraint(trigdata->tg_relation, indexRel, indexInfo,
 								   &tmptid, values, isnull,
-								   estate, false);
+								   estate, false, CurrentMemoryContext);
 	}
 
 	/*
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 74d15e6b43..cc1f5ffc39 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -129,7 +129,8 @@ static bool check_exclusion_or_unique_constraint(Relation heap, Relation index,
 									 EState *estate, bool newIndex,
 									 CEOUC_WAIT_MODE waitMode,
 									 bool errorOK,
-									 ItemPointer conflictTid);
+									 ItemPointer conflictTid,
+									 MemoryContext index_scan_cxt);
 
 static bool index_recheck_constraint(Relation index, Oid *constr_procs,
 						 Datum *existing_values, bool *existing_isnull,
@@ -410,6 +411,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 		{
 			bool		violationOK;
 			CEOUC_WAIT_MODE waitMode;
+			ExprContext *econtext = GetPerTupleExprContext(estate);
 
 			if (applyNoDupErr)
 			{
@@ -432,7 +434,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 													 indexRelation, indexInfo,
 													 tupleid, values, isnull,
 													 estate, false,
-													 waitMode, violationOK, NULL);
+													 waitMode, violationOK, NULL,
+													 econtext->ecxt_per_tuple_memory);
 		}
 
 		if ((checkUnique == UNIQUE_CHECK_PARTIAL ||
@@ -582,7 +585,8 @@ ExecCheckIndexConstraints(TupleTableSlot *slot,
 												 indexInfo, &invalidItemPtr,
 												 values, isnull, estate, false,
 												 CEOUC_WAIT, true,
-												 conflictTid);
+												 conflictTid,
+												 CurrentMemoryContext);
 		if (!satisfiesConstraint)
 			return false;
 	}
@@ -643,7 +647,8 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index,
 									 EState *estate, bool newIndex,
 									 CEOUC_WAIT_MODE waitMode,
 									 bool violationOK,
-									 ItemPointer conflictTid)
+									 ItemPointer conflictTid,
+									 MemoryContext index_scan_cxt)
 {
 	Oid		   *constr_procs;
 	uint16	   *constr_strats;
@@ -720,7 +725,7 @@ retry:
 	conflict = false;
 	found_self = false;
 	index_scan = index_beginscan(heap, index, &DirtySnapshot, indnkeyatts, 0,
-								 CurrentMemoryContext);
+								 index_scan_cxt);
 	index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0);
 
 	while ((tup = index_getnext(index_scan,
@@ -865,12 +870,14 @@ check_exclusion_constraint(Relation heap, Relation index,
 						   IndexInfo *indexInfo,
 						   ItemPointer tupleid,
 						   Datum *values, bool *isnull,
-						   EState *estate, bool newIndex)
+						   EState *estate, bool newIndex,
+						   MemoryContext index_scan_cxt)
 {
 	(void) check_exclusion_or_unique_constraint(heap, index, indexInfo, tupleid,
 												values, isnull,
 												estate, newIndex,
-												CEOUC_WAIT, false, NULL);
+												CEOUC_WAIT, false, NULL,
+												index_scan_cxt);
 }
 
 /*
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index edf538365b..c5998d9885 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -556,7 +556,8 @@ extern void check_exclusion_constraint(Relation heap, Relation index,
 						   IndexInfo *indexInfo,
 						   ItemPointer tupleid,
 						   Datum *values, bool *isnull,
-						   EState *estate, bool newIndex);
+						   EState *estate, bool newIndex,
+						   MemoryContext index_scan_cxt);
 
 /*
  * prototypes from functions in execReplication.c
-- 
2.11.0

