diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c
index 29bc5cea799c654beaca4e0dc621415c52b58749..913f1f8a51870667a26c7339dd5b5af255375b52 100644
--- a/contrib/bloom/blinsert.c
+++ b/contrib/bloom/blinsert.c
@@ -190,7 +190,9 @@ blbuildempty(Relation index)
  */
 bool
 blinsert(Relation index, Datum *values, bool *isnull,
-		 ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique)
+		 ItemPointer ht_ctid, Relation heapRel,
+		 IndexUniqueCheck checkUnique,
+		 IndexInfo *indexInfo)
 {
 	BloomState	blstate;
 	BloomTuple *itup;
diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h
index a75a235a4f84e987145c6ceafd8fcf85d1ed710a..39d8d05c5d472214bd44c54a941f8cfaf989188f 100644
--- a/contrib/bloom/bloom.h
+++ b/contrib/bloom/bloom.h
@@ -189,7 +189,8 @@ extern bool blvalidate(Oid opclassoid);
 /* index access method interface functions */
 extern bool blinsert(Relation index, Datum *values, bool *isnull,
 		 ItemPointer ht_ctid, Relation heapRel,
-		 IndexUniqueCheck checkUnique);
+		 IndexUniqueCheck checkUnique,
+		 struct IndexInfo *indexInfo);
 extern IndexScanDesc blbeginscan(Relation r, int nkeys, int norderbys);
 extern int64 blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
 extern void blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
index 5d8e5574608316ec248f01549497bdae5ecc70fb..9afd7f64179629ab1b901ea082398951e94fdbbe 100644
--- a/doc/src/sgml/indexam.sgml
+++ b/doc/src/sgml/indexam.sgml
@@ -259,7 +259,8 @@ aminsert (Relation indexRelation,
           bool *isnull,
           ItemPointer heap_tid,
           Relation heapRelation,
-          IndexUniqueCheck checkUnique);
+          IndexUniqueCheck checkUnique,
+          IndexInfo *indexInfo);
 </programlisting>
    Insert a new tuple into an existing index.  The <literal>values</> and
    <literal>isnull</> arrays give the key values to be indexed, and
