diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 28c547ffe69fc8376bd95835f815e2d8480ddbb4..640c189886021154fbfc37b7a7a04910792c0642 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.61 2000/07/12 02:36:46 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.62 2000/07/14 22:17:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,53 +65,42 @@ gistbuild(PG_FUNCTION_ARGS)
 {
 	Relation		heap = (Relation) PG_GETARG_POINTER(0);
 	Relation		index = (Relation) PG_GETARG_POINTER(1);
-	int32			natts = PG_GETARG_INT32(2);
-	AttrNumber	   *attnum = (AttrNumber *) PG_GETARG_POINTER(3);
-	FuncIndexInfo  *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(4);
-	PredInfo	   *predInfo = (PredInfo *) PG_GETARG_POINTER(5);
+	IndexInfo	   *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
+	Node		   *oldPred = (Node *) PG_GETARG_POINTER(3);
 #ifdef NOT_USED
-	bool			unique = PG_GETARG_BOOL(6);
-	IndexStrategy	istrat = (IndexStrategy) PG_GETARG_POINTER(7);
+	IndexStrategy	istrat = (IndexStrategy) PG_GETARG_POINTER(4);
 #endif
-	HeapScanDesc scan;
-	AttrNumber	i;
+	HeapScanDesc hscan;
 	HeapTuple	htup;
 	IndexTuple	itup;
-	TupleDesc	hd,
-				id;
-	InsertIndexResult res;
-	Datum	   *d;
-	bool	   *nulls;
-	int			nb,
-				nh,
-				ni;
+	TupleDesc	htupdesc,
+				itupdesc;
+	Datum		attdata[INDEX_MAX_KEYS];
+	char		nulls[INDEX_MAX_KEYS];
+	int			nhtups,
+				nitups;
+	Node	   *pred = indexInfo->ii_Predicate;
 #ifndef OMIT_PARTIAL_INDEX
-	ExprContext *econtext;
 	TupleTable	tupleTable;
 	TupleTableSlot *slot;
 #endif
-	Node	   *pred,
-			   *oldPred;
+	ExprContext *econtext;
+	InsertIndexResult res = NULL;
 	GISTSTATE	giststate;
 	GISTENTRY	tmpcentry;
 	Buffer		buffer = InvalidBuffer;
 	bool	   *compvec;
+	int			i;
 
 	/* no locking is needed */
 
-	CommandCounterIncrement();	/* so we can see the new pg_index tuple */
-
 	initGISTstate(&giststate, index);
 
-	pred = predInfo->pred;
-	oldPred = predInfo->oldPred;
-
 	/*
 	 * We expect to be called exactly once for any index relation. If
 	 * that's not the case, big trouble's what we have.
 	 */
-
-	if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
+	if (oldPred == NULL && RelationGetNumberOfBlocks(index) != 0)
 		elog(ERROR, "%s already contains data", RelationGetRelationName(index));
 
 	/* initialize the root page (if this is a new index) */
@@ -122,43 +111,50 @@ gistbuild(PG_FUNCTION_ARGS)
 		WriteBuffer(buffer);
 	}
 
-	/* init the tuple descriptors and get set for a heap scan */
-	hd = RelationGetDescr(heap);
-	id = RelationGetDescr(index);
-	d = (Datum *) palloc(natts * sizeof(*d));
-	nulls = (bool *) palloc(natts * sizeof(*nulls));
+	/* get tuple descriptors for heap and index relations */
+	htupdesc = RelationGetDescr(heap);
+	itupdesc = RelationGetDescr(index);
 
 	/*
 	 * If this is a predicate (partial) index, we will need to evaluate
 	 * the predicate using ExecQual, which requires the current tuple to
 	 * be in a slot of a TupleTable.  In addition, ExecQual must have an
 	 * ExprContext referring to that slot.	Here, we initialize dummy
-	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb
-	 * '92
+	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
+	 *
+	 * We construct the ExprContext anyway since we need a per-tuple
+	 * temporary memory context for function evaluation -- tgl July 00
 	 */
 #ifndef OMIT_PARTIAL_INDEX
 	if (pred != NULL || oldPred != NULL)
 	{
 		tupleTable = ExecCreateTupleTable(1);
 		slot = ExecAllocTableSlot(tupleTable);
-		ExecSetSlotDescriptor(slot, hd);
-		econtext = MakeExprContext(slot, TransactionCommandContext);
+		ExecSetSlotDescriptor(slot, htupdesc);
 	}
 	else
 	{
 		tupleTable = NULL;
 		slot = NULL;
-		econtext = NULL;
 	}
+	econtext = MakeExprContext(slot, TransactionCommandContext);
+#else
+	econtext = MakeExprContext(NULL, TransactionCommandContext);
 #endif	 /* OMIT_PARTIAL_INDEX */
-	/* int the tuples as we insert them */
-	nh = ni = 0;
 
-	scan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
+	/* build the index */
+	nhtups = nitups = 0;
+
+	compvec = (bool *) palloc(sizeof(bool) * indexInfo->ii_NumIndexAttrs);
 
