diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c
index 29bc5ce..913f1f8 100644
*** a/contrib/bloom/blinsert.c
--- b/contrib/bloom/blinsert.c
*************** blbuildempty(Relation index)
*** 190,196 ****
   */
  bool
  blinsert(Relation index, Datum *values, bool *isnull,
! 		 ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique)
  {
  	BloomState	blstate;
  	BloomTuple *itup;
--- 190,198 ----
   */
  bool
  blinsert(Relation index, Datum *values, bool *isnull,
! 		 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 a75a235..39d8d05 100644
*** a/contrib/bloom/bloom.h
--- b/contrib/bloom/bloom.h
*************** extern bool blvalidate(Oid opclassoid);
*** 189,195 ****
  /* index access method interface functions */
  extern bool blinsert(Relation index, Datum *values, bool *isnull,
  		 ItemPointer ht_ctid, Relation heapRel,
! 		 IndexUniqueCheck checkUnique);
  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,
--- 189,196 ----
  /* index access method interface functions */
  extern bool blinsert(Relation index, Datum *values, bool *isnull,
  		 ItemPointer ht_ctid, Relation heapRel,
! 		 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 5d8e557..9afd7f6 100644
*** a/doc/src/sgml/indexam.sgml
--- b/doc/src/sgml/indexam.sgml
*************** aminsert (Relation indexRelation,
*** 259,265 ****
            bool *isnull,
            ItemPointer heap_tid,
            Relation heapRelation,
!           IndexUniqueCheck checkUnique);
  </programlisting>
     Insert a new tuple into an existing index.  The <literal>values</> and
     <literal>isnull</> arrays give the key values to be indexed, and
--- 259,266 ----
            bool *isnull,
            ItemPointer heap_tid,
            Relation heapRelation,
!           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
*************** aminsert (Relation indexRelation,
*** 288,293 ****
--- 289,302 ----
    </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 *
  ambulkdelete (IndexVacuumInfo *info,
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index b2afdb7..4ff046b 100644
*** a/src/backend/access/brin/brin.c
--- b/src/backend/access/brin/brin.c
*************** brinhandler(PG_FUNCTION_ARGS)
*** 131,144 ****
  bool
  brininsert(Relation idxRel, Datum *values, bool *nulls,
  		   ItemPointer heaptid, Relation heapRel,
! 		   IndexUniqueCheck checkUnique)
  {
  	BlockNumber pagesPerRange;
! 	BrinDesc   *bdesc = NULL;
  	BrinRevmap *revmap;
  	Buffer		buf = InvalidBuffer;
  	MemoryContext tupcxt = NULL;
! 	MemoryContext oldcxt = NULL;
  
  	revmap = brinRevmapInitialize(idxRel, &pagesPerRange, NULL);
  
--- 131,145 ----
  bool
  brininsert(Relation idxRel, Datum *values, bool *nulls,
  		   ItemPointer heaptid, Relation heapRel,
! 		   IndexUniqueCheck checkUnique,
! 		   IndexInfo *indexInfo)
  {
  	BlockNumber pagesPerRange;
! 	BrinDesc   *bdesc = (BrinDesc *) indexInfo->ii_AmCache;
  	BrinRevmap *revmap;
  	Buffer		buf = InvalidBuffer;
  	MemoryContext tupcxt = NULL;
! 	MemoryContext oldcxt = CurrentMemoryContext;
  
  	revmap = brinRevmapInitialize(idxRel, &pagesPerRange, NULL);
  
*************** brininsert(Relation idxRel, Datum *value
*** 163,176 ****
  		if (!brtup)
  			break;
  
! 		/* First time through? */
  		if (bdesc == NULL)
  		{
  			bdesc = brin_build_desc(idxRel);
  			tupcxt = AllocSetContextCreate(CurrentMemoryContext,
  										   "brininsert cxt",
  										   ALLOCSET_DEFAULT_SIZES);
! 			oldcxt = MemoryContextSwitchTo(tupcxt);
  		}
  
  		dtup = brin_deform_tuple(bdesc, brtup);
--- 164,184 ----
  		if (!brtup)
  			break;
  
! 		/* 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);
! 			MemoryContextSwitchTo(tupcxt);
  		}
  
  		dtup = brin_deform_tuple(bdesc, brtup);
*************** brininsert(Relation idxRel, Datum *value
*** 261,272 ****
  	brinRevmapTerminate(revmap);
  	if (BufferIsValid(buf))
  		ReleaseBuffer(buf);
! 	if (bdesc != NULL)
! 	{
! 		brin_free_desc(bdesc);
! 		MemoryContextSwitchTo(oldcxt);
  		MemoryContextDelete(tupcxt);
- 	}
  
  	return false;
  }
--- 269,277 ----
  	brinRevmapTerminate(revmap);
  	if (BufferIsValid(buf))
  		ReleaseBuffer(buf);
! 	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 03a7235..3d3b9e0 100644
*** a/src/backend/access/gin/gininsert.c
--- b/src/backend/access/gin/gininsert.c
*************** ginHeapTupleInsert(GinState *ginstate, O
*** 482,520 ****
  bool
  gininsert(Relation index, Datum *values, bool *isnull,
  		  ItemPointer ht_ctid, Relation heapRel,
! 		  IndexUniqueCheck checkUnique)
  {
! 	GinState	ginstate;
  	MemoryContext oldCtx;
  	MemoryContext insertCtx;
  	int			i;
  
  	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,
  									(OffsetNumber) (i + 1),
  									values[i], isnull[i],
  									ht_ctid);
  
! 		ginHeapTupleFastInsert(&ginstate, &collector);
  	}
  	else
  	{
! 		for (i = 0; i < ginstate.origTupdesc->natts; i++)
! 			ginHeapTupleInsert(&ginstate, (OffsetNumber) (i + 1),
  							   values[i], isnull[i],
  							   ht_ctid);
  	}
--- 482,529 ----
  bool
  gininsert(Relation index, Datum *values, bool *isnull,
  		  ItemPointer ht_ctid, Relation heapRel,
! 		  IndexUniqueCheck checkUnique,
! 		  IndexInfo *indexInfo)
  {
! 	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);
  
  	if (GinGetUseFastUpdate(index))
  	{
  		GinTupleCollector collector;
  
  		memset(&collector, 0, sizeof(GinTupleCollector));
  
! 		for (i = 0; i < ginstate->origTupdesc->natts; i++)
! 			ginHeapTupleFastCollect(ginstate, &collector,
  									(OffsetNumber) (i + 1),
  									values[i], isnull[i],
  									ht_ctid);
  
! 		ginHeapTupleFastInsert(ginstate, &collector);
  	}
  	else
  	{
! 		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 c2247ad..96ead53 100644
*** a/src/backend/access/gist/gist.c
--- b/src/backend/access/gist/gist.c
***************
*** 18,23 ****
--- 18,24 ----
  #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"
*************** gistbuildempty(Relation index)
*** 144,164 ****
  bool
  gistinsert(Relation r, Datum *values, bool *isnull,
  		   ItemPointer ht_ctid, Relation heapRel,
! 		   IndexUniqueCheck checkUnique)
  {
  	IndexTuple	itup;
- 	GISTSTATE  *giststate;
  	MemoryContext oldCxt;
  
! 	giststate = initGISTstate(r);
  
- 	/*
- 	 * 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,
--- 145,167 ----
  bool
  gistinsert(Relation r, Datum *values, bool *isnull,
  		   ItemPointer ht_ctid, Relation heapRel,
! 		   IndexUniqueCheck checkUnique,
! 		   IndexInfo *indexInfo)
  {
+ 	GISTSTATE  *giststate = (GISTSTATE *) indexInfo->ii_AmCache;
  	IndexTuple	itup;
  	MemoryContext oldCxt;
  
! 	/* 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);
! 	}
  
  	oldCxt = MemoryContextSwitchTo(giststate->tempCxt);
  
  	itup = gistFormTuple(giststate, r,
*************** gistinsert(Relation r, Datum *values, bo
*** 169,175 ****
  
  	/* cleanup */
  	MemoryContextSwitchTo(oldCxt);
! 	freeGISTstate(giststate);
  
  	return false;
  }
--- 172,178 ----
  
  	/* cleanup */
  	MemoryContextSwitchTo(oldCxt);
! 	MemoryContextReset(giststate->tempCxt);
  
  	return false;
  }
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 97ad22a..bca77a8 100644
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
*************** hashbuildCallback(Relation index,
*** 232,238 ****
  bool
  hashinsert(Relation rel, Datum *values, bool *isnull,
  		   ItemPointer ht_ctid, Relation heapRel,
! 		   IndexUniqueCheck checkUnique)
  {
  	Datum		index_values[1];
  	bool		index_isnull[1];
--- 232,239 ----
  bool
  hashinsert(Relation rel, Datum *values, bool *isnull,
  		   ItemPointer ht_ctid, Relation heapRel,
! 		   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 496648c..19e7048 100644
*** a/src/backend/access/heap/tuptoaster.c
--- b/src/backend/access/heap/tuptoaster.c
*************** toast_save_datum(Relation rel, Datum val
*** 1604,1610 ****
  		 * 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.
  		 *
  		 * 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.
--- 1604,1612 ----
  		 * 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.  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.
*************** toast_save_datum(Relation rel, Datum val
*** 1617,1623 ****
  							 &(toasttup->t_self),
  							 toastrel,
  							 toastidxs[i]->rd_index->indisunique ?
! 							 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
  		}
  
  		/*
--- 1619,1626 ----
  							 &(toasttup->t_self),
  							 toastrel,
  							 toastidxs[i]->rd_index->indisunique ?
! 							 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
! 							 NULL);
  		}
  
  		/*
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index ba27c1e..4e7eca7 100644
*** a/src/backend/access/index/indexam.c
--- b/src/backend/access/index/indexam.c
*************** index_insert(Relation indexRelation,
*** 196,202 ****
  			 bool *isnull,
  			 ItemPointer heap_t_ctid,
  			 Relation heapRelation,
! 			 IndexUniqueCheck checkUnique)
  {
  	RELATION_CHECKS;
  	CHECK_REL_PROCEDURE(aminsert);
--- 196,203 ----
  			 bool *isnull,
  			 ItemPointer heap_t_ctid,
  			 Relation heapRelation,
! 			 IndexUniqueCheck checkUnique,
! 			 IndexInfo *indexInfo)
  {
  	RELATION_CHECKS;
  	CHECK_REL_PROCEDURE(aminsert);
*************** index_insert(Relation indexRelation,
*** 208,214 ****
  
  	return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull,
  												 heap_t_ctid, heapRelation,
! 												 checkUnique);
  }
  
  /*
--- 209,215 ----
  
  	return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull,
  												 heap_t_ctid, heapRelation,
! 												 checkUnique, indexInfo);
  }
  
  /*
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 469e7ab..945e563 100644
*** a/src/backend/access/nbtree/nbtree.c
--- b/src/backend/access/nbtree/nbtree.c
*************** btbuildempty(Relation index)
*** 276,282 ****
  bool
  btinsert(Relation rel, Datum *values, bool *isnull,
  		 ItemPointer ht_ctid, Relation heapRel,
! 		 IndexUniqueCheck checkUnique)
  {
  	bool		result;
  	IndexTuple	itup;
--- 276,283 ----
  bool
  btinsert(Relation rel, Datum *values, bool *isnull,
  		 ItemPointer ht_ctid, Relation heapRel,
! 		 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 b42f4b7..14f8a9e 100644
*** a/src/backend/access/spgist/spginsert.c
--- b/src/backend/access/spgist/spginsert.c
*************** spgbuildempty(Relation index)
*** 206,212 ****
  bool
  spginsert(Relation index, Datum *values, bool *isnull,
  		  ItemPointer ht_ctid, Relation heapRel,
! 		  IndexUniqueCheck checkUnique)
  {
  	SpGistState spgstate;
  	MemoryContext oldCtx;
--- 206,213 ----
  bool
  spginsert(Relation index, Datum *values, bool *isnull,
  		  ItemPointer ht_ctid, Relation heapRel,
! 		  IndexUniqueCheck checkUnique,
! 		  IndexInfo *indexInfo)
  {
  	SpGistState spgstate;
  	MemoryContext oldCtx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 815a694..f8d9214 100644
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
*************** BuildIndexInfo(Relation index)
*** 1687,1692 ****
--- 1687,1696 ----
  	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;
  }
  
*************** validate_index_heapscan(Relation heapRel
*** 3158,3164 ****
  						 &rootTuple,
  						 heapRelation,
  						 indexInfo->ii_Unique ?
! 						 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
  
  			state->tups_inserted += 1;
  		}
--- 3162,3169 ----
  						 &rootTuple,
  						 heapRelation,
  						 indexInfo->ii_Unique ?
! 						 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 76268e1..abc344a 100644
*** a/src/backend/catalog/indexing.c
--- b/src/backend/catalog/indexing.c
*************** CatalogIndexInsert(CatalogIndexState ind
*** 139,145 ****
  					 &(heapTuple->t_self),		/* tid of heap tuple */
  					 heapRelation,
  					 relationDescs[i]->rd_index->indisunique ?
! 					 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
  	}
  
  	ExecDropSingleTupleTableSlot(slot);
--- 139,146 ----
  					 &(heapTuple->t_self),		/* tid of heap tuple */
  					 heapRelation,
  					 relationDescs[i]->rd_index->indisunique ?
! 					 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
! 					 indexInfo);
  	}
  
  	ExecDropSingleTupleTableSlot(slot);
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index e5f773d..0e42316 100644
*** a/src/backend/catalog/toasting.c
--- b/src/backend/catalog/toasting.c
*************** create_toast_table(Relation rel, Oid toa
*** 315,320 ****
--- 315,322 ----
  	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 e9eeacd..e2544e5 100644
*** a/src/backend/commands/constraint.c
--- b/src/backend/commands/constraint.c
*************** unique_key_recheck(PG_FUNCTION_ARGS)
*** 165,171 ****
  		 * index will know about.
  		 */
  		index_insert(indexRel, values, isnull, &(new_row->t_self),
! 					 trigdata->tg_relation, UNIQUE_CHECK_EXISTING);
  	}
  	else
  	{
--- 165,172 ----
  		 * index will know about.
  		 */
  		index_insert(indexRel, values, isnull, &(new_row->t_self),
! 					 trigdata->tg_relation, UNIQUE_CHECK_EXISTING,
! 					 indexInfo);
  	}
  	else
  	{
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index f4814c0..265e9b3 100644
*** a/src/backend/commands/indexcmds.c
--- b/src/backend/commands/indexcmds.c
*************** CheckIndexCompatible(Oid oldId,
*** 183,188 ****
--- 183,190 ----
  	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));
*************** DefineIndex(Oid relationId,
*** 562,567 ****
--- 564,571 ----
  	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 8d119f6..5242dee 100644
*** a/src/backend/executor/execIndexing.c
--- b/src/backend/executor/execIndexing.c
*************** ExecInsertIndexTuples(TupleTableSlot *sl
*** 391,397 ****
  						 isnull,	/* null flags */
  						 tupleid,		/* tid of heap tuple */
  						 heapRelation,	/* heap relation */
! 						 checkUnique);	/* type of uniqueness check to do */
  
  		/*
  		 * If the index has an associated exclusion constraint, check that.
--- 391,398 ----
  						 isnull,	/* null flags */
  						 tupleid,		/* tid of heap tuple */
  						 heapRelation,	/* heap relation */
! 						 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 e91e41d..b0730bf 100644
*** a/src/include/access/amapi.h
--- b/src/include/access/amapi.h
*************** typedef bool (*aminsert_function) (Relat
*** 72,78 ****
  											   bool *isnull,
  											   ItemPointer heap_tid,
  											   Relation heapRelation,
! 											   IndexUniqueCheck checkUnique);
  
  /* bulk delete */
  typedef IndexBulkDeleteResult *(*ambulkdelete_function) (IndexVacuumInfo *info,
--- 72,79 ----
  											   bool *isnull,
  											   ItemPointer heap_tid,
  											   Relation heapRelation,
! 											   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 4031260..abe8877 100644
*** a/src/include/access/brin_internal.h
--- b/src/include/access/brin_internal.h
*************** extern IndexBuildResult *brinbuild(Relat
*** 89,95 ****
  extern void brinbuildempty(Relation index);
  extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
  		   ItemPointer heaptid, Relation heapRel,
! 		   IndexUniqueCheck checkUnique);
  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,
--- 89,96 ----
  extern void brinbuildempty(Relation index);
  extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
  		   ItemPointer heaptid, Relation heapRel,
! 		   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 51466b9..f467b18 100644
*** a/src/include/access/genam.h
--- b/src/include/access/genam.h
***************
*** 21,26 ****
--- 21,29 ----
  #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
   */
*************** extern bool index_insert(Relation indexR
*** 131,137 ****
  			 Datum *values, bool *isnull,
  			 ItemPointer heap_t_ctid,
  			 Relation heapRelation,
! 			 IndexUniqueCheck checkUnique);
  
  extern IndexScanDesc index_beginscan(Relation heapRelation,
  				Relation indexRelation,
--- 134,141 ----
  			 Datum *values, bool *isnull,
  			 ItemPointer heap_t_ctid,
  			 Relation heapRelation,
! 			 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 d46274e..7e1557e 100644
*** a/src/include/access/gin_private.h
--- b/src/include/access/gin_private.h
*************** extern IndexBuildResult *ginbuild(Relati
*** 617,623 ****
  extern void ginbuildempty(Relation index);
  extern bool gininsert(Relation index, Datum *values, bool *isnull,
  		  ItemPointer ht_ctid, Relation heapRel,
! 		  IndexUniqueCheck checkUnique);
  extern void ginEntryInsert(GinState *ginstate,
  			   OffsetNumber attnum, Datum key, GinNullCategory category,
  			   ItemPointerData *items, uint32 nitem,
--- 617,624 ----
  extern void ginbuildempty(Relation index);
  extern bool gininsert(Relation index, Datum *values, bool *isnull,
  		  ItemPointer ht_ctid, Relation heapRel,
! 		  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 60a770a..a4d3e7c 100644
*** a/src/include/access/gist_private.h
--- b/src/include/access/gist_private.h
*************** typedef struct GiSTOptions
*** 426,432 ****
  extern void gistbuildempty(Relation index);
  extern bool gistinsert(Relation r, Datum *values, bool *isnull,
  		   ItemPointer ht_ctid, Relation heapRel,
! 		   IndexUniqueCheck checkUnique);
  extern MemoryContext createTempGistContext(void);
  extern GISTSTATE *initGISTstate(Relation index);
  extern void freeGISTstate(GISTSTATE *giststate);
--- 426,433 ----
  extern void gistbuildempty(Relation index);
  extern bool gistinsert(Relation r, Datum *values, bool *isnull,
  		   ItemPointer ht_ctid, Relation heapRel,
! 		   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 c045585..3bf587b 100644
*** a/src/include/access/hash.h
--- b/src/include/access/hash.h
*************** extern IndexBuildResult *hashbuild(Relat
*** 277,283 ****
  extern void hashbuildempty(Relation index);
  extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
  		   ItemPointer ht_ctid, Relation heapRel,
! 		   IndexUniqueCheck checkUnique);
  extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
  extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
  extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys);
--- 277,284 ----
  extern void hashbuildempty(Relation index);
  extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
  		   ItemPointer ht_ctid, Relation heapRel,
! 		   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 011a72e..70ff3aa 100644
*** a/src/include/access/nbtree.h
--- b/src/include/access/nbtree.h
*************** extern IndexBuildResult *btbuild(Relatio
*** 659,665 ****
  extern void btbuildempty(Relation index);
  extern bool btinsert(Relation rel, Datum *values, bool *isnull,
  		 ItemPointer ht_ctid, Relation heapRel,
! 		 IndexUniqueCheck checkUnique);
  extern IndexScanDesc btbeginscan(Relation rel, int nkeys, int norderbys);
  extern bool btgettuple(IndexScanDesc scan, ScanDirection dir);
  extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
--- 659,666 ----
  extern void btbuildempty(Relation index);
  extern bool btinsert(Relation rel, Datum *values, bool *isnull,
  		 ItemPointer ht_ctid, Relation heapRel,
! 		 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 aaf78bc..c69af63 100644
*** a/src/include/access/spgist.h
--- b/src/include/access/spgist.h
*************** extern IndexBuildResult *spgbuild(Relati
*** 191,197 ****
  extern void spgbuildempty(Relation index);
  extern bool spginsert(Relation index, Datum *values, bool *isnull,
  		  ItemPointer ht_ctid, Relation heapRel,
! 		  IndexUniqueCheck checkUnique);
  
  /* spgscan.c */
  extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz);
--- 191,198 ----
  extern void spgbuildempty(Relation index);
  extern bool spginsert(Relation index, Datum *values, bool *isnull,
  		  ItemPointer ht_ctid, Relation heapRel,
! 		  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 f9bcdd6..42c6c58 100644
*** a/src/include/nodes/execnodes.h
--- b/src/include/nodes/execnodes.h
***************
*** 52,57 ****
--- 52,59 ----
   *		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.
*************** typedef struct IndexInfo
*** 76,81 ****
--- 78,85 ----
  	bool		ii_ReadyForInserts;
  	bool		ii_Concurrent;
  	bool		ii_BrokenHotChain;
+ 	void	   *ii_AmCache;
+ 	MemoryContext ii_Context;
  } IndexInfo;
  
  /* ----------------