@@ -287,6 +288,14 @@ aminsert (Relation indexRelation,
    indexed, <function>aminsert</> should just return without doing anything.
   </para>
 
+  <para>
+   If the index AM wishes to cache data across successive index insertions
+   within a SQL statement, it can allocate space
+   in <literal>indexInfo-&gt;ii_Context</literal> and store a pointer to the
+   data in <literal>indexInfo-&gt;ii_AmCache</literal> (which will be NULL
+   initially).
+  </para>
+
   <para>
 <programlisting>
 IndexBulkDeleteResult *
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index b2afdb7bedb04933e6bfc3e875f80ae71868ee04..4ff046b4b01e689f61f085c169f150dc402f3725 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -131,14 +131,15 @@ brinhandler(PG_FUNCTION_ARGS)
 bool
 brininsert(Relation idxRel, Datum *values, bool *nulls,
 		   ItemPointer heaptid, Relation heapRel,
-		   IndexUniqueCheck checkUnique)
+		   IndexUniqueCheck checkUnique,
+		   IndexInfo *indexInfo)
 {
 	BlockNumber pagesPerRange;
-	BrinDesc   *bdesc = NULL;
+	BrinDesc   *bdesc = (BrinDesc *) indexInfo->ii_AmCache;
 	BrinRevmap *revmap;
 	Buffer		buf = InvalidBuffer;
 	MemoryContext tupcxt = NULL;
-	MemoryContext oldcxt = NULL;
+	MemoryContext oldcxt = CurrentMemoryContext;
 
 	revmap = brinRevmapInitialize(idxRel, &pagesPerRange, NULL);
 
@@ -163,14 +164,21 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
 		if (!brtup)
 			break;
 
-		/* First time through? */
+		/* First time through in this statement? */
 		if (bdesc == NULL)
 		{
+			MemoryContextSwitchTo(indexInfo->ii_Context);
 			bdesc = brin_build_desc(idxRel);
+			indexInfo->ii_AmCache = (void *) bdesc;
+			MemoryContextSwitchTo(oldcxt);
+		}
+		/* First time through in this brininsert call? */
+		if (tupcxt == NULL)
+		{
 			tupcxt = AllocSetContextCreate(CurrentMemoryContext,
 										   "brininsert cxt",
 										   ALLOCSET_DEFAULT_SIZES);
-			oldcxt = MemoryContextSwitchTo(tupcxt);
+			MemoryContextSwitchTo(tupcxt);
 		}
 
 		dtup = brin_deform_tuple(bdesc, brtup);
@@ -261,12 +269,9 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
 	brinRevmapTerminate(revmap);
 	if (BufferIsValid(buf))
 		ReleaseBuffer(buf);
-	if (bdesc != NULL)
-	{
-		brin_free_desc(bdesc);
-		MemoryContextSwitchTo(oldcxt);
+	MemoryContextSwitchTo(oldcxt);
+	if (tupcxt != NULL)
 		MemoryContextDelete(tupcxt);
-	}
 
 	return false;
 }
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index 03a7235a0a3e79fd846c74e20d6e028c1797e56e..3d3b9e08400f8d8d84feb76276112962a836bba6 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -482,39 +482,48 @@ ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum,
 bool
 gininsert(Relation index, Datum *values, bool *isnull,
 		  ItemPointer ht_ctid, Relation heapRel,
-		  IndexUniqueCheck checkUnique)
+		  IndexUniqueCheck checkUnique,
+		  IndexInfo *indexInfo)
 {
-	GinState	ginstate;
+	GinState   *ginstate = (GinState *) indexInfo->ii_AmCache;
 	MemoryContext oldCtx;
 	MemoryContext insertCtx;
 	int			i;
 
+	/* Initialize GinState cache if first call in this statement */
+	if (ginstate == NULL)
+	{
+		oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
+		ginstate = (GinState *) palloc(sizeof(GinState));
+		initGinState(ginstate, index);
+		indexInfo->ii_AmCache = (void *) ginstate;
+		MemoryContextSwitchTo(oldCtx);
+	}
+
 	insertCtx = AllocSetContextCreate(CurrentMemoryContext,
 									  "Gin insert temporary context",
 									  ALLOCSET_DEFAULT_SIZES);
 
 	oldCtx = MemoryContextSwitchTo(insertCtx);
 
-	initGinState(&ginstate, index);
-
 	if (GinGetUseFastUpdate(index))
 	{
 		GinTupleCollector collector;
 
 		memset(&collector, 0, sizeof(GinTupleCollector));
 
-		for (i = 0; i < ginstate.origTupdesc->natts; i++)
-			ginHeapTupleFastCollect(&ginstate, &collector,
+		for (i = 0; i < ginstate->origTupdesc->natts; i++)
+			ginHeapTupleFastCollect(ginstate, &collector,
 									(OffsetNumber) (i + 1),
 									values[i], isnull[i],
 									ht_ctid);
 
-		ginHeapTupleFastInsert(&ginstate, &collector);
+		ginHeapTupleFastInsert(ginstate, &collector);
 	}
 	else
 	{
-		for (i = 0; i < ginstate.origTupdesc->natts; i++)
-			ginHeapTupleInsert(&ginstate, (OffsetNumber) (i + 1),
+		for (i = 0; i < ginstate->origTupdesc->natts; i++)
+			ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
 							   values[i], isnull[i],
 							   ht_ctid);
 	}
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index c2247ad2f782ff866788a049d49c09c79ec3ac21..96ead531ea3ba345eeaae797889780d169274182 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -18,6 +18,7 @@
 #include "access/gistscan.h"
 #include "catalog/pg_collation.h"
 #include "miscadmin.h"
+#include "nodes/execnodes.h"
 #include "utils/builtins.h"
 #include "utils/index_selfuncs.h"
 #include "utils/memutils.h"
@@ -144,21 +145,23 @@ gistbuildempty(Relation index)
 bool
 gistinsert(Relation r, Datum *values, bool *isnull,
 		   ItemPointer ht_ctid, Relation heapRel,
-		   IndexUniqueCheck checkUnique)
+		   IndexUniqueCheck checkUnique,
+		   IndexInfo *indexInfo)
 {
+	GISTSTATE  *giststate = (GISTSTATE *) indexInfo->ii_AmCache;
 	IndexTuple	itup;
-	GISTSTATE  *giststate;
 	MemoryContext oldCxt;
 
-	giststate = initGISTstate(r);
+	/* Initialize GISTSTATE cache if first call in this statement */
+	if (giststate == NULL)
+	{
+		oldCxt = MemoryContextSwitchTo(indexInfo->ii_Context);
+		giststate = initGISTstate(r);
+		giststate->tempCxt = createTempGistContext();
+		indexInfo->ii_AmCache = (void *) giststate;
+		MemoryContextSwitchTo(oldCxt);
+	}
 
-	/*
-	 * We use the giststate's scan context as temp context too.  This means
-	 * that any memory leaked by the support functions is not reclaimed until
-	 * end of insert.  In most cases, we aren't going to call the support
-	 * functions very many times before finishing the insert, so this seems
-	 * cheaper than resetting a temp context for each function call.
-	 */
 	oldCxt = MemoryContextSwitchTo(giststate->tempCxt);
 
 	itup = gistFormTuple(giststate, r,
@@ -169,7 +172,7 @@ gistinsert(Relation r, Datum *values, bool *isnull,
 
 	/* cleanup */
 	MemoryContextSwitchTo(oldCxt);
-	freeGISTstate(giststate);
+	MemoryContextReset(giststate->tempCxt);
 
 	return false;
 }
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 97ad22aa6f3aa88e341962a14c9e2353a7545a7f..bca77a80c3b4592b988c3adb8019576b1525429f 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -232,7 +232,8 @@ hashbuildCallback(Relation index,
 bool
 hashinsert(Relation rel, Datum *values, bool *isnull,
 		   ItemPointer ht_ctid, Relation heapRel,
-		   IndexUniqueCheck checkUnique)
+		   IndexUniqueCheck checkUnique,
+		   IndexInfo *indexInfo)
 {
 	Datum		index_values[1];
 	bool		index_isnull[1];
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index 496648c42f00066c1bfb865bfcb5f120b22b802b..19e704800284a45760d708fd989c6b3c5cef740b 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -1604,7 +1604,9 @@ toast_save_datum(Relation rel, Datum value,
 		 * Create the index entry.  We cheat a little here by not using
 		 * FormIndexDatum: this relies on the knowledge that the index columns
 		 * are the same as the initial columns of the table for all the
-		 * indexes.
+		 * indexes.  We also cheat by not providing an IndexInfo: this is okay
+		 * for now because btree doesn't need one, but we might have to be
+		 * more honest someday.
 		 *
 		 * Note also that there had better not be any user-created index on
 		 * the TOAST table, since we don't bother to update anything else.
@@ -1617,7 +1619,8 @@ toast_save_datum(Relation rel, Datum value,
 							 &(toasttup->t_self),
 							 toastrel,
 							 toastidxs[i]->rd_index->indisunique ?
-							 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+							 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+							 NULL);
 		}
 
 		/*
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index ba27c1e86d9f64de25aa2db6cd8da9b31eb6453b..4e7eca73ccef51e1bed2c8b1f3abd449a7510b84 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -196,7 +196,8 @@ index_insert(Relation indexRelation,
 			 bool *isnull,
 			 ItemPointer heap_t_ctid,
 			 Relation heapRelation,
-			 IndexUniqueCheck checkUnique)
+			 IndexUniqueCheck checkUnique,
+			 IndexInfo *indexInfo)
 {
 	RELATION_CHECKS;
 	CHECK_REL_PROCEDURE(aminsert);
@@ -208,7 +209,7 @@ index_insert(Relation indexRelation,
 
 	return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull,
 												 heap_t_ctid, heapRelation,
-												 checkUnique);
+												 checkUnique, indexInfo);
 }
 
 /*
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 469e7abe4dff2612eef8f63d223cd96033287125..945e563fcc50bd5c5a629e792909f6fdca4f1bad 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -276,7 +276,8 @@ btbuildempty(Relation index)
 bool
 btinsert(Relation rel, Datum *values, bool *isnull,
 		 ItemPointer ht_ctid, Relation heapRel,
-		 IndexUniqueCheck checkUnique)
+		 IndexUniqueCheck checkUnique,
+		 IndexInfo *indexInfo)
 {
 	bool		result;
 	IndexTuple	itup;
diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c
index b42f4b713993ea75a11e187a8e8d9189d235cba4..14f8a9ee8e012e6b98cb2f4b61e00c35bba2a235 100644
--- a/src/backend/access/spgist/spginsert.c
+++ b/src/backend/access/spgist/spginsert.c
@@ -206,7 +206,8 @@ spgbuildempty(Relation index)
 bool
 spginsert(Relation index, Datum *values, bool *isnull,
 		  ItemPointer ht_ctid, Relation heapRel,
-		  IndexUniqueCheck checkUnique)
+		  IndexUniqueCheck checkUnique,
+		  IndexInfo *indexInfo)
 {
 	SpGistState spgstate;
 	MemoryContext oldCtx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 815a694cfcd9b22a8ce154a46ce23ad59fffb418..f8d92145e86f41c7e1bf4f8fb94158e47ec70921 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1687,6 +1687,10 @@ BuildIndexInfo(Relation index)
 	ii->ii_Concurrent = false;
 	ii->ii_BrokenHotChain = false;
 
+	/* set up for possible use by index AM */
+	ii->ii_AmCache = NULL;
+	ii->ii_Context = CurrentMemoryContext;
+
 	return ii;
 }
 
@@ -3158,7 +3162,8 @@ validate_index_heapscan(Relation heapRelation,
 						 &rootTuple,
 						 heapRelation,
 						 indexInfo->ii_Unique ?
-						 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+						 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+						 indexInfo);
 
 			state->tups_inserted += 1;
 		}
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 76268e1d2a27a5898bfc5038494d555defbf91ea..abc344ad6992613d0fa0c1cf9332100da94f0bc3 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -139,7 +139,8 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
 					 &(heapTuple->t_self),		/* tid of heap tuple */
 					 heapRelation,
 					 relationDescs[i]->rd_index->indisunique ?
-					 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+					 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+					 indexInfo);
 	}
 
 	ExecDropSingleTupleTableSlot(slot);
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index e5f773d51d0b2c6802352ecd7007f7df9ef835d3..0e4231668d4e69a9d5b119b3e95b7c162b4aa449 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -315,6 +315,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 	indexInfo->ii_ReadyForInserts = true;
 	indexInfo->ii_Concurrent = false;
 	indexInfo->ii_BrokenHotChain = false;
