From 6bfe64032efd043f80a495a495331dcfc2d9f05c Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 14 Jul 2000 22:18:02 +0000
Subject: [PATCH] Cleanup of code for creating index entries.  Functional
 indexes with pass-by-ref data types --- eg, an index on lower(textfield) ---
 no longer leak memory during index creation or update.  Clean up a lot of
 redundant code ... did you know that copy, vacuum, truncate, reindex, extend
 index, and bootstrap each basically duplicated the main executor's logic for
 extracting information about an index and preparing index entries? Functional
 indexes should be a little faster now too, due to removal of repeated
 function lookups. CREATE INDEX 'opt_type' clause is deimplemented by these
 changes, but I haven't removed it from the parser yet (need to merge with
 Thomas' latest change set first).

---
 src/backend/access/gist/gist.c             | 154 ++---
 src/backend/access/hash/hash.c             |  90 +--
 src/backend/access/index/indexam.c         |  55 +-
 src/backend/access/index/istrat.c          |  15 +-
 src/backend/access/nbtree/nbtree.c         | 105 ++--
 src/backend/access/rtree/rtree.c           | 129 ++--
 src/backend/bootstrap/bootparse.y          |   3 +-
 src/backend/bootstrap/bootscanner.l        |   3 +-
 src/backend/bootstrap/bootstrap.c          |  67 +--
 src/backend/catalog/heap.c                 |  82 +--
 src/backend/catalog/index.c                | 666 +++++++++------------
 src/backend/catalog/indexing.c             |  80 +--
 src/backend/commands/cluster.c             |  66 +-
 src/backend/commands/command.c             |  21 +-
 src/backend/commands/copy.c                | 241 ++------
 src/backend/commands/indexcmds.c           | 312 ++++------
 src/backend/commands/vacuum.c              | 110 ++--
 src/backend/executor/execUtils.c           | 209 ++-----
 src/backend/storage/large_object/inv_api.c |  32 +-
 src/backend/utils/cache/relcache.c         |   3 +-
 src/include/access/funcindex.h             |  43 --
 src/include/access/genam.h                 |   6 +-
 src/include/access/gist.h                  |   1 -
 src/include/access/hash.h                  |   3 +-
 src/include/access/istrat.h                |  13 +-
 src/include/access/itup.h                  |  14 +-
 src/include/bootstrap/bootstrap.h          |  14 +-
 src/include/catalog/index.h                |  39 +-
 src/include/catalog/pg_proc.h              |  10 +-
 src/include/commands/vacuum.h              |  15 +-
 src/include/nodes/execnodes.h              |  32 +-
 src/include/utils/rel.h                    |   3 +-
 32 files changed, 900 insertions(+), 1736 deletions(-)
 delete mode 100644 src/include/access/funcindex.h

diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 28c547ffe69..640c1898860 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 354d4985723..cb740bbde9e 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 2d1504238de..dc18b0d3b77 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 fc7ac6dcb14..d6a966bcd44 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 3d8ea1a70a8..b174d303176 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 badff1ee21b..583baa534a3 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 4c13aafc0eb..cf3cd1b280b 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 125ea516f17..ed68c92ac28 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 1c52d098a1a..c3cf9371724 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 08b5e64c53d..b5334de15ed 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 41d747b0dbf..2cbcb91ac06 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 deb016e4a04..c2980f6fefc 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 38539707cd8..5c176254d66 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 6648e66f4e3..be24c696a7c 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 355b218e640..52100e92dd9 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 efe8a44180a..6ede4f51c12 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 71682baa8cd..ee0ebeb4bb7 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 daa40dccf75..39e3d5cd48b 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 cbf15626781..d8abfb4a2b7 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 c1cc688e8f6..a7cb0ecac49 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 0555755aaab..00000000000
--- 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 c7e0c5021b4..b62a979f051 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 dd8f557e9ba..1297b02ff01 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 aa461a75e2b..17d3496dee0 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 99d4901bcdc..9178f8c410e 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 e01cb7a31b6..a5047729616 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 b3ddea19d50..882ac3c7d1c 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 66b4f601be3..e00b25e6f07 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 bd260a827b4..538299773d9 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 fed4c6a9a16..b42a8e6a17f 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 2c21dba9c23..62a887d754b 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 121012d7fd4..c90ba3c5ee0 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 */
-- 
GitLab