-	while (HeapTupleIsValid(htup = heap_getnext(scan, 0)))
+	/* start a heap scan */
+	hscan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
+
+	while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
 	{
-		nh++;
+		MemoryContextReset(econtext->ecxt_per_tuple_memory);
+
+		nhtups++;
 
 #ifndef OMIT_PARTIAL_INDEX
 		/*
@@ -167,11 +163,10 @@ gistbuild(PG_FUNCTION_ARGS)
 		 */
 		if (oldPred != NULL)
 		{
-			/* SetSlotContents(slot, htup); */
 			slot->val = htup;
 			if (ExecQual((List *) oldPred, econtext, false))
 			{
-				ni++;
+				nitups++;
 				continue;
 			}
 		}
@@ -182,61 +177,41 @@ gistbuild(PG_FUNCTION_ARGS)
 		 */
 		if (pred != NULL)
 		{
-			/* SetSlotContents(slot, htup); */
 			slot->val = htup;
 			if (!ExecQual((List *) pred, econtext, false))
 				continue;
 		}
 #endif	 /* OMIT_PARTIAL_INDEX */
 
-		ni++;
+		nitups++;
 
 		/*
 		 * For the current heap tuple, extract all the attributes we use
 		 * in this index, and note which are null.
 		 */
-
-		for (i = 1; i <= natts; i++)
-		{
-			int			attoff;
-			bool		attnull;
-
-			/*
-			 * Offsets are from the start of the tuple, and are
-			 * zero-based; indices are one-based.  The next call returns i
-			 * - 1.  That's data hiding for you.
-			 */
-
-			attoff = AttrNumberGetAttrOffset(i);
-
-			/*
-			 * d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
-			 */
-			d[attoff] = GetIndexValue(htup,
-									  hd,
-									  attoff,
-									  attnum,
-									  finfo,
-									  &attnull);
-			nulls[attoff] = (attnull ? 'n' : ' ');
-		}
+		FormIndexDatum(indexInfo,
+					   htup,
+					   htupdesc,
+					   econtext->ecxt_per_tuple_memory,
+					   attdata,
+					   nulls);
 
 		/* immediately compress keys to normalize */
-		compvec = (bool *) palloc(sizeof(bool) * natts);
-		for (i = 0; i < natts; i++)
+		for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
 		{
-			gistcentryinit(&giststate, &tmpcentry, (char *) d[i],
+			gistcentryinit(&giststate, &tmpcentry, (char *) attdata[i],
 						   (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
 						   -1 /* size is currently bogus */ , TRUE);
-			if (d[i] != (Datum) tmpcentry.pred && !(giststate.keytypbyval))
+			if (attdata[i] != (Datum) tmpcentry.pred &&
+				!(giststate.keytypbyval))
 				compvec[i] = TRUE;
 			else
 				compvec[i] = FALSE;
-			d[i] = (Datum) tmpcentry.pred;
+			attdata[i] = (Datum) tmpcentry.pred;
 		}
 
 		/* form an index tuple and point it at the heap tuple */
-		itup = index_formtuple(id, &d[0], nulls);
+		itup = index_formtuple(itupdesc, attdata, nulls);
 		itup->t_tid = htup->t_self;
 
 		/*
@@ -248,24 +223,27 @@ gistbuild(PG_FUNCTION_ARGS)
 		 */
 
 		res = gistdoinsert(index, itup, &giststate);
-		for (i = 0; i < natts; i++)
-			if (compvec[i] == TRUE)
-				pfree((char *) d[i]);
+
+		for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+			if (compvec[i])
+				pfree(DatumGetPointer(attdata[i]));
+
 		pfree(itup);
 		pfree(res);
-		pfree(compvec);
 	}
 
 	/* okay, all heap tuples are indexed */
-	heap_endscan(scan);
+	heap_endscan(hscan);
+
+	pfree(compvec);
 
 #ifndef OMIT_PARTIAL_INDEX
 	if (pred != NULL || oldPred != NULL)
 	{
 		ExecDropTupleTable(tupleTable, true);
-		FreeExprContext(econtext);
 	}
 #endif	 /* OMIT_PARTIAL_INDEX */
+	FreeExprContext(econtext);
 
 	/*
 	 * Since we just counted the tuples in the heap, we update its stats
@@ -286,20 +264,16 @@ gistbuild(PG_FUNCTION_ARGS)
 
 		heap_close(heap, NoLock);
 		index_close(index);
-		UpdateStats(hrelid, nh, inplace);
-		UpdateStats(irelid, ni, inplace);
+		UpdateStats(hrelid, nhtups, inplace);
+		UpdateStats(irelid, nitups, inplace);
 		if (oldPred != NULL && !inplace)
 		{
-			if (ni == nh)
+			if (nitups == nhtups)
 				pred = NULL;
 			UpdateIndexPredicate(irelid, oldPred, pred);
 		}
 	}
 
-	/* be tidy */
-	pfree(nulls);
-	pfree(d);
-
 	PG_RETURN_VOID();
 }
 
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 354d4985723cafa06c48355dd47fffbcf041330b..cb740bbde9ed179379af480d337655cbd7302545 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.41 2000/07/12 02:36:46 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.42 2000/07/14 22:17:28 tgl Exp $
  *
  * NOTES
  *	  This file contains only the public interface routines.
@@ -41,42 +41,32 @@ hashbuild(PG_FUNCTION_ARGS)
 {
 	Relation		heap = (Relation) PG_GETARG_POINTER(0);
 	Relation		index = (Relation) PG_GETARG_POINTER(1);
-	int32			natts = PG_GETARG_INT32(2);
-	AttrNumber	   *attnum = (AttrNumber *) PG_GETARG_POINTER(3);
-	FuncIndexInfo  *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(4);
-	PredInfo	   *predInfo = (PredInfo *) PG_GETARG_POINTER(5);
+	IndexInfo	   *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
+	Node		   *oldPred = (Node *) PG_GETARG_POINTER(3);
 #ifdef NOT_USED
-	bool			unique = PG_GETARG_BOOL(6);
-	IndexStrategy	istrat = (IndexStrategy) PG_GETARG_POINTER(7);
+	IndexStrategy	istrat = (IndexStrategy) PG_GETARG_POINTER(4);
 #endif
 	HeapScanDesc hscan;
 	HeapTuple	htup;
 	IndexTuple	itup;
 	TupleDesc	htupdesc,
 				itupdesc;
-	Datum	   *attdata;
-	bool	   *nulls;
-	InsertIndexResult res;
+	Datum		attdata[INDEX_MAX_KEYS];
+	char		nulls[INDEX_MAX_KEYS];
 	int			nhtups,
 				nitups;
-	int			i;
 	HashItem	hitem;
-
+	Node	   *pred = indexInfo->ii_Predicate;
 #ifndef OMIT_PARTIAL_INDEX
-	ExprContext *econtext;
 	TupleTable	tupleTable;
 	TupleTableSlot *slot;
-
 #endif
-	Node	   *pred,
-			   *oldPred;
+	ExprContext *econtext;
+	InsertIndexResult res = NULL;
 
-	/* note that this is a new btree */
+	/* note that this is a new hash */
 	BuildingHash = true;
 
-	pred = predInfo->pred;
-	oldPred = predInfo->oldPred;
-
 	/* initialize the hash index metadata page (if this is a new index) */
 	if (oldPred == NULL)
 		_hash_metapinit(index);
@@ -85,17 +75,15 @@ hashbuild(PG_FUNCTION_ARGS)
 	htupdesc = RelationGetDescr(heap);
 	itupdesc = RelationGetDescr(index);
 
-	/* get space for data items that'll appear in the index tuple */
-	attdata = (Datum *) palloc(natts * sizeof(Datum));
-	nulls = (bool *) palloc(natts * sizeof(bool));
-
 	/*
 	 * If this is a predicate (partial) index, we will need to evaluate
 	 * the predicate using ExecQual, which requires the current tuple to
 	 * be in a slot of a TupleTable.  In addition, ExecQual must have an
 	 * ExprContext referring to that slot.	Here, we initialize dummy
-	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb
-	 * '92
+	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
+	 *
+	 * We construct the ExprContext anyway since we need a per-tuple
+	 * temporary memory context for function evaluation -- tgl July 00
 	 */
 #ifndef OMIT_PARTIAL_INDEX
 	if (pred != NULL || oldPred != NULL)
@@ -103,14 +91,15 @@ hashbuild(PG_FUNCTION_ARGS)
 		tupleTable = ExecCreateTupleTable(1);
 		slot = ExecAllocTableSlot(tupleTable);
 		ExecSetSlotDescriptor(slot, htupdesc);
-		econtext = MakeExprContext(slot, TransactionCommandContext);
 	}
 	else
 	{
 		tupleTable = NULL;
 		slot = NULL;
-		econtext = NULL;
 	}
+	econtext = MakeExprContext(slot, TransactionCommandContext);
+#else
+	econtext = MakeExprContext(NULL, TransactionCommandContext);
 #endif	 /* OMIT_PARTIAL_INDEX */
 
 	/* build the index */
@@ -121,6 +110,8 @@ hashbuild(PG_FUNCTION_ARGS)
 
 	while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
 	{
+		MemoryContextReset(econtext->ecxt_per_tuple_memory);
+
 		nhtups++;
 
 #ifndef OMIT_PARTIAL_INDEX
@@ -130,7 +121,6 @@ hashbuild(PG_FUNCTION_ARGS)
 		 */
 		if (oldPred != NULL)
 		{
-			/* SetSlotContents(slot, htup); */
 			slot->val = htup;
 			if (ExecQual((List *) oldPred, econtext, false))
 			{
@@ -145,7 +135,6 @@ hashbuild(PG_FUNCTION_ARGS)
 		 */
 		if (pred != NULL)
 		{
-			/* SetSlotContents(slot, htup); */
 			slot->val = htup;
 			if (!ExecQual((List *) pred, econtext, false))
 				continue;
@@ -158,33 +147,12 @@ hashbuild(PG_FUNCTION_ARGS)
 		 * For the current heap tuple, extract all the attributes we use
 		 * in this index, and note which are null.
 		 */
-		for (i = 1; i <= natts; i++)
-		{
-			int			attoff;
-			bool		attnull;
-
-			/*
-			 * Offsets are from the start of the tuple, and are
-			 * zero-based; indices are one-based.  The next call returns i
-			 * - 1.  That's data hiding for you.
-			 */
-
-			/* attoff = i - 1 */
-			attoff = AttrNumberGetAttrOffset(i);
-
-			/*
-			 * below, attdata[attoff] set to equal some datum & attnull is
-			 * changed to indicate whether or not the attribute is null
-			 * for this tuple
-			 */
-			attdata[attoff] = GetIndexValue(htup,
-											htupdesc,
-											attoff,
-											attnum,
-											finfo,
-											&attnull);
-			nulls[attoff] = (attnull ? 'n' : ' ');
-		}
+		FormIndexDatum(indexInfo,
+					   htup,
+					   htupdesc,
+					   econtext->ecxt_per_tuple_memory,
+					   attdata,
+					   nulls);
 
 		/* form an index tuple and point it at the heap tuple */
 		itup = index_formtuple(itupdesc, attdata, nulls);
@@ -208,7 +176,9 @@ hashbuild(PG_FUNCTION_ARGS)
 
 		itup->t_tid = htup->t_self;
 		hitem = _hash_formitem(itup);
+
 		res = _hash_doinsert(index, hitem);
+
 		pfree(hitem);
 		pfree(itup);
 		pfree(res);
@@ -221,9 +191,9 @@ hashbuild(PG_FUNCTION_ARGS)
 	if (pred != NULL || oldPred != NULL)
 	{
 		ExecDropTupleTable(tupleTable, true);
-		FreeExprContext(econtext);
 	}
 #endif	 /* OMIT_PARTIAL_INDEX */
+	FreeExprContext(econtext);
 
 	/*
 	 * Since we just counted the tuples in the heap, we update its stats
@@ -254,10 +224,6 @@ hashbuild(PG_FUNCTION_ARGS)
 		}
 	}
 
-	/* be tidy */
-	pfree(nulls);
-	pfree(attdata);
-
 	/* all done */
 	BuildingHash = false;
 
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 2d1504238deb9cd4375cc40f6187a7c287c5df40..dc18b0d3b776c9f8004f2c5f96618428307cbc60 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.45 2000/06/13 07:34:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.46 2000/07/14 22:17:30 tgl Exp $
  *
  * INTERFACE ROUTINES
  *		index_open		- open an index relation by relationId
@@ -424,56 +424,3 @@ index_getprocid(Relation irel,
 
 	return loc[(natts * (procnum - 1)) + (attnum - 1)];
 }
-
-Datum
-GetIndexValue(HeapTuple tuple,
-			  TupleDesc hTupDesc,
-			  int attOff,
-			  AttrNumber *attrNums,
-			  FuncIndexInfo *fInfo,
-			  bool *attNull)
-{
-	Datum		returnVal;
-
-	if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid)
-	{
-		FmgrInfo				flinfo;
-		FunctionCallInfoData	fcinfo;
-		int						i;
-		bool					anynull = false;
-
-		/*
-		 * XXX ought to store lookup info in FuncIndexInfo so it need not
-		 * be repeated on each call?
-		 */
-		fmgr_info(FIgetProcOid(fInfo), &flinfo);
-
-		MemSet(&fcinfo, 0, sizeof(fcinfo));
-		fcinfo.flinfo = &flinfo;
-		fcinfo.nargs = FIgetnArgs(fInfo);
-
-		for (i = 0; i < FIgetnArgs(fInfo); i++)
-		{
-			fcinfo.arg[i] = heap_getattr(tuple,
-										 attrNums[i],
-										 hTupDesc,
-										 &fcinfo.argnull[i]);
-			anynull |= fcinfo.argnull[i];
-		}
-		if (flinfo.fn_strict && anynull)
-		{
-			/* force a null result for strict function */
-			returnVal = (Datum) 0;
-			*attNull = true;
-		}
-		else
-		{
-			returnVal = FunctionCallInvoke(&fcinfo);
-			*attNull = fcinfo.isnull;
-		}
-	}
-	else
-		returnVal = heap_getattr(tuple, attrNums[attOff], hTupDesc, attNull);
-
-	return returnVal;
-}
diff --git a/src/backend/access/index/istrat.c b/src/backend/access/index/istrat.c
index fc7ac6dcb142b9dc771448593a0098a552cb119c..d6a966bcd44a700c19f0ac8c6c45ef56787d7fb8 100644
--- a/src/backend/access/index/istrat.c
+++ b/src/backend/access/index/istrat.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.45 2000/06/08 22:36:51 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.46 2000/07/14 22:17:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -533,6 +533,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
 void
 IndexSupportInitialize(IndexStrategy indexStrategy,
 					   RegProcedure *indexSupport,
+					   bool *isUnique,
 					   Oid indexObjectId,
 					   Oid accessMethodObjectId,
 					   StrategyNumber maxStrategyNumber,
@@ -544,6 +545,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 	ScanKeyData entry[2];
 	Relation	operatorRelation;
 	HeapTuple	tuple;
+	Form_pg_index iform;
 	StrategyMap map;
 	AttrNumber	attributeNumber;
 	int			attributeIndex;
@@ -568,7 +570,12 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 	}
 
 	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "IndexSupportInitialize: corrupted catalogs");
+		elog(ERROR, "IndexSupportInitialize: no pg_index entry for index %u",
+			 indexObjectId);
+
+	iform = (Form_pg_index) GETSTRUCT(tuple);
+
+	*isUnique = iform->indisunique;
 
 	maxStrategyNumber = AMStrategies(maxStrategyNumber);
 
@@ -578,10 +585,6 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 	 */
 	for (attributeIndex = 0; attributeIndex < maxAttributeNumber; attributeIndex++)
 	{
-		Form_pg_index iform;
-
-		iform = (Form_pg_index) GETSTRUCT(tuple);
-
 		if (!OidIsValid(iform->indkey[attributeIndex]))
 		{
 			if (attributeIndex == InvalidAttrNumber)
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 3d8ea1a70a8e8e04eb93d2e324b63f7506618ce7..b174d303176e95f04db9429992b673b42d7125f8 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.60 2000/07/12 02:36:48 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.61 2000/07/14 22:17:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,44 +45,34 @@ btbuild(PG_FUNCTION_ARGS)
 {
 	Relation		heap = (Relation) PG_GETARG_POINTER(0);
 	Relation		index = (Relation) PG_GETARG_POINTER(1);
-	int32			natts = PG_GETARG_INT32(2);
-	AttrNumber	   *attnum = (AttrNumber *) PG_GETARG_POINTER(3);
-	FuncIndexInfo  *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(4);
-	PredInfo	   *predInfo = (PredInfo *) PG_GETARG_POINTER(5);
-	bool			unique = PG_GETARG_BOOL(6);
+	IndexInfo	   *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
+	Node		   *oldPred = (Node *) PG_GETARG_POINTER(3);
 #ifdef NOT_USED
-	IndexStrategy	istrat = (IndexStrategy) PG_GETARG_POINTER(7);
+	IndexStrategy	istrat = (IndexStrategy) PG_GETARG_POINTER(4);
 #endif
 	HeapScanDesc hscan;
 	HeapTuple	htup;
 	IndexTuple	itup;
 	TupleDesc	htupdesc,
 				itupdesc;
-	Datum	   *attdata;
-	bool	   *nulls;
-	InsertIndexResult res = 0;
+	Datum		attdata[INDEX_MAX_KEYS];
+	char		nulls[INDEX_MAX_KEYS];
 	int			nhtups,
 				nitups;
-	int			i;
-	BTItem		btitem;
-
+	Node	   *pred = indexInfo->ii_Predicate;
 #ifndef OMIT_PARTIAL_INDEX
-	ExprContext *econtext = (ExprContext *) NULL;
-	TupleTable	tupleTable = (TupleTable) NULL;
-	TupleTableSlot *slot = (TupleTableSlot *) NULL;
-
+	TupleTable	tupleTable;
+	TupleTableSlot *slot;
 #endif
-	Node	   *pred,
-			   *oldPred;
+	ExprContext *econtext;
+	InsertIndexResult res = NULL;
 	BTSpool    *spool = NULL;
+	BTItem		btitem;
 	bool		usefast;
 
 	/* note that this is a new btree */
 	BuildingBtree = true;
 
-	pred = predInfo->pred;
-	oldPred = predInfo->oldPred;
-
 	/*
 	 * bootstrap processing does something strange, so don't use
 	 * sort/build for initial catalog indices.	at some point i need to
@@ -104,17 +94,15 @@ btbuild(PG_FUNCTION_ARGS)
 	htupdesc = RelationGetDescr(heap);
 	itupdesc = RelationGetDescr(index);
 
-	/* get space for data items that'll appear in the index tuple */
-	attdata = (Datum *) palloc(natts * sizeof(Datum));
-	nulls = (bool *) palloc(natts * sizeof(bool));
-
 	/*
 	 * If this is a predicate (partial) index, we will need to evaluate
 	 * the predicate using ExecQual, which requires the current tuple to
 	 * be in a slot of a TupleTable.  In addition, ExecQual must have an
 	 * ExprContext referring to that slot.	Here, we initialize dummy
-	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb
-	 * '92
+	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
+	 *
+	 * We construct the ExprContext anyway since we need a per-tuple
+	 * temporary memory context for function evaluation -- tgl July 00
 	 */
 #ifndef OMIT_PARTIAL_INDEX
 	if (pred != NULL || oldPred != NULL)
@@ -122,7 +110,6 @@ btbuild(PG_FUNCTION_ARGS)
 		tupleTable = ExecCreateTupleTable(1);
 		slot = ExecAllocTableSlot(tupleTable);
 		ExecSetSlotDescriptor(slot, htupdesc);
-		econtext = MakeExprContext(slot, TransactionCommandContext);
 
 		/*
 		 * we never want to use sort/build if we are extending an existing
@@ -133,22 +120,29 @@ btbuild(PG_FUNCTION_ARGS)
 		 */
 		usefast = false;
 	}
+	else
+	{
+		tupleTable = NULL;
+		slot = NULL;
+	}
+	econtext = MakeExprContext(slot, TransactionCommandContext);
+#else
+	econtext = MakeExprContext(NULL, TransactionCommandContext);
 #endif	 /* OMIT_PARTIAL_INDEX */
 
-	/* start a heap scan */
 	/* build the index */
 	nhtups = nitups = 0;
 
 	if (usefast)
-	{
-		spool = _bt_spoolinit(index, unique);
-		res = (InsertIndexResult) NULL;
-	}
+		spool = _bt_spoolinit(index, indexInfo->ii_Unique);
 
+	/* start a heap scan */
 	hscan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
 
 	while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
 	{
+		MemoryContextReset(econtext->ecxt_per_tuple_memory);
+
 		nhtups++;
 
 #ifndef OMIT_PARTIAL_INDEX
@@ -158,7 +152,6 @@ btbuild(PG_FUNCTION_ARGS)
 		 */
 		if (oldPred != NULL)
 		{
-			/* SetSlotContents(slot, htup); */
 			slot->val = htup;
 			if (ExecQual((List *) oldPred, econtext, false))
 			{
@@ -173,7 +166,6 @@ btbuild(PG_FUNCTION_ARGS)
 		 */
 		if (pred != NULL)
 		{
-			/* SetSlotContents(slot, htup); */
 			slot->val = htup;
 			if (!ExecQual((List *) pred, econtext, false))
 				continue;
@@ -186,27 +178,12 @@ btbuild(PG_FUNCTION_ARGS)
 		 * For the current heap tuple, extract all the attributes we use
 		 * in this index, and note which are null.
 		 */
-
-		for (i = 1; i <= natts; i++)
-		{
-			int			attoff;
-			bool		attnull;
-
-			/*
-			 * Offsets are from the start of the tuple, and are
-			 * zero-based; indices are one-based.  The next call returns i
-			 * - 1.  That's data hiding for you.
-			 */
-
-			attoff = AttrNumberGetAttrOffset(i);
-			attdata[attoff] = GetIndexValue(htup,
-											htupdesc,
-											attoff,
-											attnum,
-											finfo,
-											&attnull);
-			nulls[attoff] = (attnull ? 'n' : ' ');
-		}
+		FormIndexDatum(indexInfo,
+					   htup,
+					   htupdesc,
+					   econtext->ecxt_per_tuple_memory,
+					   attdata,
+					   nulls);
 
 		/* form an index tuple and point it at the heap tuple */
 		itup = index_formtuple(itupdesc, attdata, nulls);
@@ -246,7 +223,7 @@ btbuild(PG_FUNCTION_ARGS)
 		if (usefast)
 			_bt_spool(btitem, spool);
 		else
-			res = _bt_doinsert(index, btitem, unique, heap);
+			res = _bt_doinsert(index, btitem, indexInfo->ii_Unique, heap);
 
 		pfree(btitem);
 		pfree(itup);
@@ -261,9 +238,9 @@ btbuild(PG_FUNCTION_ARGS)
 	if (pred != NULL || oldPred != NULL)
 	{
 		ExecDropTupleTable(tupleTable, true);
-		FreeExprContext(econtext);
 	}
 #endif	 /* OMIT_PARTIAL_INDEX */
+	FreeExprContext(econtext);
 
 	/*
 	 * if we are doing bottom-up btree build, finish the build by (1)
@@ -305,10 +282,6 @@ btbuild(PG_FUNCTION_ARGS)
 		heap_close(heap, NoLock);
 		index_close(index);
 
-		/*
-		 * UpdateStats(hrelid, nhtups, true); UpdateStats(irelid, nitups,
-		 * false);
-		 */
 		UpdateStats(hrelid, nhtups, inplace);
 		UpdateStats(irelid, nitups, inplace);
 		if (oldPred != NULL)
@@ -320,9 +293,6 @@ btbuild(PG_FUNCTION_ARGS)
 		}
 	}
 
-	pfree(nulls);
-	pfree(attdata);
-
 	/* all done */
 	BuildingBtree = false;
 
@@ -361,8 +331,7 @@ btinsert(PG_FUNCTION_ARGS)
 
 	btitem = _bt_formitem(itup);
 
-	res = _bt_doinsert(rel, btitem,
-					   IndexIsUnique(RelationGetRelid(rel)), heapRel);
+	res = _bt_doinsert(rel, btitem, rel->rd_uniqueindex, heapRel);
 
 	pfree(btitem);
 	pfree(itup);
diff --git a/src/backend/access/rtree/rtree.c b/src/backend/access/rtree/rtree.c
index badff1ee21bec6f5b172755398a4429f598e61cb..583baa534a369e2c8a6957fbf4f22a4ff03ad63a 100644
--- a/src/backend/access/rtree/rtree.c
+++ b/src/backend/access/rtree/rtree.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.51 2000/07/12 02:36:52 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.52 2000/07/14 22:17:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,49 +64,37 @@ rtbuild(PG_FUNCTION_ARGS)
 {
 	Relation		heap = (Relation) PG_GETARG_POINTER(0);
 	Relation		index = (Relation) PG_GETARG_POINTER(1);
-	int32			natts = PG_GETARG_INT32(2);
-	AttrNumber	   *attnum = (AttrNumber *) PG_GETARG_POINTER(3);
-	FuncIndexInfo  *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(4);
-	PredInfo	   *predInfo = (PredInfo *) PG_GETARG_POINTER(5);
+	IndexInfo	   *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
+	Node		   *oldPred = (Node *) PG_GETARG_POINTER(3);
 #ifdef NOT_USED
-	bool			unique = PG_GETARG_BOOL(6);
-	IndexStrategy	istrat = (IndexStrategy) PG_GETARG_POINTER(7);
+	IndexStrategy	istrat = (IndexStrategy) PG_GETARG_POINTER(4);
 #endif
-	HeapScanDesc scan;
-	AttrNumber	i;
+	HeapScanDesc hscan;
 	HeapTuple	htup;
 	IndexTuple	itup;
-	TupleDesc	hd,
-				id;
-	InsertIndexResult res;
-	Datum	   *d;
-	bool	   *nulls;
-	Buffer		buffer = InvalidBuffer;
-	int			nb,
-				nh,
-				ni;
-
+	TupleDesc	htupdesc,
+				itupdesc;
+	Datum		attdata[INDEX_MAX_KEYS];
+	char		nulls[INDEX_MAX_KEYS];
+	int			nhtups,
+				nitups;
+	Node	   *pred = indexInfo->ii_Predicate;
 #ifndef OMIT_PARTIAL_INDEX
-	ExprContext *econtext;
 	TupleTable	tupleTable;
 	TupleTableSlot *slot;
-
 #endif
-	Node	   *pred,
-			   *oldPred;
+	ExprContext *econtext;
+	InsertIndexResult res = NULL;
+	Buffer		buffer = InvalidBuffer;
 	RTSTATE		rtState;
 
 	initRtstate(&rtState, index);
 
-	pred = predInfo->pred;
-	oldPred = predInfo->oldPred;
-
 	/*
 	 * We expect to be called exactly once for any index relation. If
 	 * that's not the case, big trouble's what we have.
 	 */
-
-	if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
+	if (oldPred == NULL && RelationGetNumberOfBlocks(index) != 0)
 		elog(ERROR, "%s already contains data", RelationGetRelationName(index));
 
 	/* initialize the root page (if this is a new index) */
@@ -117,44 +105,48 @@ rtbuild(PG_FUNCTION_ARGS)
 		WriteBuffer(buffer);
 	}
 
-	/* init the tuple descriptors and get set for a heap scan */
-	hd = RelationGetDescr(heap);
-	id = RelationGetDescr(index);
-	d = (Datum *) palloc(natts * sizeof(*d));
-	nulls = (bool *) palloc(natts * sizeof(*nulls));
+	/* get tuple descriptors for heap and index relations */
+	htupdesc = RelationGetDescr(heap);
+	itupdesc = RelationGetDescr(index);
 
 	/*
 	 * If this is a predicate (partial) index, we will need to evaluate
 	 * the predicate using ExecQual, which requires the current tuple to
 	 * be in a slot of a TupleTable.  In addition, ExecQual must have an
 	 * ExprContext referring to that slot.	Here, we initialize dummy
-	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb
-	 * '92
+	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
+	 *
+	 * We construct the ExprContext anyway since we need a per-tuple
+	 * temporary memory context for function evaluation -- tgl July 00
 	 */
 #ifndef OMIT_PARTIAL_INDEX
 	if (pred != NULL || oldPred != NULL)
 	{
 		tupleTable = ExecCreateTupleTable(1);
 		slot = ExecAllocTableSlot(tupleTable);
-		ExecSetSlotDescriptor(slot, hd);
-		econtext = MakeExprContext(slot, TransactionCommandContext);
+		ExecSetSlotDescriptor(slot, htupdesc);
 	}
 	else
 	{
 		tupleTable = NULL;
 		slot = NULL;
-		econtext = NULL;
 	}
+	econtext = MakeExprContext(slot, TransactionCommandContext);
+#else
+	econtext = MakeExprContext(NULL, TransactionCommandContext);
 #endif	 /* OMIT_PARTIAL_INDEX */
 
 	/* count the tuples as we insert them */
-	nh = ni = 0;
+	nhtups = nitups = 0;
 
-	scan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
+	/* start a heap scan */
+	hscan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
 
-	while (HeapTupleIsValid(htup = heap_getnext(scan, 0)))
+	while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
 	{
-		nh++;
+		MemoryContextReset(econtext->ecxt_per_tuple_memory);
+
+		nhtups++;
 
 #ifndef OMIT_PARTIAL_INDEX
 		/*
@@ -163,11 +155,10 @@ rtbuild(PG_FUNCTION_ARGS)
 		 */
 		if (oldPred != NULL)
 		{
-			/* SetSlotContents(slot, htup); */
 			slot->val = htup;
 			if (ExecQual((List *) oldPred, econtext, false))
 			{
-				ni++;
+				nitups++;
 				continue;
 			}
 		}
@@ -178,47 +169,27 @@ rtbuild(PG_FUNCTION_ARGS)
 		 */
 		if (pred != NULL)
 		{
-			/* SetSlotContents(slot, htup); */
 			slot->val = htup;
 			if (!ExecQual((List *) pred, econtext, false))
 				continue;
 		}
 #endif	 /* OMIT_PARTIAL_INDEX */
 
-		ni++;
+		nitups++;
 
 		/*
 		 * For the current heap tuple, extract all the attributes we use
 		 * in this index, and note which are null.
 		 */
-
-		for (i = 1; i <= natts; i++)
-		{
-			int			attoff;
-			bool		attnull;
-
-			/*
-			 * Offsets are from the start of the tuple, and are
-			 * zero-based; indices are one-based.  The next call returns i
-			 * - 1.  That's data hiding for you.
-			 */
-
-			attoff = AttrNumberGetAttrOffset(i);
-
-			/*
-			 * d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
-			 */
-			d[attoff] = GetIndexValue(htup,
-									  hd,
-									  attoff,
-									  attnum,
-									  finfo,
-									  &attnull);
-			nulls[attoff] = (attnull ? 'n' : ' ');
-		}
+		FormIndexDatum(indexInfo,
+					   htup,
+					   htupdesc,
+					   econtext->ecxt_per_tuple_memory,
+					   attdata,
+					   nulls);
 
 		/* form an index tuple and point it at the heap tuple */
-		itup = index_formtuple(id, &d[0], nulls);
+		itup = index_formtuple(itupdesc, attdata, nulls);
 		itup->t_tid = htup->t_self;
 
 		/*
@@ -235,15 +206,15 @@ rtbuild(PG_FUNCTION_ARGS)
 	}
 
 	/* okay, all heap tuples are indexed */
-	heap_endscan(scan);
+	heap_endscan(hscan);
 
 #ifndef OMIT_PARTIAL_INDEX
 	if (pred != NULL || oldPred != NULL)
 	{
 		ExecDropTupleTable(tupleTable, true);
-		FreeExprContext(econtext);
 	}
 #endif	 /* OMIT_PARTIAL_INDEX */
+	FreeExprContext(econtext);
 
 	/*
 	 * Since we just counted the tuples in the heap, we update its stats
@@ -264,20 +235,16 @@ rtbuild(PG_FUNCTION_ARGS)
 
 		heap_close(heap, NoLock);
 		index_close(index);
-		UpdateStats(hrelid, nh, inplace);
-		UpdateStats(irelid, ni, inplace);
+		UpdateStats(hrelid, nhtups, inplace);
+		UpdateStats(irelid, nitups, inplace);
 		if (oldPred != NULL && !inplace)
 		{
-			if (ni == nh)
+			if (nitups == nhtups)
 				pred = NULL;
 			UpdateIndexPredicate(irelid, oldPred, pred);
 		}
 	}
 
-	/* be tidy */
-	pfree(nulls);
-	pfree(d);
-
 	PG_RETURN_VOID();
 }
 
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 4c13aafc0eb075a05602aface14d607280182c1a..cf3cd1b280bd2be208766f5361d53b456b54ef22 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.31 2000/07/04 06:11:22 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.32 2000/07/14 22:17:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,7 +20,6 @@
 
 
 #include "access/attnum.h"
-#include "access/funcindex.h"
 #include "access/htup.h"
 #include "access/itup.h"
 #include "access/skey.h"
diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l
index 125ea516f17b5f0ead02cd2c1e706c70c93c2034..ed68c92ac289fc40e3e17e49ec9be45cf0608b31 100644
--- a/src/backend/bootstrap/bootscanner.l
+++ b/src/backend/bootstrap/bootscanner.l
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.17 2000/01/26 05:56:07 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.18 2000/07/14 22:17:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,6 @@
 #include "postgres.h"
 
 #include "access/attnum.h"
-#include "access/funcindex.h"
 #include "access/htup.h"
 #include "access/itup.h"
 #include "access/skey.h"
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 1c52d098a1aaa559cdf68ab6e30df2c20e2caac3..c3cf93717241ec962fb10b37c19dcc9f9319d48a 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.90 2000/07/03 23:09:23 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.91 2000/07/14 22:17:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -160,20 +160,12 @@ typedef struct _IndexList
 {
 	char	   *il_heap;
 	char	   *il_ind;
-	int			il_natts;
-	AttrNumber *il_attnos;
-	FuncIndexInfo *il_finfo;
-	PredInfo   *il_predInfo;
-	bool		il_unique;
+	IndexInfo  *il_info;
 	struct _IndexList *il_next;
 } IndexList;
 
 static IndexList *ILHead = (IndexList *) NULL;
 
-typedef void (*sig_func) ();
-
-
-
 
 /* ----------------------------------------------------------------
  *						misc functions
@@ -334,9 +326,9 @@ BootstrapMain(int argc, char *argv[])
 
 	if (!IsUnderPostmaster)
 	{
-		pqsignal(SIGINT, (sig_func) die);
-		pqsignal(SIGHUP, (sig_func) die);
-		pqsignal(SIGTERM, (sig_func) die);
+		pqsignal(SIGINT, (pqsigfunc) die);
+		pqsignal(SIGHUP, (pqsigfunc) die);
+		pqsignal(SIGTERM, (pqsigfunc) die);
 	}
 
 	/*
@@ -1080,14 +1072,9 @@ AddStr(char *str, int strlength, int mderef)
 void
 index_register(char *heap,
 			   char *ind,
-			   int natts,
-			   AttrNumber *attnos,
-			   FuncIndexInfo *finfo,
-			   PredInfo *predInfo,
-			   bool unique)
+			   IndexInfo *indexInfo)
 {
 	IndexList  *newind;
-	int			len;
 	MemoryContext oldcxt;
 
 	/*
@@ -1108,37 +1095,13 @@ index_register(char *heap,
 	newind = (IndexList *) palloc(sizeof(IndexList));
 	newind->il_heap = pstrdup(heap);
 	newind->il_ind = pstrdup(ind);
-	newind->il_natts = natts;
-
-	if (PointerIsValid(finfo))
-		len = FIgetnArgs(finfo) * sizeof(AttrNumber);
-	else
-		len = natts * sizeof(AttrNumber);
-
-	newind->il_attnos = (AttrNumber *) palloc(len);
-	memcpy(newind->il_attnos, attnos, len);
-
-	if (PointerIsValid(finfo))
-	{
-		newind->il_finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
-		memcpy(newind->il_finfo, finfo, sizeof(FuncIndexInfo));
-	}
-	else
-		newind->il_finfo = (FuncIndexInfo *) NULL;
+	newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
 
-	if (predInfo != NULL)
-	{
-		newind->il_predInfo = (PredInfo *) palloc(sizeof(PredInfo));
-		newind->il_predInfo->pred = predInfo->pred;
-		newind->il_predInfo->oldPred = predInfo->oldPred;
-	}
-	else
-		newind->il_predInfo = NULL;
-
-	newind->il_unique = unique;
+	memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
+	/* predicate will likely be null anyway, but may as well copy it */
+	newind->il_info->ii_Predicate = copyObject(indexInfo->ii_Predicate);
 
 	newind->il_next = ILHead;
-
 	ILHead = newind;
 
 	MemoryContextSwitchTo(oldcxt);
@@ -1147,18 +1110,16 @@ index_register(char *heap,
 void
 build_indices()
 {
-	Relation	heap;
-	Relation	ind;
-
 	for (; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next)
 	{
+		Relation	heap;
+		Relation	ind;
+
 		heap = heap_openr(ILHead->il_heap, NoLock);
 		Assert(heap);
 		ind = index_openr(ILHead->il_ind);
 		Assert(ind);
-		index_build(heap, ind, ILHead->il_natts, ILHead->il_attnos,
-					ILHead->il_finfo, ILHead->il_predInfo,
-					ILHead->il_unique);
+		index_build(heap, ind, ILHead->il_info, NULL);
 
 		/*
 		 * In normal processing mode, index_build would close the heap and
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 08b5e64c53def257e5b035f1adfdf8e2d9b3391f..b5334de15ed33aa5f51ccd21c8d6778ba4ccb095 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.139 2000/07/05 23:11:06 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.140 2000/07/14 22:17:40 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1073,91 +1073,37 @@ RelationTruncateIndexes(Relation heapRelation)
 	ScanKeyData entry;
 	HeapScanDesc scan;
 	HeapTuple	indexTuple,
-				procTuple,
 				classTuple;
-	Form_pg_index index;
+	IndexInfo  *indexInfo;
 	Oid			heapId,
 				indexId,
-				procId,
 				accessMethodId;
-	Node	   *oldPred = NULL;
-	PredInfo   *predInfo;
-	List	   *cnfPred = NULL;
-	AttrNumber *attributeNumberA;
-	FuncIndexInfo fInfo,
-			   *funcInfo = NULL;
-	bool		unique;
-	int			i,
-				numberOfAttributes;
-	char	   *predString;
 
 	heapId = RelationGetRelid(heapRelation);
 
 	/* Scan pg_index to find indexes on heapRelation */
-
 	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
 	ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
 						   ObjectIdGetDatum(heapId));
 	scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
 	while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
 	{
-
 		/*
-		 * For each index, fetch index attributes so we can apply
-		 * index_build
+		 * For each index, fetch info needed for index_build
 		 */
-		index = (Form_pg_index) GETSTRUCT(indexTuple);
-		indexId = index->indexrelid;
-		procId = index->indproc;
-		unique = index->indisunique;
-
-		for (i = 0; i < INDEX_MAX_KEYS; i++)
-		{
-			if (index->indkey[i] == InvalidAttrNumber)
-				break;
-		}
-		numberOfAttributes = i;
-
-		/* If a valid where predicate, compute predicate Node */
-		if (VARSIZE(&index->indpred) != 0)
-		{
-			predString = DatumGetCString(DirectFunctionCall1(textout,
-											PointerGetDatum(&index->indpred)));
-			oldPred = stringToNode(predString);
-			pfree(predString);
-		}
-		predInfo = (PredInfo *) palloc(sizeof(PredInfo));
-		predInfo->pred = (Node *) cnfPred;
-		predInfo->oldPred = oldPred;
-
-		/* Assign Index keys to attributes array */
-		attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
-												 sizeof(AttrNumber));
-		for (i = 0; i < numberOfAttributes; i++)
-			attributeNumberA[i] = index->indkey[i];
-
-		/* If this is a procedural index, initialize our FuncIndexInfo */
-		if (procId != InvalidOid)
-		{
-			funcInfo = &fInfo;
-			FIsetnArgs(funcInfo, numberOfAttributes);
-			procTuple = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(procId),
-											0, 0, 0);
-			if (!HeapTupleIsValid(procTuple))
-				elog(ERROR, "RelationTruncateIndexes: index procedure not found");
-			namecpy(&(funcInfo->funcName),
-					&(((Form_pg_proc) GETSTRUCT(procTuple))->proname));
-			FIsetProcOid(funcInfo, procTuple->t_data->t_oid);
-		}
+		indexId = ((Form_pg_index) GETSTRUCT(indexTuple))->indexrelid;
+		indexInfo = BuildIndexInfo(indexTuple);
 
-		/* Fetch the classTuple associated with this index */
-		classTuple = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(indexId),
+		/* Fetch the pg_class tuple associated with this index */
+		classTuple = SearchSysCacheTupleCopy(RELOID,
+											 ObjectIdGetDatum(indexId),
 											 0, 0, 0);
 		if (!HeapTupleIsValid(classTuple))
-			elog(ERROR, "RelationTruncateIndexes: index access method not found");
+			elog(ERROR, "RelationTruncateIndexes: index %u not found in pg_class",
+				 indexId);
 		accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
 
-		/* Open our index relation */
+		/* Open the index relation */
 		currentIndex = index_open(indexId);
 		if (currentIndex == NULL)
 			elog(ERROR, "RelationTruncateIndexes: can't open index relation");
@@ -1176,9 +1122,9 @@ RelationTruncateIndexes(Relation heapRelation)
 		currentIndex->rd_nblocks = 0;
 
 		/* Initialize the index and rebuild */
-		InitIndexStrategy(numberOfAttributes, currentIndex, accessMethodId);
-		index_build(heapRelation, currentIndex, numberOfAttributes,
-					attributeNumberA, funcInfo, predInfo, unique);
+		InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
+						  currentIndex, accessMethodId);
+		index_build(heapRelation, currentIndex, indexInfo, NULL);
 
 		/*
 		 * index_build will close both the heap and index relations (but
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 41d747b0dbfe534d8f0bc0bea5846391c2d1718a..2cbcb91ac0685d8a1e6d03509cc3430a8a915ba5 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,13 +8,14 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.125 2000/07/12 02:36:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.126 2000/07/14 22:17:41 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
  *		index_create()			- Create a cataloged index relation
  *		index_drop()			- Removes index relation from catalogs
- *
+ *		BuildIndexInfo()		- Prepare to insert index tuples
+ *		FormIndexDatum()		- Construct datum vector for one index tuple
  *
  *-------------------------------------------------------------------------
  */
@@ -58,28 +59,29 @@
 /* non-export function prototypes */
 static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
 				   bool istemp);
-static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
+static TupleDesc BuildFuncTupleDesc(Oid funcOid);
 static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
-				  List *attributeList, int numatts, AttrNumber *attNums);
-
+										  int numatts, AttrNumber *attNums);
 static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
 static Oid	UpdateRelationRelation(Relation indexRelation, char *temp_relname);
 static void InitializeAttributeOids(Relation indexRelation,
 						int numatts, Oid indexoid);
 static void AppendAttributeTuples(Relation indexRelation, int numatts);
 static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
-					FuncIndexInfo *funcInfo, int natts,
-					AttrNumber *attNums, Oid *classOids, Node *predicate,
-		   List *attributeList, bool islossy, bool unique, bool primary);
+								IndexInfo *indexInfo,
+								Oid *classOids,
+								bool islossy, bool primary);
 static void DefaultBuild(Relation heapRelation, Relation indexRelation,
-						 int numberOfAttributes, AttrNumber *attributeNumber,
-						 FuncIndexInfoPtr funcInfo, PredInfo *predInfo,
-						 bool unique, IndexStrategy indexStrategy);
+						 IndexInfo *indexInfo, Node *oldPred,
+						 IndexStrategy indexStrategy);
 static Oid	IndexGetRelation(Oid indexId);
 static bool activate_index(Oid indexId, bool activate);
 
+
 static bool reindexing = false;
-extern bool
+
+
+bool
 SetReindexProcessing(bool reindexmode)
 {
 	bool		old = reindexing;
@@ -87,7 +89,8 @@ SetReindexProcessing(bool reindexmode)
 	reindexing = reindexmode;
 	return old;
 }
-extern bool
+
+bool
 IsReindexProcessing(void)
 {
 	return reindexing;
@@ -154,14 +157,11 @@ GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
 }
 
 static TupleDesc
-BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
+BuildFuncTupleDesc(Oid funcOid)
 {
-	HeapTuple	tuple;
 	TupleDesc	funcTupDesc;
+	HeapTuple	tuple;
 	Oid			retType;
-	char	   *funcname;
-	int4		nargs;
-	Oid		   *argtypes;
 
 	/*
 	 * Allocate and zero a tuple descriptor.
@@ -171,30 +171,29 @@ BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
 	MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
 
 	/*
-	 * Lookup the function for the return type.
+	 * Lookup the function to get its name and return type.
 	 */
-	funcname = FIgetname(funcInfo);
-	nargs = FIgetnArgs(funcInfo);
-	argtypes = FIgetArglist(funcInfo);
-	tuple = SearchSysCacheTuple(PROCNAME,
-								PointerGetDatum(funcname),
-								Int32GetDatum(nargs),
-								PointerGetDatum(argtypes),
-								0);
-
+	tuple = SearchSysCacheTuple(PROCOID,
+								ObjectIdGetDatum(funcOid),
+								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
-		func_error("BuildFuncTupleDesc", funcname, nargs, argtypes, NULL);
-
+		elog(ERROR, "Function %u does not exist", funcOid);
 	retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
 
 	/*
-	 * Look up the return type in pg_type for the type length.
+	 * make the attributes name the same as the functions
+	 */
+	namestrcpy(&funcTupDesc->attrs[0]->attname,
+			   NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));
+
+	/*
+	 * Lookup the return type in pg_type for the type length etc.
 	 */
 	tuple = SearchSysCacheTuple(TYPEOID,
 								ObjectIdGetDatum(retType),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "Function %s return type does not exist", FIgetname(funcInfo));
+		elog(ERROR, "Type %u does not exist", retType);
 
 	/*
 	 * Assign some of the attributes values. Leave the rest as 0.
@@ -208,57 +207,48 @@ BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
 	funcTupDesc->attrs[0]->attstorage = 'p';
 	funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
 
-	/*
-	 * make the attributes name the same as the functions
-	 */
-	namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
-
 	return funcTupDesc;
 }
 
 /* ----------------------------------------------------------------
  *		ConstructTupleDescriptor
+ *
+ * Build an index tuple descriptor for a new index (plain not functional)
  * ----------------------------------------------------------------
  */
 static TupleDesc
 ConstructTupleDescriptor(Oid heapoid,
 						 Relation heapRelation,
-						 List *attributeList,
 						 int numatts,
 						 AttrNumber *attNums)
 {
 	TupleDesc	heapTupDesc;
 	TupleDesc	indexTupDesc;
-	IndexElem  *IndexKey;
-	TypeName   *IndexKeyType;
-	AttrNumber	atnum;			/* attributeNumber[attributeOffset] */
-	AttrNumber	atind;
-	int			natts;			/* Form_pg_class->relnatts */
-	char	   *from;			/* used to simplify memcpy below */
-	char	   *to;				/* used to simplify memcpy below */
+	int			natts;			/* #atts in heap rel --- for error checks */
 	int			i;
 
+	heapTupDesc = RelationGetDescr(heapRelation);
+	natts = RelationGetForm(heapRelation)->relnatts;
+
 	/* ----------------
 	 *	allocate the new tuple descriptor
 	 * ----------------
 	 */
-	natts = RelationGetForm(heapRelation)->relnatts;
 
 	indexTupDesc = CreateTemplateTupleDesc(numatts);
 
-	/* ----------------
-	 *
-	 * ----------------
-	 */
-
 	/* ----------------
 	 *	  for each attribute we are indexing, obtain its attribute
 	 *	  tuple form from either the static table of system attribute
 	 *	  tuple forms or the relation tuple descriptor
 	 * ----------------
 	 */
-	for (i = 0; i < numatts; i += 1)
+	for (i = 0; i < numatts; i++)
 	{
+		AttrNumber	atnum;		/* attributeNumber[attributeOffset] */
+		AttrNumber	atind;
+		char	   *from;		/* used to simplify memcpy below */
+		char	   *to;			/* used to simplify memcpy below */
 
 		/* ----------------
 		 *	 get the attribute number and make sure it's valid
@@ -268,16 +258,9 @@ ConstructTupleDescriptor(Oid heapoid,
 		if (atnum > natts)
 			elog(ERROR, "Cannot create index: attribute %d does not exist",
 				 atnum);
-		if (attributeList)
-		{
-			IndexKey = (IndexElem *) lfirst(attributeList);
-			IndexKeyType = IndexKey->typename;
-			attributeList = lnext(attributeList);
-		}
-		else
-			IndexKeyType = NULL;
 
-		indexTupDesc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
+		indexTupDesc->attrs[i] =
+			(Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
 
 		/* ----------------
 		 *	 determine which tuple descriptor to copy
@@ -285,10 +268,9 @@ ConstructTupleDescriptor(Oid heapoid,
 		 */
 		if (!AttrNumberIsForUserDefinedAttr(atnum))
 		{
-
 			/* ----------------
-			 *	  here we are indexing on a system attribute (-1...-12)
-			 *	  so we convert atnum into a usable index 0...11 so we can
+			 *	  here we are indexing on a system attribute (-1...-n)
+			 *	  so we convert atnum into a usable index 0...n-1 so we can
 			 *	  use it to dereference the array sysatts[] which stores
 			 *	  tuple descriptor information for system attributes.
 			 * ----------------
@@ -298,7 +280,6 @@ ConstructTupleDescriptor(Oid heapoid,
 			atind = (-atnum) - 1;
 
 			from = (char *) (&sysatts[atind]);
-
 		}
 		else
 		{
@@ -306,7 +287,6 @@ ConstructTupleDescriptor(Oid heapoid,
 			 *	  here we are indexing on a normal attribute (1...n)
 			 * ----------------
 			 */
-			heapTupDesc = RelationGetDescr(heapRelation);
 			atind = AttrNumberGetAttrOffset(atnum);
 
 			from = (char *) (heapTupDesc->attrs[atind]);
@@ -317,43 +297,18 @@ ConstructTupleDescriptor(Oid heapoid,
 		 *	 the tuple desc data...
 		 * ----------------
 		 */
-
 		to = (char *) (indexTupDesc->attrs[i]);
 		memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
 
+		/*
+		 * Fix the stuff that should not be the same as the underlying attr
+		 */
 		((Form_pg_attribute) to)->attnum = i + 1;
 
+		((Form_pg_attribute) to)->attdisbursion = 0.0;
 		((Form_pg_attribute) to)->attnotnull = false;
 		((Form_pg_attribute) to)->atthasdef = false;
 		((Form_pg_attribute) to)->attcacheoff = -1;
-		((Form_pg_attribute) to)->atttypmod = -1;
-		((Form_pg_attribute) to)->attalign = 'i';
-
-		/*
-		 * if the keytype is defined, we need to change the tuple form's
-		 * atttypid & attlen field to match that of the key's type
-		 */
-		if (IndexKeyType != NULL)
-		{
-			HeapTuple	tup;
-
-			tup = SearchSysCacheTuple(TYPENAME,
-									  PointerGetDatum(IndexKeyType->name),
-									  0, 0, 0);
-			if (!HeapTupleIsValid(tup))
-				elog(ERROR, "create index: type '%s' undefined",
-					 IndexKeyType->name);
-			((Form_pg_attribute) to)->atttypid = tup->t_data->t_oid;
-			((Form_pg_attribute) to)->attbyval =
-				((Form_pg_type) GETSTRUCT(tup))->typbyval;
-			((Form_pg_attribute) to)->attlen =
-				((Form_pg_type) GETSTRUCT(tup))->typlen;
-			((Form_pg_attribute) to)->attstorage = 'p';
-			((Form_pg_attribute) to)->attalign =
-				((Form_pg_type) GETSTRUCT(tup))->typalign;
-			((Form_pg_attribute) to)->atttypmod = IndexKeyType->typmod;
-		}
-
 
 		/* ----------------
 		 *	  now we have to drop in the proper relation descriptor
@@ -539,17 +494,14 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
 				new_tuple;
 	bool		hasind;
 	Relation	idescs[Num_pg_attr_indices];
-
 	Datum		value[Natts_pg_attribute];
 	char		nullv[Natts_pg_attribute];
 	char		replace[Natts_pg_attribute];
-
 	TupleDesc	indexTupDesc;
 	int			i;
 
 	/* ----------------
 	 *	open the attribute relation
-	 *	XXX ADD INDEXING
 	 * ----------------
 	 */
 	pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
@@ -641,7 +593,6 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
 	heap_close(pg_attribute, RowExclusiveLock);
 	if (hasind)
 		CatalogCloseIndices(Num_pg_attr_indices, idescs);
-
 }
 
 /* ----------------------------------------------------------------
@@ -651,18 +602,12 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
 static void
 UpdateIndexRelation(Oid indexoid,
 					Oid heapoid,
-					FuncIndexInfo *funcInfo,
-					int natts,
-					AttrNumber *attNums,
+					IndexInfo *indexInfo,
 					Oid *classOids,
-					Node *predicate,
-					List *attributeList,
 					bool islossy,
-					bool unique,
 					bool primary)
 {
 	Form_pg_index indexForm;
-	IndexElem  *IndexKey;
 	char	   *predString;
 	text	   *predText;
 	int			predLen,
@@ -673,13 +618,13 @@ UpdateIndexRelation(Oid indexoid,
 	Relation	idescs[Num_pg_index_indices];
 
 	/* ----------------
-	 *	allocate an Form_pg_index big enough to hold the
+	 *	allocate a Form_pg_index big enough to hold the
 	 *	index-predicate (if any) in string form
 	 * ----------------
 	 */
-	if (predicate != NULL)
+	if (indexInfo->ii_Predicate != NULL)
 	{
-		predString = nodeToString(predicate);
+		predString = nodeToString(indexInfo->ii_Predicate);
 		predText = DatumGetTextP(DirectFunctionCall1(textin,
 											CStringGetDatum(predString)));
 		pfree(predString);
@@ -691,57 +636,33 @@ UpdateIndexRelation(Oid indexoid,
 	predLen = VARSIZE(predText);
 	itupLen = predLen + sizeof(FormData_pg_index);
 	indexForm = (Form_pg_index) palloc(itupLen);
-	memset(indexForm, 0, sizeof(FormData_pg_index));
-
-	memmove((char *) &indexForm->indpred, (char *) predText, predLen);
+	MemSet(indexForm, 0, sizeof(FormData_pg_index));
 
 	/* ----------------
-	 *	store the oid information into the index tuple form
+	 *	store information into the index tuple form
 	 * ----------------
 	 */
-	indexForm->indrelid = heapoid;
 	indexForm->indexrelid = indexoid;
-	indexForm->indproc = (PointerIsValid(funcInfo)) ?
-		FIgetProcOid(funcInfo) : InvalidOid;
+	indexForm->indrelid = heapoid;
+	indexForm->indproc = indexInfo->ii_FuncOid;
+	indexForm->indisclustered = false;
 	indexForm->indislossy = islossy;
+	indexForm->indhaskeytype = true; /* not actually used anymore */
+	indexForm->indisunique = indexInfo->ii_Unique;
 	indexForm->indisprimary = primary;
-	indexForm->indisunique = unique;
-
-	indexForm->indhaskeytype = 0;
-	while (attributeList != NIL)
-	{
-		IndexKey = (IndexElem *) lfirst(attributeList);
-		if (IndexKey->typename != NULL)
-		{
-			indexForm->indhaskeytype = 1;
-			break;
-		}
-		attributeList = lnext(attributeList);
-	}
-
-	MemSet((char *) &indexForm->indkey[0], 0, sizeof indexForm->indkey);
-	MemSet((char *) &indexForm->indclass[0], 0, sizeof indexForm->indclass);
+	memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
 
 	/* ----------------
 	 *	copy index key and op class information
+	 *
+	 *	We zeroed the extra slots (if any) above --- that's essential.
 	 * ----------------
 	 */
-	for (i = 0; i < natts; i += 1)
-	{
-		indexForm->indkey[i] = attNums[i];
-		indexForm->indclass[i] = classOids[i];
-	}
-
-	/*
-	 * If we have a functional index, add all attribute arguments
-	 */
-	if (PointerIsValid(funcInfo))
-	{
-		for (i = 1; i < FIgetnArgs(funcInfo); i++)
-			indexForm->indkey[i] = attNums[i];
-	}
+	for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
+		indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
 
-	indexForm->indisclustered = '\0';	/* XXX constant */
+	for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+		indexForm->indclass[i] = classOids[i];
 
 	/* ----------------
 	 *	open the system catalog index relation
@@ -759,13 +680,12 @@ UpdateIndexRelation(Oid indexoid,
 
 	/* ----------------
 	 *	insert the tuple into the pg_index
-	 *	XXX ADD INDEX TUPLES TOO
 	 * ----------------
 	 */
 	heap_insert(pg_index, tuple);
 
 	/* ----------------
-	 *	insert the index tuple into the pg_index
+	 *	add index tuples for it
 	 * ----------------
 	 */
 	if (!IsIgnoringSystemIndexes())
@@ -774,6 +694,7 @@ UpdateIndexRelation(Oid indexoid,
 		CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
 		CatalogCloseIndices(Num_pg_index_indices, idescs);
 	}
+
 	/* ----------------
 	 *	close the relation and free the tuple
 	 * ----------------
@@ -923,6 +844,7 @@ InitIndexStrategy(int numatts,
 	CommandCounterIncrement();
 
 	IndexSupportInitialize(strategy, support,
+						   &indexRelation->rd_uniqueindex,
 						   attrelid, accessMethodObjectId,
 						   amstrategies, amsupport, numatts);
 
@@ -941,15 +863,10 @@ InitIndexStrategy(int numatts,
 void
 index_create(char *heapRelationName,
 			 char *indexRelationName,
-			 FuncIndexInfo *funcInfo,
-			 List *attributeList,
+			 IndexInfo *indexInfo,
 			 Oid accessMethodObjectId,
-			 int numatts,
-			 AttrNumber *attNums,
 			 Oid *classObjectId,
-			 Node *predicate,
 			 bool islossy,
-			 bool unique,
 			 bool primary,
 			 bool allow_system_table_mods)
 {
@@ -958,16 +875,17 @@ index_create(char *heapRelationName,
 	TupleDesc	indexTupDesc;
 	Oid			heapoid;
 	Oid			indexoid;
-	PredInfo   *predInfo;
 	bool		istemp = (get_temp_rel_by_username(heapRelationName) != NULL);
 	char	   *temp_relname = NULL;
 
+	SetReindexProcessing(false);
+
 	/* ----------------
 	 *	check parameters
 	 * ----------------
 	 */
-	SetReindexProcessing(false);
-	if (numatts < 1)
+	if (indexInfo->ii_NumIndexAttrs < 1 ||
+		indexInfo->ii_NumKeyAttrs < 1)
 		elog(ERROR, "must index at least one attribute");
 
 	/* ----------------
@@ -985,14 +903,13 @@ index_create(char *heapRelationName,
 	 *	  construct new tuple descriptor
 	 * ----------------
 	 */
-	if (PointerIsValid(funcInfo))
-		indexTupDesc = BuildFuncTupleDesc(funcInfo);
+	if (OidIsValid(indexInfo->ii_FuncOid))
+		indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
 	else
 		indexTupDesc = ConstructTupleDescriptor(heapoid,
 												heapRelation,
-												attributeList,
-												numatts,
-												attNums);
+												indexInfo->ii_NumKeyAttrs,
+												indexInfo->ii_KeyAttrNumbers);
 
 	if (istemp)
 	{
@@ -1035,13 +952,15 @@ index_create(char *heapRelationName,
 	 *	tuple forms in the index relation's tuple descriptor
 	 * ----------------
 	 */
-	InitializeAttributeOids(indexRelation, numatts, indexoid);
+	InitializeAttributeOids(indexRelation,
+							indexInfo->ii_NumIndexAttrs,
+							indexoid);
 
 	/* ----------------
-	 *	  append ATTRIBUTE tuples
+	 *	  append ATTRIBUTE tuples for the index
 	 * ----------------
 	 */
-	AppendAttributeTuples(indexRelation, numatts);
+	AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
 
 	/* ----------------
 	 *	  update pg_index
@@ -1051,19 +970,16 @@ index_create(char *heapRelationName,
 	 *	  (Or, could define a rule to maintain the predicate) --Nels, Feb '92
 	 * ----------------
 	 */
-	UpdateIndexRelation(indexoid, heapoid, funcInfo,
-						numatts, attNums, classObjectId, predicate,
-						attributeList, islossy, unique, primary);
-
-	predInfo = (PredInfo *) palloc(sizeof(PredInfo));
-	predInfo->pred = predicate;
-	predInfo->oldPred = NULL;
+	UpdateIndexRelation(indexoid, heapoid, indexInfo,
+						classObjectId, islossy, primary);
 
 	/* ----------------
 	 *	  initialize the index strategy
 	 * ----------------
 	 */
-	InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
+	InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
+					  indexRelation,
+					  accessMethodObjectId);
 
 	/*
 	 * If this is bootstrap (initdb) time, then we don't actually fill in
@@ -1078,14 +994,12 @@ index_create(char *heapRelationName,
 	 */
 	if (IsBootstrapProcessingMode())
 	{
-		index_register(heapRelationName, indexRelationName, numatts, attNums,
-					   funcInfo, predInfo, unique);
+		index_register(heapRelationName, indexRelationName, indexInfo);
 		/* XXX shouldn't we close the heap and index rels here? */
 	}
 	else
 	{
-		index_build(heapRelation, indexRelation, numatts, attNums,
-					funcInfo, predInfo, unique);
+		index_build(heapRelation, indexRelation, indexInfo, NULL);
 	}
 }
 
@@ -1238,43 +1152,163 @@ index_drop(Oid indexId)
  *						index_build support
  * ----------------------------------------------------------------
  */
+
+/* ----------------
+ *		BuildIndexInfo
+ *			Construct an IndexInfo record given the index's pg_index tuple
+ *
+ * IndexInfo stores the information about the index that's needed by
+ * FormIndexDatum, which is used for both index_build() and later insertion
+ * of individual index tuples.  Normally we build an IndexInfo for an index
+ * just once per command, and then use it for (potentially) many tuples.
+ * ----------------
+ */
+IndexInfo *
+BuildIndexInfo(HeapTuple indexTuple)
+{
+	Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
+	IndexInfo  *ii = makeNode(IndexInfo);
+	int			i;
+	int			numKeys;
+
+	/* ----------------
+	 *	count the number of keys, and copy them into the IndexInfo
+	 * ----------------
+	 */
+	numKeys = 0;
+	for (i = 0; i < INDEX_MAX_KEYS &&
+		 indexStruct->indkey[i] != InvalidAttrNumber; i++)
+	{
+		ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i];
+		numKeys++;
+	}
+	ii->ii_NumKeyAttrs = numKeys;
+
+	/* ----------------
+	 *	Handle functional index.
+	 *
+	 *	If we have a functional index then the number of
+	 *	attributes defined in the index must be 1 (the function's
+	 *	single return value).  Otherwise it's same as number of keys.
+	 * ----------------
+	 */
+	ii->ii_FuncOid = indexStruct->indproc;
+
+	if (OidIsValid(indexStruct->indproc))
+	{
+		ii->ii_NumIndexAttrs = 1;
+		/* Do a lookup on the function, too */
+		fmgr_info(indexStruct->indproc, & ii->ii_FuncInfo);
+	}
+	else
+		ii->ii_NumIndexAttrs = numKeys;
+
+	/* ----------------
+	 *	If partial index, convert predicate into expression nodetree
+	 * ----------------
+	 */
+	if (VARSIZE(&indexStruct->indpred) != 0)
+	{
+		char	   *predString;
+
+		predString = DatumGetCString(DirectFunctionCall1(textout,
+									 PointerGetDatum(&indexStruct->indpred)));
+		ii->ii_Predicate = stringToNode(predString);
+		pfree(predString);
+	}
+	else
+		ii->ii_Predicate = NULL;
+
+	/* Other info */
+	ii->ii_Unique = indexStruct->indisunique;
+
+	return ii;
+}
+
 /* ----------------
  *		FormIndexDatum
+ *			Construct Datum[] and nullv[] arrays for a new index tuple.
+ *
+ *	indexInfo		Info about the index
+ *	heapTuple		Heap tuple for which we must prepare an index entry
+ *	heapDescriptor	tupledesc for heap tuple
+ *	resultCxt		Temporary memory context for any palloc'd datums created
+ *	datum			Array of index Datums (output area)
+ *	nullv			Array of is-null indicators (output area)
+ *
+ * For largely historical reasons, we don't actually call index_formtuple()
+ * here, we just prepare its input arrays datum[] and nullv[].
  * ----------------
  */
 void
-FormIndexDatum(int numberOfAttributes,
-			   AttrNumber *attributeNumber,
+FormIndexDatum(IndexInfo *indexInfo,
 			   HeapTuple heapTuple,
 			   TupleDesc heapDescriptor,
+			   MemoryContext resultCxt,
 			   Datum *datum,
-			   char *nullv,
-			   FuncIndexInfoPtr fInfo)
+			   char *nullv)
 {
-	AttrNumber	i;
-	int			offset;
+	MemoryContext oldContext;
+	int			i;
+	Datum		iDatum;
 	bool		isNull;
 
-	/* ----------------
-	 *	for each attribute we need from the heap tuple,
-	 *	get the attribute and stick it into the datum and
-	 *	null arrays.
-	 * ----------------
-	 */
+	oldContext = MemoryContextSwitchTo(resultCxt);
 
-	for (i = 1; i <= numberOfAttributes; i++)
+	if (OidIsValid(indexInfo->ii_FuncOid))
 	{
-		offset = AttrNumberGetAttrOffset(i);
+		/* ----------------
+		 *	Functional index --- compute the single index attribute
+		 * ----------------
+		 */
+		FunctionCallInfoData	fcinfo;
+		bool					anynull = false;
 
-		datum[offset] = PointerGetDatum(GetIndexValue(heapTuple,
-													  heapDescriptor,
-													  offset,
-													  attributeNumber,
-													  fInfo,
-													  &isNull));
+		MemSet(&fcinfo, 0, sizeof(fcinfo));
+		fcinfo.flinfo = &indexInfo->ii_FuncInfo;
+		fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
 
-		nullv[offset] = (isNull) ? 'n' : ' ';
+		for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
+		{
+			fcinfo.arg[i] = heap_getattr(heapTuple,
+										 indexInfo->ii_KeyAttrNumbers[i],
+										 heapDescriptor,
+										 &fcinfo.argnull[i]);
+			anynull |= fcinfo.argnull[i];
+		}
+		if (indexInfo->ii_FuncInfo.fn_strict && anynull)
+		{
+			/* force a null result for strict function */
+			iDatum = (Datum) 0;
+			isNull = true;
+		}
+		else
+		{
+			iDatum = FunctionCallInvoke(&fcinfo);
+			isNull = fcinfo.isnull;
+		}
+		datum[0] = iDatum;
+		nullv[0] = (isNull) ? 'n' : ' ';
+	}
+	else
+	{
+		/* ----------------
+		 *	Plain index --- for each attribute we need from the heap tuple,
+		 *	get the attribute and stick it into the datum and nullv arrays.
+		 * ----------------
+		 */
+		for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+		{
+			iDatum = heap_getattr(heapTuple,
+								  indexInfo->ii_KeyAttrNumbers[i],
+								  heapDescriptor,
+								  &isNull);
+			datum[i] = iDatum;
+			nullv[i] = (isNull) ? 'n' : ' ';
+		}
 	}
+
+	MemoryContextSwitchTo(oldContext);
 }
 
 
@@ -1282,9 +1316,9 @@ FormIndexDatum(int numberOfAttributes,
  *		Lock class info for update
  * --------------------------------------------
  */
-static
-bool
-LockClassinfoForUpdate(Oid relid, HeapTuple rtup, Buffer *buffer, bool confirmCommitted)
+static bool
+LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
+					   Buffer *buffer, bool confirmCommitted)
 {
 	HeapTuple	classTuple;
 	Form_pg_class pgcform;
@@ -1429,7 +1463,7 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
 
 	/*
 	 * Confirm that target tuple is locked by this transaction in case of
-	 * immedaite updation.
+	 * immediate updation.
 	 */
 	if (immediate)
 	{
@@ -1682,32 +1716,23 @@ UpdateStats(Oid relid, long reltuples, bool inplace)
 static void
 DefaultBuild(Relation heapRelation,
 			 Relation indexRelation,
-			 int numberOfAttributes,
-			 AttrNumber *attributeNumber,
-			 FuncIndexInfoPtr funcInfo,
-			 PredInfo *predInfo,
-			 bool unique,		/* not used */
+			 IndexInfo *indexInfo,
+			 Node *oldPred,
 			 IndexStrategy indexStrategy) /* not used */
 {
 	HeapScanDesc scan;
 	HeapTuple	heapTuple;
-	IndexTuple	indexTuple;
 	TupleDesc	heapDescriptor;
-	TupleDesc	indexDescriptor;
-	Datum	   *datum;
-	char	   *nullv;
+	Datum		datum[INDEX_MAX_KEYS];
+	char		nullv[INDEX_MAX_KEYS];
 	long		reltuples,
 				indtuples;
-
+	Node	   *predicate = indexInfo->ii_Predicate;
 #ifndef OMIT_PARTIAL_INDEX
-	ExprContext *econtext;
 	TupleTable	tupleTable;
 	TupleTableSlot *slot;
-
 #endif
-	Node	   *predicate;
-	Node	   *oldPred;
-
+	ExprContext *econtext;
 	InsertIndexResult insertResult;
 
 	/* ----------------
@@ -1716,48 +1741,33 @@ DefaultBuild(Relation heapRelation,
 	 */
 	Assert(OidIsValid(indexRelation->rd_rel->relam));	/* XXX */
 
-	/* ----------------
-	 *	get the tuple descriptors from the relations so we know
-	 *	how to form the index tuples..
-	 * ----------------
-	 */
 	heapDescriptor = RelationGetDescr(heapRelation);
-	indexDescriptor = RelationGetDescr(indexRelation);
-
-	/* ----------------
-	 *	datum and null are arrays in which we collect the index attributes
-	 *	when forming a new index tuple.
-	 * ----------------
-	 */
-	datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
-	nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
 
 	/*
 	 * If this is a predicate (partial) index, we will need to evaluate
 	 * the predicate using ExecQual, which requires the current tuple to
 	 * be in a slot of a TupleTable.  In addition, ExecQual must have an
 	 * ExprContext referring to that slot.	Here, we initialize dummy
-	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb
-	 * '92
+	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
+	 *
+	 * We construct the ExprContext anyway since we need a per-tuple
+	 * temporary memory context for function evaluation -- tgl July 00
 	 */
-
-	predicate = predInfo->pred;
-	oldPred = predInfo->oldPred;
-
 #ifndef OMIT_PARTIAL_INDEX
 	if (predicate != NULL || oldPred != NULL)
 	{
 		tupleTable = ExecCreateTupleTable(1);
 		slot = ExecAllocTableSlot(tupleTable);
 		ExecSetSlotDescriptor(slot, heapDescriptor);
-		econtext = MakeExprContext(slot, TransactionCommandContext);
 	}
 	else
 	{
 		tupleTable = NULL;
 		slot = NULL;
-		econtext = NULL;
 	}
+	econtext = MakeExprContext(slot, TransactionCommandContext);
+#else
+	econtext = MakeExprContext(NULL, TransactionCommandContext);
 #endif	 /* OMIT_PARTIAL_INDEX */
 
 	/* ----------------
@@ -1781,6 +1791,8 @@ DefaultBuild(Relation heapRelation,
 	 */
 	while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
 	{
+		MemoryContextReset(econtext->ecxt_per_tuple_memory);
+
 		reltuples++;
 
 #ifndef OMIT_PARTIAL_INDEX
@@ -1790,7 +1802,6 @@ DefaultBuild(Relation heapRelation,
 		 */
 		if (oldPred != NULL)
 		{
-			/* SetSlotContents(slot, heapTuple); */
 			slot->val = heapTuple;
 			if (ExecQual((List *) oldPred, econtext, false))
 			{
@@ -1805,7 +1816,6 @@ DefaultBuild(Relation heapRelation,
 		 */
 		if (predicate != NULL)
 		{
-			/* SetSlotContents(slot, heapTuple); */
 			slot->val = heapTuple;
 			if (!ExecQual((List *) predicate, econtext, false))
 				continue;
@@ -1819,26 +1829,18 @@ DefaultBuild(Relation heapRelation,
 		 *	with attribute information taken from the given heap tuple.
 		 * ----------------
 		 */
-		FormIndexDatum(numberOfAttributes,		/* num attributes */
-					   attributeNumber, /* array of att nums to extract */
-					   heapTuple,		/* tuple from base relation */
-					   heapDescriptor,	/* heap tuple's descriptor */
-					   datum,	/* return: array of attributes */
-					   nullv,	/* return: array of char's */
-					   funcInfo);
-
-		indexTuple = index_formtuple(indexDescriptor,
-									 datum,
-									 nullv);
-
-		indexTuple->t_tid = heapTuple->t_self;
+		FormIndexDatum(indexInfo,
+					   heapTuple,
+					   heapDescriptor,
+					   econtext->ecxt_per_tuple_memory,
+					   datum,
+					   nullv);
 
 		insertResult = index_insert(indexRelation, datum, nullv,
 									&(heapTuple->t_self), heapRelation);
 
 		if (insertResult)
 			pfree(insertResult);
-		pfree(indexTuple);
 	}
 
 	heap_endscan(scan);
@@ -1846,14 +1848,10 @@ DefaultBuild(Relation heapRelation,
 #ifndef OMIT_PARTIAL_INDEX
 	if (predicate != NULL || oldPred != NULL)
 	{
-		/* parameter was 'false', almost certainly wrong --- tgl 9/21/99 */
 		ExecDropTupleTable(tupleTable, true);
-		FreeExprContext(econtext);
 	}
 #endif	 /* OMIT_PARTIAL_INDEX */
-
-	pfree(nullv);
-	pfree(datum);
+	FreeExprContext(econtext);
 
 	/*
 	 * Since we just counted the tuples in the heap, we update its stats
@@ -1893,11 +1891,8 @@ DefaultBuild(Relation heapRelation,
 void
 index_build(Relation heapRelation,
 			Relation indexRelation,
-			int numberOfAttributes,
-			AttrNumber *attributeNumber,
-			FuncIndexInfo *funcInfo,
-			PredInfo *predInfo,
-			bool unique)
+			IndexInfo *indexInfo,
+			Node *oldPred)
 {
 	RegProcedure procedure;
 
@@ -1915,23 +1910,17 @@ index_build(Relation heapRelation,
 	 * ----------------
 	 */
 	if (RegProcedureIsValid(procedure))
-		OidFunctionCall8(procedure,
+		OidFunctionCall5(procedure,
 						 PointerGetDatum(heapRelation),
 						 PointerGetDatum(indexRelation),
-						 Int32GetDatum(numberOfAttributes),
-						 PointerGetDatum(attributeNumber),
-						 PointerGetDatum(funcInfo),
-						 PointerGetDatum(predInfo),
-						 BoolGetDatum(unique),
+						 PointerGetDatum(indexInfo),
+						 PointerGetDatum(oldPred),
 						 PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
 	else
 		DefaultBuild(heapRelation,
 					 indexRelation,
-					 numberOfAttributes,
-					 attributeNumber,
-					 funcInfo,
-					 predInfo,
-					 unique,
+					 indexInfo,
+					 oldPred,
 					 RelationGetIndexStrategy(indexRelation));
 }
 
@@ -1959,34 +1948,9 @@ IndexGetRelation(Oid indexId)
 	return index->indrelid;
 }
 
-/*
- * IndexIsUnique: given an index's relation OID, see if it
- * is unique using the system cache.
- */
-bool
-IndexIsUnique(Oid indexId)
-{
-	HeapTuple	tuple;
-	Form_pg_index index;
-
-	tuple = SearchSysCacheTuple(INDEXRELID,
-								ObjectIdGetDatum(indexId),
-								0, 0, 0);
-	if (!HeapTupleIsValid(tuple))
-	{
-		elog(ERROR, "IndexIsUnique: can't find index id %u",
-			 indexId);
-	}
-	index = (Form_pg_index) GETSTRUCT(tuple);
-	Assert(index->indexrelid == indexId);
-
-	return index->indisunique;
-}
-
-
 /* ---------------------------------
  * activate_index -- activate/deactivate the specified index.
- *		Note that currelntly PostgreSQL doesn't hold the
+ *		Note that currently PostgreSQL doesn't hold the
  *		status per index
  * ---------------------------------
  */
@@ -2011,92 +1975,47 @@ reindex_index(Oid indexId, bool force)
 	ScanKeyData entry;
 	HeapScanDesc scan;
 	HeapTuple	indexTuple,
-				procTuple,
 				classTuple;
-	Form_pg_index index;
+	IndexInfo  *indexInfo;
 	Oid			heapId,
-				procId,
 				accessMethodId;
-	Node	   *oldPred = NULL;
-	PredInfo   *predInfo;
-	AttrNumber *attributeNumberA;
-	FuncIndexInfo fInfo,
-			   *funcInfo = NULL;
-	int			i,
-				numberOfAttributes;
-	bool		unique;
-	char	   *predString;
 	bool		old;
 
 	old = SetReindexProcessing(true);
-	/* Scan pg_index to find indexes on heapRelation */
+
+	/* Scan pg_index to find the index's pg_index entry */
 	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
 	ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
 						   ObjectIdGetDatum(indexId));
 	scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
 	indexTuple = heap_getnext(scan, 0);
 	if (!HeapTupleIsValid(indexTuple))
-		elog(ERROR, "reindex_index index %d tuple is invalid", indexId);
-
-	/*
-	 * For the index, fetch index attributes so we can apply index_build
-	 */
-	index = (Form_pg_index) GETSTRUCT(indexTuple);
-	heapId = index->indrelid;
-	procId = index->indproc;
-	unique = index->indisunique;
-
-	for (i = 0; i < INDEX_MAX_KEYS; i++)
-	{
-		if (index->indkey[i] == InvalidAttrNumber)
-			break;
-	}
-	numberOfAttributes = i;
+		elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
 
-	/* If a valid where predicate, compute predicate Node */
-	if (VARSIZE(&index->indpred) != 0)
-	{
-		predString = DatumGetCString(DirectFunctionCall1(textout,
-											PointerGetDatum(&index->indpred)));
-		oldPred = stringToNode(predString);
-		pfree(predString);
-	}
-	predInfo = (PredInfo *) palloc(sizeof(PredInfo));
-	predInfo->pred = (Node *) oldPred;
-	predInfo->oldPred = NULL;
+	/* Get OID of index's parent table */
+	heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
+	/* Fetch info needed for index_build */
+	indexInfo = BuildIndexInfo(indexTuple);
 
-	/* Assign Index keys to attributes array */
-	attributeNumberA = (AttrNumber *) palloc(numberOfAttributes * sizeof(AttrNumber));
-	for (i = 0; i < numberOfAttributes; i++)
-		attributeNumberA[i] = index->indkey[i];
-
-	/* If this is a procedural index, initialize our FuncIndexInfo */
-	if (procId != InvalidOid)
-	{
-		funcInfo = &fInfo;
-		FIsetnArgs(funcInfo, numberOfAttributes);
-		procTuple = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(procId),
-										0, 0, 0);
-		if (!HeapTupleIsValid(procTuple))
-			elog(ERROR, "RelationTruncateIndexes: index procedure not found");
-		namecpy(&(funcInfo->funcName),
-				&(((Form_pg_proc) GETSTRUCT(procTuple))->proname));
-		FIsetProcOid(funcInfo, procTuple->t_data->t_oid);
-	}
+	/* Complete the scan and close pg_index */
+	heap_endscan(scan);
+	heap_close(indexRelation, AccessShareLock);
 
 	/* Fetch the classTuple associated with this index */
-	classTuple = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(indexId), 0, 0, 0);
+	classTuple = SearchSysCacheTuple(RELOID,
+									 ObjectIdGetDatum(indexId),
+									 0, 0, 0);
 	if (!HeapTupleIsValid(classTuple))
-		elog(ERROR, "RelationTruncateIndexes: index access method not found");
+		elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
 	accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
 
 	/* Open our index relation */
-	iRel = index_open(indexId);
-	if (iRel == NULL)
-		elog(ERROR, "reindex_index: can't open index relation");
 	heapRelation = heap_open(heapId, ExclusiveLock);
 	if (heapRelation == NULL)
 		elog(ERROR, "reindex_index: can't open heap relation");
+	iRel = index_open(indexId);
+	if (iRel == NULL)
+		elog(ERROR, "reindex_index: can't open index relation");
 
 	/* Obtain exclusive lock on it, just to be sure */
 	LockRelation(iRel, AccessExclusiveLock);
@@ -2112,23 +2031,16 @@ reindex_index(Oid indexId, bool force)
 	iRel->rd_nblocks = 0;
 
 	/* Initialize the index and rebuild */
-	InitIndexStrategy(numberOfAttributes, iRel, accessMethodId);
-	index_build(heapRelation, iRel, numberOfAttributes,
-				attributeNumberA, funcInfo, predInfo, unique);
+	InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
+	index_build(heapRelation, iRel, indexInfo, NULL);
 
 	/*
 	 * index_build will close both the heap and index relations (but not
-	 * give up the locks we hold on them).	That's fine for the index, but
-	 * we need to open the heap again.	We need no new lock, since this
-	 * backend still has the exclusive lock grabbed by heap_truncate.
+	 * give up the locks we hold on them).  So we're done.
 	 */
-	iRel = index_open(indexId);
-	Assert(iRel != NULL);
 
-	/* Complete the scan and close pg_index */
-	heap_endscan(scan);
-	heap_close(indexRelation, AccessShareLock);
 	SetReindexProcessing(old);
+
 	return true;
 }
 
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index deb016e4a04e5e0b71a6427faf91c8a1d8252ba3..c2980f6fefc10b831206a8b18bc8d90985ec0e3b 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.66 2000/06/17 04:56:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.67 2000/07/14 22:17:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,9 +83,9 @@ static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
 
 
 /*
- * Changes (appends) to catalogs can (and does) happen at various places
+ * Changes (appends) to catalogs can and do happen at various places
  * throughout the code.  We need a generic routine that will open all of
- * the indices defined on a given catalog a return the relation descriptors
+ * the indices defined on a given catalog and return the relation descriptors
  * associated with them.
  */
 void
@@ -115,9 +115,20 @@ CatalogCloseIndices(int nIndices, Relation *idescs)
 
 
 /*
- * For the same reasons outlined above CatalogOpenIndices() we need a routine
- * that takes a new catalog tuple and inserts an associated index tuple into
- * each catalog index.
+ * For the same reasons outlined above for CatalogOpenIndices(), we need a
+ * routine that takes a new catalog tuple and inserts an associated index
+ * tuple into each catalog index.
+ *
+ * NOTE: since this routine looks up all the pg_index data on each call,
+ * it's relatively inefficient for inserting a large number of tuples into
+ * the same catalog.  We use it only for inserting one or a few tuples
+ * in a given command.  See ExecOpenIndices() and related routines if you
+ * are inserting tuples in bulk.
+ *
+ * NOTE: we do not bother to handle partial indices.  Nor do we try to
+ * be efficient for functional indices (the code should work for them,
+ * but may leak memory intraquery).  This should be OK for system catalogs,
+ * but don't use this routine for user tables!
  */
 void
 CatalogIndexInsert(Relation *idescs,
@@ -125,15 +136,9 @@ CatalogIndexInsert(Relation *idescs,
 				   Relation heapRelation,
 				   HeapTuple heapTuple)
 {
-	HeapTuple	index_tup;
 	TupleDesc	heapDescriptor;
-	Form_pg_index index_form;
 	Datum		datum[INDEX_MAX_KEYS];
-	char		nulls[INDEX_MAX_KEYS];
-	int			natts;
-	AttrNumber *attnumP;
-	FuncIndexInfo finfo,
-			   *finfoP;
+	char		nullv[INDEX_MAX_KEYS];
 	int			i;
 
 	if (IsIgnoringSystemIndexes())
@@ -142,51 +147,30 @@ CatalogIndexInsert(Relation *idescs,
 
 	for (i = 0; i < nIndices; i++)
 	{
+		HeapTuple	index_tup;
+		IndexInfo  *indexInfo;
 		InsertIndexResult indexRes;
 
-		index_tup = SearchSysCacheTupleCopy(INDEXRELID,
-									  ObjectIdGetDatum(idescs[i]->rd_id),
-											0, 0, 0);
-		Assert(index_tup);
-		index_form = (Form_pg_index) GETSTRUCT(index_tup);
-
-		if (index_form->indproc != InvalidOid)
-		{
-			int			fatts;
-
-			/*
-			 * Compute the number of attributes we are indexing upon.
-			 */
-			for (attnumP = index_form->indkey, fatts = 0;
-				 fatts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
-				 attnumP++, fatts++)
-				;
-			FIgetnArgs(&finfo) = fatts;
-			natts = 1;
-			FIgetProcOid(&finfo) = index_form->indproc;
-			*(FIgetname(&finfo)) = '\0';
-			finfoP = &finfo;
-		}
-		else
-		{
-			natts = RelationGetDescr(idescs[i])->natts;
-			finfoP = (FuncIndexInfo *) NULL;
-		}
+		index_tup = SearchSysCacheTuple(INDEXRELID,
+										ObjectIdGetDatum(idescs[i]->rd_id),
+										0, 0, 0);
+		if (!HeapTupleIsValid(index_tup))
+			elog(ERROR, "CatalogIndexInsert: index %u not found",
+				 idescs[i]->rd_id);
+		indexInfo = BuildIndexInfo(index_tup);
 
-		FormIndexDatum(natts,
-					   (AttrNumber *) index_form->indkey,
+		FormIndexDatum(indexInfo,
 					   heapTuple,
 					   heapDescriptor,
+					   CurrentMemoryContext,
 					   datum,
-					   nulls,
-					   finfoP);
+					   nullv);
 
-		indexRes = index_insert(idescs[i], datum, nulls,
+		indexRes = index_insert(idescs[i], datum, nullv,
 								&heapTuple->t_self, heapRelation);
 		if (indexRes)
 			pfree(indexRes);
-
-		heap_freetuple(index_tup);
+		pfree(indexInfo);
 	}
 }
 
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 38539707cd8154f0028bc780c560bb62137f9b6a..5c176254d665cfe09877708145d6649dd57615d1 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.57 2000/07/04 06:11:27 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.58 2000/07/14 22:17:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -198,35 +198,31 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
 	Relation	OldIndex,
 				NewHeap;
 	HeapTuple	Old_pg_index_Tuple,
-				Old_pg_index_relation_Tuple,
-				pg_proc_Tuple;
+				Old_pg_index_relation_Tuple;
 	Form_pg_index Old_pg_index_Form;
 	Form_pg_class Old_pg_index_relation_Form;
-	Form_pg_proc pg_proc_Form;
+	IndexInfo  *indexInfo;
 	char	   *NewIndexName;
-	AttrNumber *attnumP;
-	int			natts;
-	FuncIndexInfo *finfo;
 
 	NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
 	OldIndex = index_open(OIDOldIndex);
 
 	/*
 	 * OK. Create a new (temporary) index for the one that's already here.
-	 * To do this I get the info from pg_index, re-build the FunctInfo if
-	 * I have to, and add a new index with a temporary name.
+	 * To do this I get the info from pg_index, and add a new index with
+	 * a temporary name.
 	 */
-	Old_pg_index_Tuple = SearchSysCacheTuple(INDEXRELID,
+	Old_pg_index_Tuple = SearchSysCacheTupleCopy(INDEXRELID,
 							ObjectIdGetDatum(RelationGetRelid(OldIndex)),
-											 0, 0, 0);
-
+												 0, 0, 0);
 	Assert(Old_pg_index_Tuple);
 	Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple);
 
-	Old_pg_index_relation_Tuple = SearchSysCacheTuple(RELOID,
-							ObjectIdGetDatum(RelationGetRelid(OldIndex)),
-													  0, 0, 0);
+	indexInfo = BuildIndexInfo(Old_pg_index_Tuple);
 
+	Old_pg_index_relation_Tuple = SearchSysCacheTupleCopy(RELOID,
+							ObjectIdGetDatum(RelationGetRelid(OldIndex)),
+														  0, 0, 0);
 	Assert(Old_pg_index_relation_Tuple);
 	Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
 
@@ -234,50 +230,12 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
 	NewIndexName = palloc(NAMEDATALEN); /* XXX */
 	snprintf(NewIndexName, NAMEDATALEN, "temp_%x", OIDOldIndex);
 
-	/*
-	 * Ugly as it is, the only way I have of working out the number of
-	 * attribues is to count them. Mostly there'll be just one but I've
-	 * got to be sure.
-	 */
-	for (attnumP = &(Old_pg_index_Form->indkey[0]), natts = 0;
-		 natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
-		 attnumP++, natts++);
-
-	/*
-	 * If this is a functional index, I need to rebuild the functional
-	 * component to pass it to the defining procedure.
-	 */
-	if (Old_pg_index_Form->indproc != InvalidOid)
-	{
-		finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
-		FIgetnArgs(finfo) = natts;
-		FIgetProcOid(finfo) = Old_pg_index_Form->indproc;
-
-		pg_proc_Tuple = SearchSysCacheTuple(PROCOID,
-							ObjectIdGetDatum(Old_pg_index_Form->indproc),
-											0, 0, 0);
-
-		Assert(pg_proc_Tuple);
-		pg_proc_Form = (Form_pg_proc) GETSTRUCT(pg_proc_Tuple);
-		namecpy(&(finfo->funcName), &(pg_proc_Form->proname));
-		natts = 1;				/* function result is a single column */
-	}
-	else
-	{
-		finfo = (FuncIndexInfo *) NULL;
-	}
-
 	index_create(RelationGetRelationName(NewHeap),
 				 NewIndexName,
-				 finfo,
-				 NULL,			/* type info is in the old index */
+				 indexInfo,
 				 Old_pg_index_relation_Form->relam,
-				 natts,
-				 Old_pg_index_Form->indkey,
 				 Old_pg_index_Form->indclass,
-				 (Node *) NULL,	/* XXX where's the predicate? */
 				 Old_pg_index_Form->indislossy,
-				 Old_pg_index_Form->indisunique,
 				 Old_pg_index_Form->indisprimary,
 				 allowSystemTableMods);
 
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 6648e66f4e398f73cc7a8be56bd25f5203f7898d..be24c696a7cb2328c7764dd0853fdf692f2242e2 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.88 2000/07/05 23:11:09 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.89 2000/07/14 22:17:42 tgl Exp $
  *
  * NOTES
  *	  The PerformAddAttribute() code, like most of the relation
@@ -1205,7 +1205,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
 	char				toast_relname[NAMEDATALEN + 1];
 	char				toast_idxname[NAMEDATALEN + 1];
 	Relation			toast_rel;
-	AttrNumber			attNums[1];
+	IndexInfo		   *indexInfo;
 	Oid					classObjectId[1];
 
 	/*
@@ -1334,11 +1334,20 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
 	CommandCounterIncrement();
 
 	/* create index on chunk_id */
-	attNums[0] = 1;
+
+	indexInfo = makeNode(IndexInfo);
+	indexInfo->ii_NumIndexAttrs = 1;
+	indexInfo->ii_NumKeyAttrs = 1;
+	indexInfo->ii_KeyAttrNumbers[0] = 1;
+	indexInfo->ii_Predicate = NULL;
+	indexInfo->ii_FuncOid = InvalidOid;
+	indexInfo->ii_Unique = false;
+
 	classObjectId[0] = OID_OPS_OID;
-	index_create(toast_relname, toast_idxname, NULL, NULL, BTREE_AM_OID,
-				 1, attNums, classObjectId,
-				 (Node *) NULL, false, false, false, true);
+
+	index_create(toast_relname, toast_idxname, indexInfo,
+				 BTREE_AM_OID, classObjectId,
+				 false, false, true);
 
 	/* make the index visible in this transaction */
 	CommandCounterIncrement();
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 355b218e6409a209fd0f194d24042619a7f9d449..52100e92dd92db72b0bc6c480b8df7d768e6fb37 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.118 2000/07/12 02:36:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.119 2000/07/14 22:17:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,10 +50,6 @@ static Oid	GetOutputFunction(Oid type);
 static Oid	GetTypeElement(Oid type);
 static Oid	GetInputFunction(Oid type);
 static Oid	IsTypeByVal(Oid type);
-static void GetIndexRelations(Oid main_relation_oid,
-				  int *n_indices,
-				  Relation **index_rels);
-
 static void CopyReadNewline(FILE *fp, int *newline);
 static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print);
 
@@ -576,53 +572,35 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
 }
 
 static void
-CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print)
+CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
+		 char *delim, char *null_print)
 {
 	HeapTuple	tuple;
-	AttrNumber	attr_count;
+	TupleDesc	tupDesc;
 	Form_pg_attribute *attr;
+	AttrNumber	attr_count;
 	FmgrInfo   *in_functions;
+	Oid		   *elements;
+	int32	   *typmod;
 	int			i;
 	Oid			in_func_oid;
 	Datum	   *values;
-	char	   *nulls,
-			   *index_nulls;
+	char	   *nulls;
 	bool	   *byval;
 	bool		isnull;
-	bool		has_index;
 	int			done = 0;
 	char	   *string = NULL,
 			   *ptr;
-	Relation   *index_rels;
 	int32		len,
 				null_ct,
 				null_id;
 	int32		ntuples,
 				tuples_read = 0;
 	bool		reading_to_eof = true;
-	Oid		   *elements;
-	int32	   *typmod;
-	FuncIndexInfo *finfo,
-			  **finfoP = NULL;
-	TupleDesc  *itupdescArr;
-	HeapTuple	pgIndexTup;
-	Form_pg_index *pgIndexP = NULL;
-	int		   *indexNatts = NULL;
-	char	   *predString;
-	Node	  **indexPred = NULL;
-	TupleDesc	rtupdesc;
+	RelationInfo *relationInfo;
 	EState	   *estate = makeNode(EState);		/* for ExecConstraints() */
-#ifndef OMIT_PARTIAL_INDEX
-	ExprContext *econtext = NULL;
 	TupleTable	tupleTable;
-	TupleTableSlot *slot = NULL;
-#endif
-	int			natts;
-	AttrNumber *attnumP;
-	Datum	   *idatum;
-	int			n_indices;
-	InsertIndexResult indexRes;
-	TupleDesc	tupDesc;
+	TupleTableSlot *slot;
 	Oid			loaded_oid = InvalidOid;
 	bool		skip_tuple = false;
 
@@ -630,71 +608,26 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
 	attr = tupDesc->attrs;
 	attr_count = tupDesc->natts;
 
-	has_index = false;
-
 	/*
-	 * This may be a scalar or a functional index.	We initialize all
-	 * kinds of arrays here to avoid doing extra work at every tuple copy.
+	 * We need a RelationInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount
+	 * of code here that basically duplicated execUtils.c ...)
 	 */
+	relationInfo = makeNode(RelationInfo);
+	relationInfo->ri_RangeTableIndex = 1; /* dummy */
+	relationInfo->ri_RelationDesc = rel;
+	relationInfo->ri_NumIndices = 0;
+	relationInfo->ri_IndexRelationDescs = NULL;
+	relationInfo->ri_IndexRelationInfo = NULL;
 
-	if (rel->rd_rel->relhasindex)
-	{
-		GetIndexRelations(RelationGetRelid(rel), &n_indices, &index_rels);
-		if (n_indices > 0)
-		{
-			has_index = true;
-			itupdescArr = (TupleDesc *) palloc(n_indices * sizeof(TupleDesc));
-			pgIndexP = (Form_pg_index *) palloc(n_indices * sizeof(Form_pg_index));
-			indexNatts = (int *) palloc(n_indices * sizeof(int));
-			finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
-			finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
-			indexPred = (Node **) palloc(n_indices * sizeof(Node *));
-			for (i = 0; i < n_indices; i++)
-			{
-				itupdescArr[i] = RelationGetDescr(index_rels[i]);
-				pgIndexTup = SearchSysCacheTuple(INDEXRELID,
-					   ObjectIdGetDatum(RelationGetRelid(index_rels[i])),
-												 0, 0, 0);
-				Assert(pgIndexTup);
-				pgIndexP[i] = (Form_pg_index) GETSTRUCT(pgIndexTup);
-				for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
-				 natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
-					 attnumP++, natts++);
-				if (pgIndexP[i]->indproc != InvalidOid)
-				{
-					FIgetnArgs(&finfo[i]) = natts;
-					natts = 1;
-					FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc;
-					*(FIgetname(&finfo[i])) = '\0';
-					finfoP[i] = &finfo[i];
-				}
-				else
-					finfoP[i] = (FuncIndexInfo *) NULL;
-				indexNatts[i] = natts;
-				if (VARSIZE(&pgIndexP[i]->indpred) != 0)
-				{
-					predString = DatumGetCString(DirectFunctionCall1(textout,
-									PointerGetDatum(&pgIndexP[i]->indpred)));
-					indexPred[i] = stringToNode(predString);
-					pfree(predString);
-#ifndef OMIT_PARTIAL_INDEX
-					/* make dummy ExprContext for use by ExecQual */
-					if (econtext == NULL)
-					{
-						tupleTable = ExecCreateTupleTable(1);
-						slot = ExecAllocTableSlot(tupleTable);
-						rtupdesc = RelationGetDescr(rel);
-						ExecSetSlotDescriptor(slot, rtupdesc);
-						econtext = MakeExprContext(slot,
-												   TransactionCommandContext);
-					}
-#endif	 /* OMIT_PARTIAL_INDEX */
-				}
-				else
-					indexPred[i] = NULL;
-			}
-		}
-	}
+	ExecOpenIndices(relationInfo);
+
+	estate->es_result_relation_info = relationInfo;
+
+	/* Set up a dummy tuple table too */
+	tupleTable = ExecCreateTupleTable(1);
+	slot = ExecAllocTableSlot(tupleTable);
+	ExecSetSlotDescriptor(slot, tupDesc);
 
 	if (!binary)
 	{
@@ -723,16 +656,13 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
 			reading_to_eof = false;
 	}
 
-	values = (Datum *) palloc(sizeof(Datum) * attr_count);
-	nulls = (char *) palloc(attr_count);
-	index_nulls = (char *) palloc(attr_count);
-	idatum = (Datum *) palloc(sizeof(Datum) * attr_count);
+	values = (Datum *) palloc(attr_count * sizeof(Datum));
+	nulls = (char *) palloc(attr_count * sizeof(char));
 	byval = (bool *) palloc(attr_count * sizeof(bool));
 
 	for (i = 0; i < attr_count; i++)
 	{
 		nulls[i] = ' ';
-		index_nulls[i] = ' ';
 #ifdef	_DROP_COLUMN_HACK__
 		if (COLUMN_IS_DROPPED(attr[i]))
 		{
@@ -873,6 +803,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
 			tuple->t_data->t_oid = loaded_oid;
 
 		skip_tuple = false;
+
 		/* BEFORE ROW INSERT Triggers */
 		if (rel->trigdesc &&
 			rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
@@ -893,45 +824,25 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
 		if (!skip_tuple)
 		{
 			/* ----------------
-			 * Check the constraints of a tuple
+			 * Check the constraints of the tuple
 			 * ----------------
 			 */
 
 			if (rel->rd_att->constr)
 				ExecConstraints("CopyFrom", rel, tuple, estate);
 
+			/* ----------------
+			 * OK, store the tuple and create index entries for it
+			 * ----------------
+			 */
 			heap_insert(rel, tuple);
 
-			if (has_index)
+			if (relationInfo->ri_NumIndices > 0)
 			{
-				for (i = 0; i < n_indices; i++)
-				{
-#ifndef OMIT_PARTIAL_INDEX
-					if (indexPred[i] != NULL)
-					{
-						/*
-						 * if tuple doesn't satisfy predicate, don't
-						 * update index
-						 */
-						slot->val = tuple;
-						/* SetSlotContents(slot, tuple); */
-						if (!ExecQual((List *) indexPred[i], econtext, false))
-							continue;
-					}
-#endif	 /* OMIT_PARTIAL_INDEX */
-					FormIndexDatum(indexNatts[i],
-								(AttrNumber *) &(pgIndexP[i]->indkey[0]),
-								   tuple,
-								   tupDesc,
-								   idatum,
-								   index_nulls,
-								   finfoP[i]);
-					indexRes = index_insert(index_rels[i], idatum, index_nulls,
-											&(tuple->t_self), rel);
-					if (indexRes)
-						pfree(indexRes);
-				}
+				ExecStoreTuple(tuple, slot, InvalidBuffer, false);
+				ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
 			}
+
 			/* AFTER ROW INSERT Triggers */
 			if (rel->trigdesc &&
 				rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
@@ -948,8 +859,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
 				if (!binary)
 					pfree((void *) values[i]);
 			}
-			else if (nulls[i] == 'n')
-				nulls[i] = ' ';
+			/* reset nulls[] array for next time */
+			nulls[i] = ' ';
 		}
 
 		heap_freetuple(tuple);
@@ -958,11 +869,14 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
 		if (!reading_to_eof && ntuples == tuples_read)
 			done = true;
 	}
+
+	/*
+	 * Done, clean up
+	 */
 	lineno = 0;
+
 	pfree(values);
 	pfree(nulls);
-	pfree(index_nulls);
-	pfree(idatum);
 	pfree(byval);
 
 	if (!binary)
@@ -972,21 +886,10 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
 		pfree(typmod);
 	}
 
-	if (has_index)
-	{
-		for (i = 0; i < n_indices; i++)
-		{
-			if (index_rels[i] == NULL)
-				continue;
-			/* see comments in ExecOpenIndices() in execUtils.c */
-			if ((index_rels[i])->rd_rel->relam != BTREE_AM_OID &&
-				(index_rels[i])->rd_rel->relam != HASH_AM_OID)
-				UnlockRelation(index_rels[i], AccessExclusiveLock);
-			index_close(index_rels[i]);
-		}
-	}
-}
+	ExecDropTupleTable(tupleTable, true);
 
+	ExecCloseIndices(relationInfo);
+}
 
 
 static Oid
@@ -1054,52 +957,6 @@ IsTypeByVal(Oid type)
 	return InvalidOid;
 }
 
-/*
- * Given the OID of a relation, return an array of index relation descriptors
- * and the number of index relations.  These relation descriptors are open
- * using index_open().
- *
- * Space for the array itself is palloc'ed.
- */
-
-static void
-GetIndexRelations(Oid main_relation_oid,
-				  int *n_indices,
-				  Relation **index_rels)
-{
-	Relation	relation;
-	List	   *indexoidlist,
-			   *indexoidscan;
-	int			i;
-
-	relation = heap_open(main_relation_oid, AccessShareLock);
-	indexoidlist = RelationGetIndexList(relation);
-
-	*n_indices = length(indexoidlist);
-
-	if (*n_indices > 0)
-		*index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
-	else
-		*index_rels = NULL;
-
-	i = 0;
-	foreach(indexoidscan, indexoidlist)
-	{
-		Oid			indexoid = lfirsti(indexoidscan);
-		Relation	index = index_open(indexoid);
-
-		/* see comments in ExecOpenIndices() in execUtils.c */
-		if (index != NULL &&
-			index->rd_rel->relam != BTREE_AM_OID &&
-			index->rd_rel->relam != HASH_AM_OID)
-			LockRelation(index, AccessExclusiveLock);
-		(*index_rels)[i] = index;
-		i++;
-	}
-
-	freeList(indexoidlist);
-	heap_close(relation, AccessShareLock);
-}
 
 /*
  * Reads input from fp until an end of line is seen.
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index efe8a44180a7554a091b28fed77b093e83532f40..6ede4f51c1234fbc9f594e01dcdc0f8562a1bfee 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.34 2000/07/05 23:11:11 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.35 2000/07/14 22:17:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #include "catalog/catname.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
+#include "catalog/pg_am.h"
 #include "catalog/pg_amop.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_index.h"
@@ -47,14 +48,14 @@
 static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
 static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
 static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
-static void FuncIndexArgs(IndexElem *funcIndex, FuncIndexInfo *funcInfo,
-						  AttrNumber *attNumP, Oid *opOidP, Oid relId,
+static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP,
+						  IndexElem *funcIndex,
+						  Oid relId,
 						  char *accessMethodName, Oid accessMethodId);
-static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
-						   Oid *opOidP, Oid relId,
+static void NormIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
+						   List *attList,
+						   Oid relId,
 						   char *accessMethodName, Oid accessMethodId);
-static void ProcessAttrTypename(IndexElem *attribute,
-					Oid defType, int32 defTypmod);
 static Oid	GetAttrOpClass(IndexElem *attribute, Oid attrType,
 						   char *accessMethodName, Oid accessMethodId);
 static char *GetDefaultOpClass(Oid atttypid);
@@ -67,10 +68,7 @@ static char *GetDefaultOpClass(Oid atttypid);
  *		index or a list of attributes to index on.
  * 'parameterList' is a list of DefElem specified in the with clause.
  * 'predicate' is the qual specified in the where clause.
- * 'rangetable' is for the predicate
- *
- * Exceptions:
- *		XXX
+ * 'rangetable' is needed to interpret the predicate
  */
 void
 DefineIndex(char *heapRelationName,
@@ -86,16 +84,15 @@ DefineIndex(char *heapRelationName,
 	Oid		   *classObjectId;
 	Oid			accessMethodId;
 	Oid			relationId;
+	IndexInfo  *indexInfo;
 	int			numberOfAttributes;
-	AttrNumber *attributeNumberA;
 	HeapTuple	tuple;
-	FuncIndexInfo fInfo;
-	List	   *cnfPred = NULL;
+	List	   *cnfPred = NIL;
 	bool		lossy = false;
 	List	   *pl;
 
 	/*
-	 * count attributes
+	 * count attributes in index
 	 */
 	numberOfAttributes = length(attributeList);
 	if (numberOfAttributes <= 0)
@@ -108,21 +105,8 @@ DefineIndex(char *heapRelationName,
 	 * compute heap relation id
 	 */
 	if ((relationId = RelnameFindRelid(heapRelationName)) == InvalidOid)
-	{
 		elog(ERROR, "DefineIndex: relation \"%s\" not found",
 			 heapRelationName);
-	}
-
-	/*
-	 * XXX Hardwired hacks to check for limitations on supported index types.
-	 * We really ought to be learning this info from entries in the pg_am
-	 * table, instead of having it wired in here!
-	 */
-	if (unique && strcmp(accessMethodName, "btree") != 0)
-		elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
-
-	if (numberOfAttributes > 1 && strcmp(accessMethodName, "btree") != 0)
-		elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method");
 
 	/*
 	 * compute access method id
@@ -131,12 +115,21 @@ DefineIndex(char *heapRelationName,
 								PointerGetDatum(accessMethodName),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
-	{
 		elog(ERROR, "DefineIndex: access method \"%s\" not found",
 			 accessMethodName);
-	}
 	accessMethodId = tuple->t_data->t_oid;
 
+	/*
+	 * XXX Hardwired hacks to check for limitations on supported index types.
+	 * We really ought to be learning this info from entries in the pg_am
+	 * table, instead of having it wired in here!
+	 */
+	if (unique && accessMethodId != BTREE_AM_OID)
+		elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
+
+	if (numberOfAttributes > 1 && accessMethodId != BTREE_AM_OID)
+		elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method");
+
 	/*
 	 * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
 	 */
@@ -145,7 +138,7 @@ DefineIndex(char *heapRelationName,
 		DefElem    *param = (DefElem *) lfirst(pl);
 
 		if (!strcasecmp(param->defname, "islossy"))
-			lossy = TRUE;
+			lossy = true;
 		else
 			elog(NOTICE, "Unrecognized index attribute \"%s\" ignored",
 				 param->defname);
@@ -169,55 +162,51 @@ DefineIndex(char *heapRelationName,
 	if (!IsBootstrapProcessingMode() && !IndexesAreActive(relationId, false))
 		elog(ERROR, "Existing indexes are inactive. REINDEX first");
 
+	/*
+	 * Prepare arguments for index_create, primarily an IndexInfo structure
+	 */
+	indexInfo = makeNode(IndexInfo);
+	indexInfo->ii_Predicate = (Node *) cnfPred;
+	indexInfo->ii_FuncOid = InvalidOid;
+	indexInfo->ii_Unique = unique;
+
 	if (IsFuncIndex(attributeList))
 	{
-		IndexElem  *funcIndex = lfirst(attributeList);
+		IndexElem  *funcIndex = (IndexElem *) lfirst(attributeList);
 		int			nargs;
 
+		/* Parser should have given us only one list item, but check */
+		if (numberOfAttributes != 1)
+			elog(ERROR, "Functional index can only have one attribute");
+
 		nargs = length(funcIndex->args);
 		if (nargs > INDEX_MAX_KEYS)
 			elog(ERROR, "Index function can take at most %d arguments",
 				 INDEX_MAX_KEYS);
 
-		FIsetnArgs(&fInfo, nargs);
-
-		namestrcpy(&fInfo.funcName, funcIndex->name);
-
-		attributeNumberA = (AttrNumber *) palloc(nargs *
-											 sizeof attributeNumberA[0]);
+		indexInfo->ii_NumIndexAttrs = 1;
+		indexInfo->ii_NumKeyAttrs = nargs;
 
 		classObjectId = (Oid *) palloc(sizeof(Oid));
 
-		FuncIndexArgs(funcIndex, &fInfo, attributeNumberA,
-					  classObjectId, relationId,
-					  accessMethodName, accessMethodId);
-
-		index_create(heapRelationName, indexRelationName,
-					 &fInfo, NULL,
-					 accessMethodId, numberOfAttributes, attributeNumberA,
-					 classObjectId,
-					 (Node *) cnfPred,
-					 lossy, unique, primary, allowSystemTableMods);
+		FuncIndexArgs(indexInfo, classObjectId, funcIndex,
+					  relationId, accessMethodName, accessMethodId);
 	}
 	else
 	{
-		attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
-											 sizeof attributeNumberA[0]);
+		indexInfo->ii_NumIndexAttrs = numberOfAttributes;
+		indexInfo->ii_NumKeyAttrs = numberOfAttributes;
 
 		classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 
-		NormIndexAttrs(attributeList, attributeNumberA,
-					   classObjectId, relationId,
-					   accessMethodName, accessMethodId);
-
-		index_create(heapRelationName, indexRelationName,
-					 NULL, attributeList,
-					 accessMethodId, numberOfAttributes, attributeNumberA,
-					 classObjectId,
-					 (Node *) cnfPred,
-					 lossy, unique, primary, allowSystemTableMods);
+		NormIndexAttrs(indexInfo, classObjectId, attributeList,
+					   relationId, accessMethodName, accessMethodId);
 	}
 
+	index_create(heapRelationName, indexRelationName,
+				 indexInfo, accessMethodId, classObjectId,
+				 lossy, primary, allowSystemTableMods);
+
 	/*
 	 * We update the relation's pg_class tuple even if it already has
 	 * relhasindex = true.  This is needed to cause a shared-cache-inval
@@ -232,83 +221,48 @@ DefineIndex(char *heapRelationName,
 /*
  * ExtendIndex
  *		Extends a partial index.
- *
- * Exceptions:
- *		XXX
  */
 void
 ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
 {
-	Oid		   *classObjectId;
-	Oid			accessMethodId;
-	Oid			indexId,
+	Relation	heapRelation;
+	Relation	indexRelation;
+	Oid			accessMethodId,
+				indexId,
 				relationId;
-	Oid			indproc;
-	int			numberOfAttributes;
-	AttrNumber *attributeNumberA;
 	HeapTuple	tuple;
-	FuncIndexInfo fInfo;
-	FuncIndexInfo *funcInfo = NULL;
-	bool		unique;
 	Form_pg_index index;
-	Node	   *oldPred = NULL;
-	List	   *cnfPred = NULL;
-	PredInfo   *predInfo;
-	Relation	heapRelation;
-	Relation	indexRelation;
-	int			i;
+	List	   *cnfPred = NIL;
+	IndexInfo  *indexInfo;
+	Node	   *oldPred;
 
 	/*
-	 * compute index relation id and access method id
+	 * Get index's relation id and access method id from pg_class
 	 */
 	tuple = SearchSysCacheTuple(RELNAME,
 								PointerGetDatum(indexRelationName),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
-	{
 		elog(ERROR, "ExtendIndex: index \"%s\" not found",
 			 indexRelationName);
-	}
 	indexId = tuple->t_data->t_oid;
 	accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
 
 	/*
-	 * find pg_index tuple
+	 * Extract info from the pg_index tuple for the index
 	 */
 	tuple = SearchSysCacheTuple(INDEXRELID,
 								ObjectIdGetDatum(indexId),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
-	{
 		elog(ERROR, "ExtendIndex: relation \"%s\" is not an index",
 			 indexRelationName);
-	}
-
-	/*
-	 * Extract info from the pg_index tuple
-	 */
 	index = (Form_pg_index) GETSTRUCT(tuple);
 	Assert(index->indexrelid == indexId);
 	relationId = index->indrelid;
-	indproc = index->indproc;
-	unique = index->indisunique;
-
-	for (i = 0; i < INDEX_MAX_KEYS; i++)
-	{
-		if (index->indkey[i] == InvalidAttrNumber)
-			break;
-	}
-	numberOfAttributes = i;
+	indexInfo = BuildIndexInfo(tuple);
+	oldPred = indexInfo->ii_Predicate;
 
-	if (VARSIZE(&index->indpred) != 0)
-	{
-		char	   *predString;
-
-		predString = DatumGetCString(DirectFunctionCall1(textout,
-											PointerGetDatum(&index->indpred)));
-		oldPred = stringToNode(predString);
-		pfree(predString);
-	}
 	if (oldPred == NULL)
 		elog(ERROR, "ExtendIndex: \"%s\" is not a partial index",
 			 indexRelationName);
@@ -316,8 +270,11 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
 	/*
 	 * Convert the extension predicate from parsetree form to plan form,
 	 * so it can be readily evaluated during index creation. Note:
-	 * "predicate" comes in as a list containing (1) the predicate itself
-	 * (a where_clause), and (2) a corresponding range table.
+	 * "predicate" comes in two parts (1) the predicate expression itself,
+	 * and (2) a corresponding range table.
+	 *
+	 * XXX I think this code is broken --- index_build expects a single
+	 * expression not a list --- tgl Jul 00
 	 */
 	if (rangetable != NIL)
 	{
@@ -326,47 +283,20 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
 		CheckPredicate(cnfPred, rangetable, relationId);
 	}
 
-	/* make predInfo list to pass to index_build */
-	predInfo = (PredInfo *) palloc(sizeof(PredInfo));
-	predInfo->pred = (Node *) cnfPred;
-	predInfo->oldPred = oldPred;
-
-	attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
-											 sizeof attributeNumberA[0]);
-	classObjectId = (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
-
-
-	for (i = 0; i < numberOfAttributes; i++)
-	{
-		attributeNumberA[i] = index->indkey[i];
-		classObjectId[i] = index->indclass[i];
-	}
-
-	if (indproc != InvalidOid)
-	{
-		funcInfo = &fInfo;
-		FIsetnArgs(funcInfo, numberOfAttributes);
-
-		tuple = SearchSysCacheTuple(PROCOID,
-									ObjectIdGetDatum(indproc),
-									0, 0, 0);
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "ExtendIndex: index procedure %u not found",
-				 indproc);
-
-		namecpy(&(funcInfo->funcName),
-				&(((Form_pg_proc) GETSTRUCT(tuple))->proname));
-
-		FIsetProcOid(funcInfo, tuple->t_data->t_oid);
-	}
+	/* pass new predicate to index_build */
+	indexInfo->ii_Predicate = (Node *) cnfPred;
 
+	/* Open heap and index rels, and get suitable locks */
 	heapRelation = heap_open(relationId, ShareLock);
 	indexRelation = index_open(indexId);
 
-	InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
+	/* Obtain exclusive lock on it, just to be sure */
+	LockRelation(indexRelation, AccessExclusiveLock);
+
+	InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
+					  indexRelation, accessMethodId);
 
-	index_build(heapRelation, indexRelation, numberOfAttributes,
-				attributeNumberA, funcInfo, predInfo, unique);
+	index_build(heapRelation, indexRelation, indexInfo, oldPred);
 
 	/* heap and index rels are closed as a side-effect of index_build */
 }
@@ -431,15 +361,15 @@ CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
 
 
 static void
-FuncIndexArgs(IndexElem *funcIndex,
-			  FuncIndexInfo *funcInfo,
-			  AttrNumber *attNumP,
-			  Oid *opOidP,
+FuncIndexArgs(IndexInfo *indexInfo,
+			  Oid *classOidP,
+			  IndexElem *funcIndex,
 			  Oid relId,
 			  char *accessMethodName,
 			  Oid accessMethodId)
 {
-	List	   *rest;
+	Oid			argTypes[FUNC_MAX_ARGS];
+	List	   *arglist;
 	HeapTuple	tuple;
 	Oid			retType;
 	int			argn = 0;
@@ -447,68 +377,77 @@ FuncIndexArgs(IndexElem *funcIndex,
 	/*
 	 * process the function arguments, which are a list of T_String
 	 * (someday ought to allow more general expressions?)
+	 *
+	 * Note caller already checked that list is not too long.
 	 */
-	MemSet(funcInfo->arglist, 0, FUNC_MAX_ARGS * sizeof(Oid));
+	MemSet(argTypes, 0, sizeof(argTypes));
 
-	foreach(rest, funcIndex->args)
+	foreach(arglist, funcIndex->args)
 	{
-		char	   *arg = strVal(lfirst(rest));
+		char	   *arg = strVal(lfirst(arglist));
 		Form_pg_attribute att;
 
 		tuple = SearchSysCacheTuple(ATTNAME,
 									ObjectIdGetDatum(relId),
-									PointerGetDatum(arg), 0, 0);
-
+									PointerGetDatum(arg),
+									0, 0);
 		if (!HeapTupleIsValid(tuple))
 			elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg);
 		att = (Form_pg_attribute) GETSTRUCT(tuple);
-		*attNumP++ = att->attnum;
-		funcInfo->arglist[argn++] = att->atttypid;
+
+		indexInfo->ii_KeyAttrNumbers[argn] = att->attnum;
+		argTypes[argn] = att->atttypid;
+		argn++;
 	}
 
 	/* ----------------
 	 * Lookup the function procedure to get its OID and result type.
+	 *
+	 * XXX need to accept binary-compatible functions here, not just
+	 * an exact match.
 	 * ----------------
 	 */
 	tuple = SearchSysCacheTuple(PROCNAME,
-								PointerGetDatum(FIgetname(funcInfo)),
-								Int32GetDatum(FIgetnArgs(funcInfo)),
-								PointerGetDatum(FIgetArglist(funcInfo)),
+								PointerGetDatum(funcIndex->name),
+								Int32GetDatum(indexInfo->ii_NumKeyAttrs),
+								PointerGetDatum(argTypes),
 								0);
-
 	if (!HeapTupleIsValid(tuple))
 	{
-		func_error("DefineIndex", FIgetname(funcInfo),
-				   FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL);
+		func_error("DefineIndex", funcIndex->name,
+				   indexInfo->ii_NumKeyAttrs, argTypes, NULL);
 	}
 
-	FIsetProcOid(funcInfo, tuple->t_data->t_oid);
+	indexInfo->ii_FuncOid = tuple->t_data->t_oid;
 	retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
 
-	/* Process type and opclass, using func return type as default */
+	/* Process opclass, using func return type as default type */
 
-	ProcessAttrTypename(funcIndex, retType, -1);
+	classOidP[0] = GetAttrOpClass(funcIndex, retType,
+								  accessMethodName, accessMethodId);
 
-	*opOidP = GetAttrOpClass(funcIndex, retType,
-							 accessMethodName, accessMethodId);
+	/* Need to do the fmgr function lookup now, too */
+
+	fmgr_info(indexInfo->ii_FuncOid, & indexInfo->ii_FuncInfo);
 }
 
 static void
-NormIndexAttrs(List *attList,	/* list of IndexElem's */
-			   AttrNumber *attNumP,
+NormIndexAttrs(IndexInfo *indexInfo,
 			   Oid *classOidP,
+			   List *attList,	/* list of IndexElem's */
 			   Oid relId,
 			   char *accessMethodName,
 			   Oid accessMethodId)
 {
 	List	   *rest;
+	int			attn = 0;
 
 	/*
 	 * process attributeList
 	 */
 	foreach(rest, attList)
 	{
-		IndexElem  *attribute = lfirst(rest);
+		IndexElem  *attribute = (IndexElem *) lfirst(rest);
 		HeapTuple	atttuple;
 		Form_pg_attribute attform;
 
@@ -524,36 +463,13 @@ NormIndexAttrs(List *attList,	/* list of IndexElem's */
 				 attribute->name);
 		attform = (Form_pg_attribute) GETSTRUCT(atttuple);
 
-		*attNumP++ = attform->attnum;
-
-		ProcessAttrTypename(attribute, attform->atttypid, attform->atttypmod);
+		indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;
 
-		*classOidP++ = GetAttrOpClass(attribute, attform->atttypid,
-									  accessMethodName, accessMethodId);
+		classOidP[attn] = GetAttrOpClass(attribute, attform->atttypid,
+										 accessMethodName, accessMethodId);
 
 		heap_freetuple(atttuple);
-	}
-}
-
-static void
-ProcessAttrTypename(IndexElem *attribute,
-					Oid defType, int32 defTypmod)
-{
-	HeapTuple	tuple;
-
-	/* build a type node so we can set the proper alignment, etc. */
-	if (attribute->typename == NULL)
-	{
-		tuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(defType),
-									0, 0, 0);
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "DefineIndex: type for attribute \"%s\" undefined",
-				 attribute->name);
-
-		attribute->typename = makeNode(TypeName);
-		attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
-		attribute->typename->typmod = defTypmod;
+		attn++;
 	}
 }
 
@@ -626,7 +542,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
 	 *
 	 * If the opclass was the default for the datatype, assume we can skip
 	 * this check --- that saves a few cycles in the most common case.
-	 * If pg_opclass is messed up then we're probably screwed anyway...
+	 * If pg_opclass is wrong then we're probably screwed anyway...
 	 */
 	if (doTypeCheck)
 	{
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 71682baa8cd57df17b16d8a7a53c9caaa634bcd6..ee0ebeb4bb726e94dcfeafff687af50f18681400 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.162 2000/07/05 16:17:38 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.163 2000/07/14 22:17:42 tgl Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -28,6 +28,7 @@
 #include "catalog/index.h"
 #include "commands/vacuum.h"
 #include "miscadmin.h"
+#include "nodes/execnodes.h"
 #include "storage/sinval.h"
 #include "storage/smgr.h"
 #include "tcop/tcopprot.h"
@@ -71,7 +72,8 @@ static void reap_page(VacPageList vacpagelist, VacPage vacpage);
 static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
 static void get_indices(Relation relation, int *nindices, Relation **Irel);
 static void close_indices(int nindices, Relation *Irel);
-static void get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
+static IndexInfo **get_index_desc(Relation onerel, int nindices,
+								  Relation *Irel);
 static void *vac_find_eq(void *bot, int nelem, int size, void *elm,
 			 int (*compar) (const void *, const void *));
 static int	vac_cmp_blk(const void *left, const void *right);
@@ -948,9 +950,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
 				newitemid;
 	HeapTupleData tuple,
 				newtup;
-	TupleDesc	tupdesc = NULL;
-	Datum	   *idatum = NULL;
-	char	   *inulls = NULL;
+	TupleDesc	tupdesc;
+	IndexInfo **indexInfo = NULL;
+	Datum		idatum[INDEX_MAX_KEYS];
+	char		inulls[INDEX_MAX_KEYS];
 	InsertIndexResult iresult;
 	VacPageListData Nvacpagelist;
 	VacPage		cur_page = NULL,
@@ -958,8 +961,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
 				vacpage,
 			   *curpage;
 	int			cur_item = 0;
-	IndDesc    *Idesc,
-			   *idcur;
 	int			last_move_dest_block = -1,
 				last_vacuum_block,
 				i = 0;
@@ -980,13 +981,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
 	myXID = GetCurrentTransactionId();
 	myCID = GetCurrentCommandId();
 
+	tupdesc = RelationGetDescr(onerel);
+
 	if (Irel != (Relation *) NULL)		/* preparation for index' inserts */
-	{
-		get_index_desc(onerel, nindices, Irel, &Idesc);
-		tupdesc = RelationGetDescr(onerel);
-		idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof(*idatum));
-		inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof(*inulls));
-	}
+		indexInfo = get_index_desc(onerel, nindices, Irel);
 
 	Nvacpagelist.num_pages = 0;
 	num_fraged_pages = fraged_pages->num_pages;
@@ -1456,15 +1454,22 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
 
 					if (Irel != (Relation *) NULL)
 					{
-						for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
+						/*
+						 * XXX using CurrentMemoryContext here means
+						 * intra-vacuum memory leak for functional indexes.
+						 * Should fix someday.
+						 *
+						 * XXX This code fails to handle partial indexes!
+						 * Probably should change it to use ExecOpenIndices.
+						 */
+						for (i = 0; i < nindices; i++)
 						{
-							FormIndexDatum(idcur->natts,
-							   (AttrNumber *) &(idcur->tform->indkey[0]),
+							FormIndexDatum(indexInfo[i],
 										   &newtup,
 										   tupdesc,
+										   CurrentMemoryContext,
 										   idatum,
-										   inulls,
-										   idcur->finfoP);
+										   inulls);
 							iresult = index_insert(Irel[i],
 												   idatum,
 												   inulls,
@@ -1575,15 +1580,22 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
 			/* insert index' tuples if needed */
 			if (Irel != (Relation *) NULL)
 			{
-				for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
+				/*
+				 * XXX using CurrentMemoryContext here means
+				 * intra-vacuum memory leak for functional indexes.
+				 * Should fix someday.
+				 *
+				 * XXX This code fails to handle partial indexes!
+				 * Probably should change it to use ExecOpenIndices.
+				 */
+				for (i = 0; i < nindices; i++)
 				{
-					FormIndexDatum(idcur->natts,
-							   (AttrNumber *) &(idcur->tform->indkey[0]),
+					FormIndexDatum(indexInfo[i],
 								   &newtup,
 								   tupdesc,
+								   CurrentMemoryContext,
 								   idatum,
-								   inulls,
-								   idcur->finfoP);
+								   inulls);
 					iresult = index_insert(Irel[i],
 										   idatum,
 										   inulls,
@@ -1821,10 +1833,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
 
 	if (Irel != (Relation *) NULL)		/* pfree index' allocations */
 	{
-		pfree(Idesc);
-		pfree(idatum);
-		pfree(inulls);
 		close_indices(nindices, Irel);
+		pfree(indexInfo);
 	}
 
 	pfree(vacpage);
@@ -2347,46 +2357,30 @@ close_indices(int nindices, Relation *Irel)
 }
 
 
-static void
-get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc)
+/*
+ * Obtain IndexInfo data for each index on the rel
+ */
+static IndexInfo **
+get_index_desc(Relation onerel, int nindices, Relation *Irel)
 {
-	IndDesc    *idcur;
-	HeapTuple	cachetuple;
-	AttrNumber *attnumP;
-	int			natts;
+	IndexInfo **indexInfo;
 	int			i;
+	HeapTuple	cachetuple;
 
-	*Idesc = (IndDesc *) palloc(nindices * sizeof(IndDesc));
+	indexInfo = (IndexInfo **) palloc(nindices * sizeof(IndexInfo *));
 
-	for (i = 0, idcur = *Idesc; i < nindices; i++, idcur++)
+	for (i = 0; i < nindices; i++)
 	{
-		cachetuple = SearchSysCacheTupleCopy(INDEXRELID,
+		cachetuple = SearchSysCacheTuple(INDEXRELID,
 							 ObjectIdGetDatum(RelationGetRelid(Irel[i])),
-											 0, 0, 0);
-		Assert(cachetuple);
-
-		/*
-		 * we never free the copy we make, because Idesc needs it for
-		 * later
-		 */
-		idcur->tform = (Form_pg_index) GETSTRUCT(cachetuple);
-		for (attnumP = &(idcur->tform->indkey[0]), natts = 0;
-			 natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
-			 attnumP++, natts++);
-		if (idcur->tform->indproc != InvalidOid)
-		{
-			idcur->finfoP = &(idcur->finfo);
-			FIgetnArgs(idcur->finfoP) = natts;
-			natts = 1;
-			FIgetProcOid(idcur->finfoP) = idcur->tform->indproc;
-			*(FIgetname(idcur->finfoP)) = '\0';
-		}
-		else
-			idcur->finfoP = (FuncIndexInfo *) NULL;
-
-		idcur->natts = natts;
+										 0, 0, 0);
+		if (!HeapTupleIsValid(cachetuple))
+			elog(ERROR, "get_index_desc: index %u not found",
+				 RelationGetRelid(Irel[i]));
+		indexInfo[i] = BuildIndexInfo(cachetuple);
 	}
 
+	return indexInfo;
 }
 
 
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index daa40dccf75e7c188b2ba7c95935949634a56d52..39e3d5cd48bdbfd57c2b64e4c638c8d32ba3fc02 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.63 2000/07/12 02:37:03 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.64 2000/07/14 22:17:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,11 +27,9 @@
  *		QueryDescGetTypeInfo - moved here from main.c
  *								am not sure what uses it -cim 10/12/89
  *
- *		ExecGetIndexKeyInfo		\
- *		ExecOpenIndices			 | referenced by InitPlan, EndPlan,
- *		ExecCloseIndices		 | ExecAppend, ExecReplace
- *		ExecFormIndexTuple		 |
- *		ExecInsertIndexTuple	/
+ *		ExecOpenIndices			\
+ *		ExecCloseIndices		 | referenced by InitPlan, EndPlan,
+ *		ExecInsertIndexTuples	/  ExecAppend, ExecReplace
  *
  *	 NOTES
  *		This file has traditionally been the place to stick misc.
@@ -55,8 +53,6 @@
 #include "utils/relcache.h"
 #include "utils/syscache.h"
 
-static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP,
-					AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
 
 /* ----------------------------------------------------------------
  *		global counters for number of tuples processed, retrieved,
@@ -684,93 +680,6 @@ QueryDescGetTypeInfo(QueryDesc *queryDesc)
  *				  ExecInsertIndexTuples support
  * ----------------------------------------------------------------
  */
-/* ----------------------------------------------------------------
- *		ExecGetIndexKeyInfo
- *
- *		Extracts the index key attribute numbers from
- *		an index tuple form (i.e. a tuple from the pg_index relation)
- *		into an array of attribute numbers.  The array and the
- *		size of the array are returned to the caller via return
- *		parameters.
- * ----------------------------------------------------------------
- */
-static void
-ExecGetIndexKeyInfo(Form_pg_index indexTuple,
-					int *numAttsOutP,
-					AttrNumber **attsOutP,
-					FuncIndexInfoPtr fInfoP)
-{
-	int			i;
-	int			numKeys;
-	AttrNumber *attKeys;
-
-	/* ----------------
-	 *	check parameters
-	 * ----------------
-	 */
-	if (numAttsOutP == NULL || attsOutP == NULL)
-	{
-		elog(DEBUG, "ExecGetIndexKeyInfo: %s",
-		"invalid parameters: numAttsOutP and attsOutP must be non-NULL");
-	}
-
-	/* ----------------
-	 * set the procid for a possible functional index.
-	 * ----------------
-	 */
-	FIsetProcOid(fInfoP, indexTuple->indproc);
-
-	/* ----------------
-	 *	count the number of keys..
-	 * ----------------
-	 */
-	numKeys = 0;
-	for (i = 0; i < INDEX_MAX_KEYS &&
-		 indexTuple->indkey[i] != InvalidAttrNumber; i++)
-		numKeys++;
-
-	/* ----------------
-	 *	place number keys in callers return area
-	 *	or the number of arguments for a functional index.
-	 *
-	 *	If we have a functional index then the number of
-	 *	attributes defined in the index must 1 (the function's
-	 *	single return value).
-	 * ----------------
-	 */
-	if (FIgetProcOid(fInfoP) != InvalidOid)
-	{
-		FIsetnArgs(fInfoP, numKeys);
-		(*numAttsOutP) = 1;
-	}
-	else
-		(*numAttsOutP) = numKeys;
-
-	if (numKeys < 1)
-	{
-		elog(DEBUG, "ExecGetIndexKeyInfo: %s",
-			 "all index key attribute numbers are zero!");
-		(*attsOutP) = NULL;
-		return;
-	}
-
-	/* ----------------
-	 *	allocate and fill in array of key attribute numbers
-	 * ----------------
-	 */
-	CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);
-
-	attKeys = (AttrNumber *) palloc(numKeys * sizeof(AttrNumber));
-
-	for (i = 0; i < numKeys; i++)
-		attKeys[i] = indexTuple->indkey[i];
-
-	/* ----------------
-	 *	return array to caller.
-	 * ----------------
-	 */
-	(*attsOutP) = attKeys;
-}
 
 /* ----------------------------------------------------------------
  *		ExecOpenIndices
@@ -838,11 +747,6 @@ ExecOpenIndices(RelationInfo *resultRelationInfo)
 		Oid			indexOid = lfirsti(indexoidscan);
 		Relation	indexDesc;
 		HeapTuple	indexTuple;
-		Form_pg_index indexStruct;
-		int			numKeyAtts;
-		AttrNumber *indexKeyAtts;
-		FuncIndexInfoPtr fInfoP;
-		PredInfo   *predicate;
 		IndexInfo  *ii;
 
 		/* ----------------
@@ -874,47 +778,17 @@ ExecOpenIndices(RelationInfo *resultRelationInfo)
 		 *	Get the pg_index tuple for the index
 		 * ----------------
 		 */
-		indexTuple = SearchSysCacheTupleCopy(INDEXRELID,
-											 ObjectIdGetDatum(indexOid),
-											 0, 0, 0);
+		indexTuple = SearchSysCacheTuple(INDEXRELID,
+										 ObjectIdGetDatum(indexOid),
+										 0, 0, 0);
 		if (!HeapTupleIsValid(indexTuple))
 			elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
-		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 
 		/* ----------------
 		 *	extract the index key information from the tuple
 		 * ----------------
 		 */
-		fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
-		ExecGetIndexKeyInfo(indexStruct,
-							&numKeyAtts,
-							&indexKeyAtts,
-							fInfoP);
-
-		/* ----------------
-		 *	next get the index predicate from the tuple
-		 * ----------------
-		 */
-		if (VARSIZE(&indexStruct->indpred) != 0)
-		{
-			char	   *predString;
-
-			predString = DatumGetCString(DirectFunctionCall1(textout,
-									PointerGetDatum(&indexStruct->indpred)));
-			predicate = (PredInfo *) stringToNode(predString);
-			pfree(predString);
-		}
-		else
-			predicate = NULL;
-
-		/* Save the index info */
-		ii = makeNode(IndexInfo);
-		ii->ii_NumKeyAttributes = numKeyAtts;
-		ii->ii_KeyAttributeNumbers = indexKeyAtts;
-		ii->ii_FuncIndexInfo = fInfoP;
-		ii->ii_Predicate = (Node *) predicate;
-
-		heap_freetuple(indexTuple);
+		ii = BuildIndexInfo(indexTuple);
 
 		relationDescs[i] = indexDesc;
 		indexInfoArray[i] = ii;
@@ -984,17 +858,11 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 	int			numIndices;
 	RelationPtr relationDescs;
 	Relation	heapRelation;
+	TupleDesc	heapDescriptor;
 	IndexInfo **indexInfoArray;
-	IndexInfo  *indexInfo;
-	Node	   *predicate;
 	ExprContext *econtext;
-	InsertIndexResult result;
-	int			numberOfAttributes;
-	AttrNumber *keyAttributeNumbers;
-	FuncIndexInfoPtr fInfoP;
-	TupleDesc	heapDescriptor;
-	Datum	   *datum;
-	char	   *nulls;
+	Datum		datum[INDEX_MAX_KEYS];
+	char		nullv[INDEX_MAX_KEYS];
 
 	heapTuple = slot->val;
 
@@ -1007,14 +875,27 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 	relationDescs = resultRelationInfo->ri_IndexRelationDescs;
 	indexInfoArray = resultRelationInfo->ri_IndexRelationInfo;
 	heapRelation = resultRelationInfo->ri_RelationDesc;
+	heapDescriptor = RelationGetDescr(heapRelation);
+
+	/* ----------------
+	 *	Make a temporary expr/memory context for evaluating predicates
+	 *	and functional-index functions.
+	 *	XXX should do this once per command not once per tuple, and
+	 *	just reset it once per tuple.
+	 * ----------------
+	 */
+	econtext = MakeExprContext(slot, TransactionCommandContext);
 
 	/* ----------------
 	 *	for each index, form and insert the index tuple
 	 * ----------------
 	 */
-	econtext = NULL;
 	for (i = 0; i < numIndices; i++)
 	{
+		IndexInfo  *indexInfo;
+		Node	   *predicate;
+		InsertIndexResult result;
+
 		if (relationDescs[i] == NULL)
 			continue;
 
@@ -1022,39 +903,26 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 		predicate = indexInfo->ii_Predicate;
 		if (predicate != NULL)
 		{
-			if (econtext == NULL)
-				econtext = MakeExprContext(slot,
-										   TransactionCommandContext);
-
 			/* Skip this index-update if the predicate isn't satisfied */
 			if (!ExecQual((List *) predicate, econtext, false))
 				continue;
 		}
 
 		/* ----------------
-		 *		get information from index info structure
+		 *	FormIndexDatum fills in its datum and null parameters
+		 *	with attribute information taken from the given heap tuple.
 		 * ----------------
 		 */
-		numberOfAttributes = indexInfo->ii_NumKeyAttributes;
-		keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
-		fInfoP = indexInfo->ii_FuncIndexInfo;
-		datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
-		nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
-		heapDescriptor = (TupleDesc) RelationGetDescr(heapRelation);
-
-		FormIndexDatum(numberOfAttributes,		/* num attributes */
-					   keyAttributeNumbers,		/* array of att nums to
-												 * extract */
-					   heapTuple,		/* tuple from base relation */
-					   heapDescriptor,	/* heap tuple's descriptor */
-					   datum,	/* return: array of attributes */
-					   nulls,	/* return: array of char's */
-					   fInfoP); /* functional index information */
-
+		FormIndexDatum(indexInfo,
+					   heapTuple,
+					   heapDescriptor,
+					   econtext->ecxt_per_tuple_memory,
+					   datum,
+					   nullv);
 
 		result = index_insert(relationDescs[i], /* index relation */
 							  datum,	/* array of heaptuple Datums */
-							  nulls,	/* info on nulls */
+							  nullv,	/* info on nulls */
 							  &(heapTuple->t_self),		/* tid of heap tuple */
 							  heapRelation);
 
@@ -1064,15 +932,11 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 		 */
 		IncrIndexInserted();
 
-		/* ----------------
-		 *		free index tuple after insertion
-		 * ----------------
-		 */
 		if (result)
 			pfree(result);
 	}
-	if (econtext != NULL)
-		FreeExprContext(econtext);
+
+	FreeExprContext(econtext);
 }
 
 void
@@ -1094,5 +958,4 @@ SetChangedParamList(Plan *node, List *newchg)
 		/* else - add this param to the list */
 		node->chgParam = lappendi(node->chgParam, paramId);
 	}
-
 }
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index cbf156267812c3abca9fd9ff487c434ee832bc3b..d8abfb4a2b7a23905b42f0d39f78a8091ab92270 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.73 2000/07/04 06:11:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.74 2000/07/14 22:17:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,12 +87,12 @@ static int	_inv_getsize(Relation hreln, TupleDesc hdesc, Relation ireln);
 LargeObjectDesc *
 inv_create(int flags)
 {
-	int			file_oid;
 	LargeObjectDesc *retval;
+	Oid			file_oid;
 	Relation	r;
 	Relation	indr;
 	TupleDesc	tupdesc;
-	AttrNumber	attNums[1];
+	IndexInfo  *indexInfo;
 	Oid			classObjectId[1];
 	char		objname[NAMEDATALEN];
 	char		indname[NAMEDATALEN];
@@ -109,17 +109,13 @@ inv_create(int flags)
 	sprintf(indname, "xinx%u", file_oid);
 
 	if (RelnameFindRelid(objname) != InvalidOid)
-	{
 		elog(ERROR,
 		  "internal error: %s already exists -- cannot create large obj",
 			 objname);
-	}
 	if (RelnameFindRelid(indname) != InvalidOid)
-	{
 		elog(ERROR,
 		  "internal error: %s already exists -- cannot create large obj",
 			 indname);
-	}
 
 	/* this is pretty painful...  want a tuple descriptor */
 	tupdesc = CreateTemplateTupleDesc(2);
@@ -155,21 +151,25 @@ inv_create(int flags)
 
 	/*
 	 * Now create a btree index on the relation's olastbyte attribute to
-	 * make seeks go faster.  The hardwired constants are embarassing to
-	 * me, and are symptomatic of the pressure under which this code was
-	 * written.
-	 *
-	 * ok, mao, let's put in some symbolic constants - jolly
+	 * make seeks go faster.
 	 */
+	indexInfo = makeNode(IndexInfo);
+	indexInfo->ii_NumIndexAttrs = 1;
+	indexInfo->ii_NumKeyAttrs = 1;
+	indexInfo->ii_KeyAttrNumbers[0] = 1;
+	indexInfo->ii_Predicate = NULL;
+	indexInfo->ii_FuncOid = InvalidOid;
+	indexInfo->ii_Unique = false;
 
-	attNums[0] = 1;
 	classObjectId[0] = INT4_OPS_OID;
-	index_create(objname, indname, NULL, NULL, BTREE_AM_OID,
-				 1, &attNums[0], &classObjectId[0],
-				 (Node *) NULL, false, false, false, false);
+
+	index_create(objname, indname, indexInfo,
+				 BTREE_AM_OID, classObjectId,
+				 false, false, false);
 
 	/* make the index visible in this transaction */
 	CommandCounterIncrement();
+
 	indr = index_openr(indname);
 
 	if (!RelationIsValid(indr))
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index c1cc688e8f61d430e80ba8f464dbde8e3d03155e..a7cb0ecac4998bfce06754fcfdffb318c20157ed 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.106 2000/07/05 23:11:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.107 2000/07/14 22:17:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1065,6 +1065,7 @@ IndexedAccessMethodInitialize(Relation relation)
 		support = (RegProcedure *) NULL;
 
 	IndexSupportInitialize(strategy, support,
+						   &relation->rd_uniqueindex,
 						   relation->rd_att->attrs[0]->attrelid,
 						   relation->rd_rel->relam,
 						   relamstrategies, relamsupport, natts);
diff --git a/src/include/access/funcindex.h b/src/include/access/funcindex.h
deleted file mode 100644
index 0555755aaab7f26585a3bce4044b88cd5ea9dfba..0000000000000000000000000000000000000000
--- a/src/include/access/funcindex.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * funcindex.h
- *
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: funcindex.h,v 1.9 2000/01/26 05:57:50 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef _FUNC_INDEX_INCLUDED_
-#define _FUNC_INDEX_INCLUDED_
-
-typedef struct
-{
-	int			nargs;
-	Oid			arglist[FUNC_MAX_ARGS];
-	Oid			procOid;
-	NameData	funcName;
-} FuncIndexInfo;
-
-typedef FuncIndexInfo *FuncIndexInfoPtr;
-
-/*
- * some marginally useful macro definitions
- */
-/* #define FIgetname(FINFO) (&((FINFO)->funcName.data[0]))*/
-#define FIgetname(FINFO) (FINFO)->funcName.data
-#define FIgetnArgs(FINFO) (FINFO)->nargs
-#define FIgetProcOid(FINFO) (FINFO)->procOid
-#define FIgetArg(FINFO, argnum) (FINFO)->arglist[argnum]
-#define FIgetArglist(FINFO) (FINFO)->arglist
-
-#define FIsetnArgs(FINFO, numargs) ((FINFO)->nargs = numargs)
-#define FIsetProcOid(FINFO, id) ((FINFO)->procOid = id)
-#define FIsetArg(FINFO, argnum, argtype) ((FINFO)->arglist[argnum] = argtype)
-
-#define FIisFunctionalIndex(FINFO) (FINFO->procOid != InvalidOid)
-
-#endif	 /* FUNCINDEX_H */
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index c7e0c5021b4b8b69bcaf97d2c788696aa79b5e7b..b62a979f051fe18fad6ba2b9c4492b770883b5d4 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -7,14 +7,13 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: genam.h,v 1.23 2000/01/26 05:57:50 momjian Exp $
+ * $Id: genam.h,v 1.24 2000/07/14 22:17:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GENAM_H
 #define GENAM_H
 
-#include "access/funcindex.h"
 #include "access/itup.h"
 #include "access/relscan.h"
 #include "access/sdir.h"
@@ -42,9 +41,6 @@ extern RetrieveIndexResult index_getnext(IndexScanDesc scan,
 extern RegProcedure index_cost_estimator(Relation relation);
 extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
 				uint16 procnum);
-extern Datum GetIndexValue(HeapTuple tuple, TupleDesc hTupDesc,
-			  int attOff, AttrNumber *attrNums, FuncIndexInfo *fInfo,
-			  bool *attNull);
 
 /* in genam.c */
 extern IndexScanDesc RelationGetIndexScan(Relation relation, bool scanFromEnd,
diff --git a/src/include/access/gist.h b/src/include/access/gist.h
index dd8f557e9ba975c128846b66816cb95f1dedcc67..1297b02ff019c7e25fc08ce8916a78a4224c699e 100644
--- a/src/include/access/gist.h
+++ b/src/include/access/gist.h
@@ -12,7 +12,6 @@
 #ifndef GIST_H
 #define GIST_H
 
-#include "access/funcindex.h"
 #include "access/itup.h"
 #include "access/relscan.h"
 #include "access/sdir.h"
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index aa461a75e2b40ad8e23eadf8bbfd060e08d0786d..17d3496dee084c90a18ff74210dcf15d5c12b584 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: hash.h,v 1.34 2000/06/19 03:54:35 tgl Exp $
+ * $Id: hash.h,v 1.35 2000/07/14 22:17:53 tgl Exp $
  *
  * NOTES
  *		modeled after Margo Seltzer's hash implementation for unix.
@@ -17,7 +17,6 @@
 #ifndef HASH_H
 #define HASH_H
 
-#include "access/funcindex.h"
 #include "access/itup.h"
 #include "access/relscan.h"
 #include "access/sdir.h"
diff --git a/src/include/access/istrat.h b/src/include/access/istrat.h
index 99d4901bcdc989fbe6732e7799632b094022b3ee..9178f8c410e49a7b92de9a287279eb24355f2c48 100644
--- a/src/include/access/istrat.h
+++ b/src/include/access/istrat.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: istrat.h,v 1.17 2000/06/08 22:37:36 momjian Exp $
+ * $Id: istrat.h,v 1.18 2000/07/14 22:17:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,9 +56,12 @@ extern StrategyNumber RelationGetStrategy(Relation relation,
 			   AttrNumber attributeNumber, StrategyEvaluation evaluation,
 					RegProcedure procedure);
 extern void IndexSupportInitialize(IndexStrategy indexStrategy,
-					   RegProcedure *indexSupport, Oid indexObjectId,
-			  Oid accessMethodObjectId, StrategyNumber maxStrategyNumber,
-		 StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber);
-
+								   RegProcedure *indexSupport,
+								   bool *isUnique,
+								   Oid indexObjectId,
+								   Oid accessMethodObjectId,
+								   StrategyNumber maxStrategyNumber,
+								   StrategyNumber maxSupportNumber,
+								   AttrNumber maxAttributeNumber);
 
 #endif	 /* ISTRAT_H */
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index e01cb7a31b628653f66234b1cb657c5d59c12a34..a5047729616ce140246533c24cda382f0338dafe 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: itup.h,v 1.24 2000/03/17 02:36:37 tgl Exp $
+ * $Id: itup.h,v 1.25 2000/07/14 22:17:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,18 +61,6 @@ typedef struct RetrieveIndexResultData
 typedef RetrieveIndexResultData *RetrieveIndexResult;
 
 
-/*-----------------
- * PredInfo -
- *	  used for partial indices
- *-----------------
- */
-typedef struct PredInfo
-{
-	Node	   *pred;
-	Node	   *oldPred;
-} PredInfo;
-
-
 /* ----------------
  *		externs
  * ----------------
diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index b3ddea19d5078918d6179a2f6ce52ffbf46cbb70..882ac3c7d1cfd68c16b276027c314f91e74e5d44 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -7,18 +7,21 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: bootstrap.h,v 1.18 2000/06/17 23:41:49 tgl Exp $
+ * $Id: bootstrap.h,v 1.19 2000/07/14 22:17:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef BOOTSTRAP_H
 #define BOOTSTRAP_H
 
-#include "access/funcindex.h"
 #include "access/itup.h"
+#include "nodes/execnodes.h"
 #include "utils/rel.h"
 
-#define MAXATTR 40				/* max. number of attributes in a relation */
+/* MAXATTR is the maximum number of attributes in a relation supported
+ * at bootstrap time (ie, the max possible in a system table).
+ */
+#define MAXATTR 40
 
 typedef struct hashnode
 {
@@ -35,10 +38,7 @@ extern int	DebugMode;
 
 extern int	BootstrapMain(int ac, char *av[]);
 
-extern void index_register(char *heap, char *ind,
-						   int natts, AttrNumber *attnos,
-						   FuncIndexInfo *finfo, PredInfo *predInfo,
-						   bool unique);
+extern void index_register(char *heap, char *ind, IndexInfo *indexInfo);
 
 extern void err_out(void);
 extern void InsertOneTuple(Oid objectid);
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 66b4f601be36d061065470636f7bdba0b998181e..e00b25e6f0758feb844a172ab5e2aa6455437360 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: index.h,v 1.28 2000/07/12 02:37:27 tgl Exp $
+ * $Id: index.h,v 1.29 2000/07/14 22:17:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,25 +27,24 @@ extern void InitIndexStrategy(int numatts,
 				  Oid accessMethodObjectId);
 
 extern void index_create(char *heapRelationName,
-			 char *indexRelationName,
-			 FuncIndexInfo *funcInfo,
-			 List *attributeList,
-			 Oid accessMethodObjectId,
-			 int numatts,
-			 AttrNumber *attNums,
-			 Oid *classObjectId,
-			 Node *predicate,
-			 bool islossy,
-			 bool unique,
-			 bool primary,
-			 bool allow_system_table_mods);
+						 char *indexRelationName,
+						 IndexInfo *indexInfo,
+						 Oid accessMethodObjectId,
+						 Oid *classObjectId,
+						 bool islossy,
+						 bool primary,
+						 bool allow_system_table_mods);
 
 extern void index_drop(Oid indexId);
 
-extern void FormIndexDatum(int numberOfAttributes,
-			   AttrNumber *attributeNumber, HeapTuple heapTuple,
-			   TupleDesc heapDescriptor, Datum *datum,
-			   char *nullv, FuncIndexInfoPtr fInfo);
+extern IndexInfo *BuildIndexInfo(HeapTuple indexTuple);
+
+extern void FormIndexDatum(IndexInfo *indexInfo,
+						   HeapTuple heapTuple,
+						   TupleDesc heapDescriptor,
+						   MemoryContext resultCxt,
+						   Datum *datum,
+						   char *nullv);
 
 extern void UpdateStats(Oid relid, long reltuples, bool inplace);
 extern bool IndexesAreActive(Oid relid, bool comfirmCommitted);
@@ -54,11 +53,7 @@ extern bool SetReindexProcessing(bool processing);
 extern bool IsReindexProcessing(void);
 
 extern void index_build(Relation heapRelation, Relation indexRelation,
-						int numberOfAttributes, AttrNumber *attributeNumber,
-						FuncIndexInfo *funcInfo, PredInfo *predInfo,
-						bool unique);
-
-extern bool IndexIsUnique(Oid indexId);
+						IndexInfo *indexInfo, Node *oldPred);
 
 extern bool reindex_index(Oid indexId, bool force);
 extern bool activate_indexes_of_a_table(Oid relid, bool activate);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index bd260a827b47440414a4c2d08f3538f148b486d3..538299773d96afc37d658779ff64758b926b9f50 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.146 2000/07/08 03:04:21 tgl Exp $
+ * $Id: pg_proc.h,v 1.147 2000/07/14 22:17:56 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -677,7 +677,7 @@ DATA(insert OID = 321 (  rtdelete		   PGUID 12 f t f t 2 f 23 "0 0" 100 0 0 100
 DESCR("r-tree(internal)");
 DATA(insert OID = 322 (  rtgettuple		   PGUID 12 f t f t 2 f 23 "0 0" 100 0 0 100  rtgettuple - ));
 DESCR("r-tree(internal)");
-DATA(insert OID = 323 (  rtbuild		   PGUID 12 f t f t 8 f 23 "0 0 0 0 0 0 0 0" 100 0 0 100  rtbuild - ));
+DATA(insert OID = 323 (  rtbuild		   PGUID 12 f t f t 5 f 23 "0 0 0 0 0" 100 0 0 100  rtbuild - ));
 DESCR("r-tree(internal)");
 DATA(insert OID = 324 (  rtbeginscan	   PGUID 12 f t f t 4 f 23 "0 0 0 0" 100 0 0 100  rtbeginscan - ));
 DESCR("r-tree(internal)");
@@ -706,7 +706,7 @@ DATA(insert OID = 336 (  btmarkpos		   PGUID 12 f t f t 1 f 23 "0" 100 0 0 100
 DESCR("btree(internal)");
 DATA(insert OID = 337 (  btrestrpos		   PGUID 12 f t f t 1 f 23 "0" 100 0 0 100  btrestrpos - ));
 DESCR("btree(internal)");
-DATA(insert OID = 338 (  btbuild		   PGUID 12 f t f t 8 f 23 "0 0 0 0 0 0 0 0" 100 0 0 100  btbuild - ));
+DATA(insert OID = 338 (  btbuild		   PGUID 12 f t f t 5 f 23 "0 0 0 0 0" 100 0 0 100  btbuild - ));
 DESCR("btree(internal)");
 
 DATA(insert OID = 339 (  poly_same		   PGUID 11 f t t t 2 f 16 "604 604" 100 0 1 0  poly_same - ));
@@ -810,7 +810,7 @@ DATA(insert OID = 446 (  hashmarkpos	   PGUID 12 f t f t 1 f 23 "0" 100 0 0 100
 DESCR("hash(internal)");
 DATA(insert OID = 447 (  hashrestrpos	   PGUID 12 f t f t 1 f 23 "0" 100 0 0 100  hashrestrpos - ));
 DESCR("hash(internal)");
-DATA(insert OID = 448 (  hashbuild		   PGUID 12 f t f t 8 f 23 "0 0 0 0 0 0 0 0" 100 0 0 100  hashbuild - ));
+DATA(insert OID = 448 (  hashbuild		   PGUID 12 f t f t 5 f 23 "0 0 0 0 0" 100 0 0 100  hashbuild - ));
 DESCR("hash(internal)");
 DATA(insert OID = 449 (  hashint2		   PGUID 12 f t t t 1 f 23 "21" 100 0 0 100  hashint2 - ));
 DESCR("hash");
@@ -1033,7 +1033,7 @@ DATA(insert OID = 780 (  gistmarkpos	   PGUID 12 f t f t 1 f 23 "0" 100 0 0 100
 DESCR("gist(internal)");
 DATA(insert OID = 781 (  gistrestrpos	   PGUID 12 f t f t 1 f 23 "0" 100 0 0 100  gistrestrpos - ));
 DESCR("gist(internal)");
-DATA(insert OID = 782 (  gistbuild		   PGUID 12 f t f t 8 f 23 "0 0 0 0 0 0 0 0" 100 0 0 100  gistbuild - ));
+DATA(insert OID = 782 (  gistbuild		   PGUID 12 f t f t 5 f 23 "0 0 0 0 0" 100 0 0 100  gistbuild - ));
 DESCR("gist(internal)");
 
 DATA(insert OID = 784 (  tintervaleq	   PGUID 12 f t f t 2 f 16 "704 704" 100 0 0 100	tintervaleq - ));
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index fed4c6a9a1691a544d14b3c51d9f9d5267a122c4..b42a8e6a17f8cec9fb9ff61b122a452b7258962f 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -7,17 +7,16 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: vacuum.h,v 1.31 2000/05/29 17:40:44 momjian Exp $
+ * $Id: vacuum.h,v 1.32 2000/07/14 22:17:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef VACUUM_H
 #define VACUUM_H
 
-#include "fmgr.h"
-#include "access/funcindex.h"
-#include "catalog/pg_index.h"
 #include "catalog/pg_attribute.h"
+#include "catalog/pg_index.h"
+#include "fmgr.h"
 #include "nodes/pg_list.h"
 #include "storage/itemptr.h"
 
@@ -54,14 +53,6 @@ typedef struct VacPageListData
 
 typedef VacPageListData *VacPageList;
 
-typedef struct
-{
-	FuncIndexInfo finfo;
-	FuncIndexInfo *finfoP;
-	Form_pg_index tform;
-	int			natts;
-} IndDesc;
-
 typedef struct
 {
 	Form_pg_attribute attr;
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 2c21dba9c237acfcc1735b41630a44e62a388878..62a887d754ba3c77a6a1d52e11fa88733fcd2112 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,39 +7,49 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.43 2000/07/12 02:37:32 tgl Exp $
+ * $Id: execnodes.h,v 1.44 2000/07/14 22:17:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef EXECNODES_H
 #define EXECNODES_H
 
-#include "access/funcindex.h"
 #include "access/relscan.h"
 #include "access/sdir.h"
 #include "executor/hashjoin.h"
 #include "executor/tuptable.h"
+#include "fmgr.h"
 #include "nodes/params.h"
 #include "nodes/primnodes.h"
 
 /* ----------------
  *	  IndexInfo information
  *
- *		this class holds the information saying what attributes
- *		are the key attributes for this index. -cim 10/15/89
- *
- *		NumKeyAttributes		number of key attributes for this index
- *		KeyAttributeNumbers		array of attribute numbers used as keys
- *		Predicate				partial-index predicate for this index
+ *		this class holds the information needed to construct new index
+ *		entries for a particular index.  Used for both index_build and
+ *		retail creation of index entries.
+ *
+ *		NumIndexAttrs		number of columns in this index
+ *							(1 if a func. index, else same as NumKeyAttrs)
+ *		NumKeyAttrs			number of key attributes for this index
+ *							(ie, number of attrs from underlying relation)
+ *		KeyAttrNumbers		underlying-rel attribute numbers used as keys
+ *		Predicate			partial-index predicate, or NULL if none
+ *		FuncOid				OID of function, or InvalidOid if not f. index
+ *		FuncInfo			fmgr lookup data for function, if FuncOid valid
+ *		Unique				is it a unique index?
  * ----------------
  */
 typedef struct IndexInfo
 {
 	NodeTag		type;
-	int			ii_NumKeyAttributes;
-	AttrNumber *ii_KeyAttributeNumbers;
-	FuncIndexInfoPtr ii_FuncIndexInfo;
+	int			ii_NumIndexAttrs;
+	int			ii_NumKeyAttrs;
+	AttrNumber	ii_KeyAttrNumbers[INDEX_MAX_KEYS];
 	Node	   *ii_Predicate;
+	Oid			ii_FuncOid;
+	FmgrInfo	ii_FuncInfo;
+	bool		ii_Unique;
 } IndexInfo;
 
 /* ----------------
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 121012d7fd4984bf61683ec5fcfec04e9bd8a2f5..c90ba3c5ee0900e0d2ceb860dac9176bfe685211 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rel.h,v 1.39 2000/06/30 07:04:03 tgl Exp $
+ * $Id: rel.h,v 1.40 2000/07/14 22:18:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,6 +92,7 @@ typedef struct RelationData
 	bool		rd_isnailed;	/* rel is nailed in cache */
 	bool		rd_unlinked;	/* rel already unlinked or not created yet */
 	bool		rd_indexfound;	/* true if rd_indexlist is valid */
+	bool		rd_uniqueindex;	/* true if rel is a UNIQUE index */
 	Form_pg_am	rd_am;			/* AM tuple */
 	Form_pg_class rd_rel;		/* RELATION tuple */
 	Oid			rd_id;			/* relation's object id */