+	indexInfo->ii_AmCache = NULL;
+	indexInfo->ii_Context = CurrentMemoryContext;
 
 	collationObjectId[0] = InvalidOid;
 	collationObjectId[1] = InvalidOid;
diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c
index e9eeacd03a9ef39287d1ff0bfe47f5a2683ab251..e2544e51ed5f45cdd037e9281078b95d3ccfb6f8 100644
--- a/src/backend/commands/constraint.c
+++ b/src/backend/commands/constraint.c
@@ -165,7 +165,8 @@ unique_key_recheck(PG_FUNCTION_ARGS)
 		 * index will know about.
 		 */
 		index_insert(indexRel, values, isnull, &(new_row->t_self),
-					 trigdata->tg_relation, UNIQUE_CHECK_EXISTING);
+					 trigdata->tg_relation, UNIQUE_CHECK_EXISTING,
+					 indexInfo);
 	}
 	else
 	{
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index f4814c095b59884191d3f7e4ad0516bbd35b5241..265e9b33f78bd762909ed90f8cc8e0c4043c4650 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -183,6 +183,8 @@ CheckIndexCompatible(Oid oldId,
 	indexInfo->ii_ExclusionOps = NULL;
 	indexInfo->ii_ExclusionProcs = NULL;
 	indexInfo->ii_ExclusionStrats = NULL;
+	indexInfo->ii_AmCache = NULL;
+	indexInfo->ii_Context = CurrentMemoryContext;
 	typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
@@ -562,6 +564,8 @@ DefineIndex(Oid relationId,
 	indexInfo->ii_ReadyForInserts = !stmt->concurrent;
 	indexInfo->ii_Concurrent = stmt->concurrent;
 	indexInfo->ii_BrokenHotChain = false;
+	indexInfo->ii_AmCache = NULL;
+	indexInfo->ii_Context = CurrentMemoryContext;
 
 	typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 8d119f6a19b306979c3aa66ee3f5a01f159654e7..5242dee00644725ba4eb45727f1d6ad11ec84269 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -391,7 +391,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 						 isnull,	/* null flags */
 						 tupleid,		/* tid of heap tuple */
 						 heapRelation,	/* heap relation */
-						 checkUnique);	/* type of uniqueness check to do */
+						 checkUnique,	/* type of uniqueness check to do */
+						 indexInfo);	/* index AM may need this */
 
 		/*
 		 * If the index has an associated exclusion constraint, check that.
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
index e91e41dc0f405e741bc239adab30eb321a5449df..b0730bfefae0728dcc92a513c1f9494b06781e13 100644
--- a/src/include/access/amapi.h
+++ b/src/include/access/amapi.h
@@ -72,7 +72,8 @@ typedef bool (*aminsert_function) (Relation indexRelation,
 											   bool *isnull,
 											   ItemPointer heap_tid,
 											   Relation heapRelation,
-											   IndexUniqueCheck checkUnique);
+											   IndexUniqueCheck checkUnique,
+											   struct IndexInfo *indexInfo);
 
 /* bulk delete */
 typedef IndexBulkDeleteResult *(*ambulkdelete_function) (IndexVacuumInfo *info,
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
index 40312604f8dc1f7de5594749b09f0db59a87969e..abe887788be39508f4b5081216ddcbb6f7b1fdff 100644
--- a/src/include/access/brin_internal.h
+++ b/src/include/access/brin_internal.h
@@ -89,7 +89,8 @@ extern IndexBuildResult *brinbuild(Relation heap, Relation index,
 extern void brinbuildempty(Relation index);
 extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
 		   ItemPointer heaptid, Relation heapRel,
-		   IndexUniqueCheck checkUnique);
+		   IndexUniqueCheck checkUnique,
+		   struct IndexInfo *indexInfo);
 extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
 extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
 extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 51466b96e8b079e24f10169c367ff971007db015..f467b18a9c79cabbe1c4024e8d89b92bed1e2e3e 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -21,6 +21,9 @@
 #include "utils/relcache.h"
 #include "utils/snapshot.h"
 
+/* We don't want this file to depend on execnodes.h. */
+struct IndexInfo;
+
 /*
  * Struct for statistics returned by ambuild
  */
@@ -131,7 +134,8 @@ extern bool index_insert(Relation indexRelation,
 			 Datum *values, bool *isnull,
 			 ItemPointer heap_t_ctid,
 			 Relation heapRelation,
-			 IndexUniqueCheck checkUnique);
+			 IndexUniqueCheck checkUnique,
+			 struct IndexInfo *indexInfo);
 
 extern IndexScanDesc index_beginscan(Relation heapRelation,
 				Relation indexRelation,
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index d46274ee85d573246c2ff623060173375f1d08e5..7e1557ea85fbd02b349f416f5c240c5ffbdefa1e 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -617,7 +617,8 @@ extern IndexBuildResult *ginbuild(Relation heap, Relation index,
 extern void ginbuildempty(Relation index);
 extern bool gininsert(Relation index, Datum *values, bool *isnull,
 		  ItemPointer ht_ctid, Relation heapRel,
-		  IndexUniqueCheck checkUnique);
+		  IndexUniqueCheck checkUnique,
+		  struct IndexInfo *indexInfo);
 extern void ginEntryInsert(GinState *ginstate,
 			   OffsetNumber attnum, Datum key, GinNullCategory category,
 			   ItemPointerData *items, uint32 nitem,
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index f4beeb920949cbbd2d970e7aaa905e8dd0c7009b..873c52a1a220de8c139365131bc341bc1706996c 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -426,7 +426,8 @@ typedef struct GiSTOptions
 extern void gistbuildempty(Relation index);
 extern bool gistinsert(Relation r, Datum *values, bool *isnull,
 		   ItemPointer ht_ctid, Relation heapRel,
-		   IndexUniqueCheck checkUnique);
+		   IndexUniqueCheck checkUnique,
+		   struct IndexInfo *indexInfo);
 extern MemoryContext createTempGistContext(void);
 extern GISTSTATE *initGISTstate(Relation index);
 extern void freeGISTstate(GISTSTATE *giststate);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index c0455851f466d3361804f85aa6fe4c40f62589df..3bf587b1b703af89c9fc97e6ca06b5cb386252d5 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -277,7 +277,8 @@ extern IndexBuildResult *hashbuild(Relation heap, Relation index,
 extern void hashbuildempty(Relation index);
 extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
 		   ItemPointer ht_ctid, Relation heapRel,
-		   IndexUniqueCheck checkUnique);
+		   IndexUniqueCheck checkUnique,
+		   struct IndexInfo *indexInfo);
 extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
 extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
 extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index b2517623aa863a98972238a1ac944bba61f0d215..344ef9933c89e56a00623ec2684735b32c3b6d8b 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -659,7 +659,8 @@ extern IndexBuildResult *btbuild(Relation heap, Relation index,
 extern void btbuildempty(Relation index);
 extern bool btinsert(Relation rel, Datum *values, bool *isnull,
 		 ItemPointer ht_ctid, Relation heapRel,
-		 IndexUniqueCheck checkUnique);
+		 IndexUniqueCheck checkUnique,
+		 struct IndexInfo *indexInfo);
 extern IndexScanDesc btbeginscan(Relation rel, int nkeys, int norderbys);
 extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
 extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 6f59c0bbc52246897a00c02575f3f66c16bfab81..ee7480ad39e92250ee9c9b9eedfd127e4d985bb4 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -191,7 +191,8 @@ extern IndexBuildResult *spgbuild(Relation heap, Relation index,
 extern void spgbuildempty(Relation index);
 extern bool spginsert(Relation index, Datum *values, bool *isnull,
 		  ItemPointer ht_ctid, Relation heapRel,
-		  IndexUniqueCheck checkUnique);
+		  IndexUniqueCheck checkUnique,
+		  struct IndexInfo *indexInfo);
 
 /* spgscan.c */
 extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f9bcdd63de0718a5419649fe7ea4f10e34d913cb..42c6c58ff9c9b934c38e863bf5ffd828b8df0960 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -52,6 +52,8 @@
  *		ReadyForInserts		is it valid for inserts?
  *		Concurrent			are we doing a concurrent index build?
  *		BrokenHotChain		did we detect any broken HOT chains?
+ *		AmCache				private cache area for index AM
+ *		Context				memory context holding this IndexInfo
  *
  * ii_Concurrent and ii_BrokenHotChain are used only during index build;
  * they're conventionally set to false otherwise.
@@ -76,6 +78,8 @@ typedef struct IndexInfo
 	bool		ii_ReadyForInserts;
 	bool		ii_Concurrent;
 	bool		ii_BrokenHotChain;
+	void	   *ii_AmCache;
+	MemoryContext ii_Context;
 } IndexInfo;
 
 /* ----------------