diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index b21f408e2cb5a4a9d49591275c8a80a63e62157f..755a7512723e695d9a061408de0f1d3085253c87 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.116 2000/06/17 04:56:36 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.117 2000/06/17 21:48:39 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1105,6 +1105,7 @@ index_create(char *heapRelationName,
 void
 index_drop(Oid indexId)
 {
+	Oid			heapId;
 	Relation	userHeapRelation;
 	Relation	userIndexRelation;
 	Relation	indexRelation;
@@ -1125,8 +1126,8 @@ index_drop(Oid indexId)
 	 *	else other backends will still see this index in pg_index.
 	 * ----------------
 	 */
-	userHeapRelation = heap_open(IndexGetRelation(indexId),
-								 AccessExclusiveLock);
+	heapId = IndexGetRelation(indexId);
+	userHeapRelation = heap_open(heapId, AccessExclusiveLock);
 
 	userIndexRelation = index_open(indexId);
 	LockRelation(userIndexRelation, AccessExclusiveLock);
@@ -1158,6 +1159,7 @@ index_drop(Oid indexId)
 	 */
 	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
 
+	/* Remove the pg_class tuple for the index itself */
 	tuple = SearchSysCacheTupleCopy(RELOID,
 									ObjectIdGetDatum(indexId),
 									0, 0, 0);
@@ -1166,6 +1168,23 @@ index_drop(Oid indexId)
 
 	heap_delete(relationRelation, &tuple->t_self, NULL);
 	heap_freetuple(tuple);
+
+	/*
+	 * Find the pg_class tuple for the owning relation.  We do not attempt
+	 * to clear relhasindex, since we are too lazy to test whether any other
+	 * indexes remain (the next VACUUM will fix it if necessary).  But we
+	 * must send out a shared-cache-inval notice on the owning relation
+	 * to ensure other backends update their relcache lists of indexes.
+	 */
+	tuple = SearchSysCacheTupleCopy(RELOID,
+									ObjectIdGetDatum(heapId),
+									0, 0, 0);
+
+	Assert(HeapTupleIsValid(tuple));
+
+	ImmediateInvalidateSharedHeapTuple(relationRelation, tuple);
+	heap_freetuple(tuple);
+
 	heap_close(relationRelation, RowExclusiveLock);
 
 	/* ----------------
@@ -1447,9 +1466,6 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
 	 */
 	if (pg_class_scan)
 	{
-
-		if (!IsBootstrapProcessingMode())
-			ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
 		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
 		rd_rel->relhasindex = hasindex;
 		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
@@ -1461,12 +1477,18 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
 
 		htup.t_self = tuple->t_self;
 		heap_fetch(pg_class, SnapshotNow, &htup, &buffer);
-		ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
 		rd_rel = (Form_pg_class) GETSTRUCT(&htup);
 		rd_rel->relhasindex = hasindex;
 		WriteBuffer(buffer);
 	}
 
+	/*
+	 * Send out a shared-cache-inval message so other backends notice the
+	 * update and fix their syscaches/relcaches.
+	 */
+	if (!IsBootstrapProcessingMode())
+		ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
+
 	if (!pg_class_scan)
 		heap_freetuple(tuple);
 	else
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index db20ca7372f155ee0d7ae12099cbc311852ffbe1..e29ed167963c0a8f3d008ac0b6910aa912a1c4b9 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.114 2000/06/15 03:32:07 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.115 2000/06/17 21:48:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,6 +32,7 @@
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/relcache.h"
 #include "utils/syscache.h"
 
 #ifdef MULTIBYTE
@@ -1081,78 +1082,43 @@ IsTypeByVal(Oid type)
  * Space for the array itself is palloc'ed.
  */
 
-typedef struct rel_list
-{
-	Oid			index_rel_oid;
-	struct rel_list *next;
-} RelationList;
-
 static void
 GetIndexRelations(Oid main_relation_oid,
 				  int *n_indices,
 				  Relation **index_rels)
 {
-	RelationList *head,
-			   *scan;
-	Relation	pg_index_rel;
-	HeapScanDesc scandesc;
-	Oid			index_relation_oid;
-	HeapTuple	tuple;
-	TupleDesc	tupDesc;
+	Relation	relation;
+	List	   *indexoidlist,
+			   *indexoidscan;
 	int			i;
-	bool		isnull;
 
-	pg_index_rel = heap_openr(IndexRelationName, AccessShareLock);
-	scandesc = heap_beginscan(pg_index_rel, 0, SnapshotNow, 0, NULL);
-	tupDesc = RelationGetDescr(pg_index_rel);
+	relation = heap_open(main_relation_oid, AccessShareLock);
+	indexoidlist = RelationGetIndexList(relation);
 
-	*n_indices = 0;
+	*n_indices = length(indexoidlist);
 
-	head = (RelationList *) palloc(sizeof(RelationList));
-	scan = head;
-	head->next = NULL;
+	if (*n_indices > 0)
+		*index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
+	else
+		*index_rels = NULL;
 
-	while (HeapTupleIsValid(tuple = heap_getnext(scandesc, 0)))
+	i = 0;
+	foreach(indexoidscan, indexoidlist)
 	{
+		Oid			indexoid = lfirsti(indexoidscan);
+		Relation	index = index_open(indexoid);
 
-		index_relation_oid = (Oid) DatumGetInt32(heap_getattr(tuple, 2,
-													  tupDesc, &isnull));
-		if (index_relation_oid == main_relation_oid)
-		{
-			scan->index_rel_oid = (Oid) DatumGetInt32(heap_getattr(tuple,
-												Anum_pg_index_indexrelid,
-													  tupDesc, &isnull));
-			(*n_indices)++;
-			scan->next = (RelationList *) palloc(sizeof(RelationList));
-			scan = scan->next;
-		}
-	}
-
-	heap_endscan(scandesc);
-	heap_close(pg_index_rel, AccessShareLock);
-
-	/* We cannot trust to relhasindex of the main_relation now, so... */
-	if (*n_indices == 0)
-		return;
-
-	*index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
-
-	for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
-	{
-		(*index_rels)[i] = index_open(scan->index_rel_oid);
 		/* see comments in ExecOpenIndices() in execUtils.c */
-		if ((*index_rels)[i] != NULL &&
-			((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID &&
-			((*index_rels)[i])->rd_rel->relam != HASH_AM_OID)
-			LockRelation((*index_rels)[i], AccessExclusiveLock);
+		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++;
 	}
 
-	for (i = 0, scan = head; i < *n_indices + 1; i++)
-	{
-		scan = head->next;
-		pfree(head);
-		head = scan;
-	}
+	freeList(indexoidlist);
+	heap_close(relation, AccessShareLock);
 }
 
 /*
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 31c96c7d6ab0b6dcec4f1bfde3976c9fa98f8008..f0d61aa112319f408f728c915118658097c24d62 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.29 2000/06/15 03:32:07 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.30 2000/06/17 21:48:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -221,6 +221,13 @@ DefineIndex(char *heapRelationName,
 					 lossy, unique, primary);
 	}
 
+	/*
+	 * We update the relation's pg_class tuple even if it already has
+	 * relhasindex = true.  This is needed to cause a shared-cache-inval
+	 * message to be sent for the pg_class tuple, which will cause other
+	 * backends to flush their relcache entries and in particular their
+	 * cached lists of the indexes for this relation.
+	 */
 	setRelhasindexInplace(relationId, true, false);
 }
 
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 1ee4e28f21096fdc288115fd819a5c9b0767cffb..5eed27387a72d220b530c6ef34a231a125ecd8ac 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.159 2000/05/29 17:40:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -72,7 +72,7 @@ static void update_relstats(Oid relid, int num_pages, int num_tuples, bool hasin
 static VacPage tid_reaped(ItemPointer itemptr, VacPageList vacpagelist);
 static void reap_page(VacPageList vacpagelist, VacPage vacpage);
 static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
-static void get_indices(Oid relid, int *nindices, Relation **Irel);
+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 void *vac_find_eq(void *bot, int nelem, int size, void *elm,
@@ -416,7 +416,7 @@ vacuum_rel(Oid relid, bool analyze)
 	/* Now open indices */
 	nindices = 0;
 	Irel = (Relation *) NULL;
-	get_indices(vacrelstats->relid, &nindices, &Irel);
+	get_indices(onerel, &nindices, &Irel);
 	if (!Irel)
 		reindex = false;
 	else if (!RelationGetForm(onerel)->relhasindex)
@@ -2331,80 +2331,33 @@ CommonSpecialPortalIsOpen(void)
 	return CommonSpecialPortalInUse;
 }
 
+
 static void
-get_indices(Oid relid, int *nindices, Relation **Irel)
+get_indices(Relation relation, int *nindices, Relation **Irel)
 {
-	Relation	pgindex;
-	Relation	irel;
-	TupleDesc	tupdesc;
-	HeapTuple	tuple;
-	HeapScanDesc scan;
-	Datum		d;
-	int			i,
-				k;
-	bool		n;
-	ScanKeyData key;
-	Oid		   *ioid;
-
-	*nindices = i = 0;
-
-	ioid = (Oid *) palloc(10 * sizeof(Oid));
-
-	/* prepare a heap scan on the pg_index relation */
-	pgindex = heap_openr(IndexRelationName, AccessShareLock);
-	tupdesc = RelationGetDescr(pgindex);
-
-	ScanKeyEntryInitialize(&key, 0x0, Anum_pg_index_indrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(relid));
-
-	scan = heap_beginscan(pgindex, false, SnapshotNow, 1, &key);
-
-	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
-	{
-		d = heap_getattr(tuple, Anum_pg_index_indexrelid,
-						 tupdesc, &n);
-		i++;
-		if (i % 10 == 0)
-			ioid = (Oid *) repalloc(ioid, (i + 10) * sizeof(Oid));
-		ioid[i - 1] = DatumGetObjectId(d);
-	}
+	List	   *indexoidlist,
+			   *indexoidscan;
+	int			i;
 
-	heap_endscan(scan);
-	heap_close(pgindex, AccessShareLock);
+	indexoidlist = RelationGetIndexList(relation);
 
-	if (i == 0)
-	{							/* No one index found */
-		pfree(ioid);
-		return;
-	}
+	*nindices = length(indexoidlist);
 
-	if (Irel != (Relation **) NULL)
-		*Irel = (Relation *) palloc(i * sizeof(Relation));
+	if (*nindices > 0)
+		*Irel = (Relation *) palloc(*nindices * sizeof(Relation));
+	else
+		*Irel = NULL;
 
-	for (k = 0; i > 0;)
+	i = 0;
+	foreach(indexoidscan, indexoidlist)
 	{
-		irel = index_open(ioid[--i]);
-		if (irel != (Relation) NULL)
-		{
-			if (Irel != (Relation **) NULL)
-				(*Irel)[k] = irel;
-			else
-				index_close(irel);
-			k++;
-		}
-		else
-			elog(NOTICE, "CAN'T OPEN INDEX %u - SKIP IT", ioid[i]);
-	}
-	*nindices = k;
-	pfree(ioid);
+		Oid			indexoid = lfirsti(indexoidscan);
 
-	if (Irel != (Relation **) NULL && *nindices == 0)
-	{
-		pfree(*Irel);
-		*Irel = (Relation *) NULL;
+		(*Irel)[i] = index_open(indexoid);
+		i++;
 	}
 
+	freeList(indexoidlist);
 }
 
 
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 8fbb4be6cb0dc3991121babad1034af200b5b9ff..f80fe9abab719bdb7227b10f4d125b7ee7622882 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.117 2000/06/15 04:09:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.118 2000/06/17 21:48:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -735,7 +735,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 		 */
 		if (resultRelationDesc->rd_rel->relhasindex &&
 			operation != CMD_DELETE)
-			ExecOpenIndices(resultRelationOid, resultRelationInfo);
+			ExecOpenIndices(resultRelationInfo);
 
 		estate->es_result_relation_info = resultRelationInfo;
 	}
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 852ff5872ce0fe9cd260f2fc8d41033a7a1a16f8..c1b6e5d79a38a2393e2f2b8598782be65e421ea7 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.59 2000/06/15 04:09:52 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.60 2000/06/17 21:48:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,8 @@
 #include "miscadmin.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/relcache.h"
+#include "utils/syscache.h"
 
 static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP,
 					AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
@@ -657,7 +659,7 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
 	 *	check parameters
 	 * ----------------
 	 */
-	if (numAttsOutP == NULL && attsOutP == NULL)
+	if (numAttsOutP == NULL || attsOutP == NULL)
 	{
 		elog(DEBUG, "ExecGetIndexKeyInfo: %s",
 		"invalid parameters: numAttsOutP and attsOutP must be non-NULL");
@@ -724,115 +726,112 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
 /* ----------------------------------------------------------------
  *		ExecOpenIndices
  *
- *		Here we scan the pg_index relation to find indices
- *		associated with a given heap relation oid.	Since we
- *		don't know in advance how many indices we have, we
- *		form lists containing the information we need from
- *		pg_index and then process these lists.
+ *		Find the indices associated with a result relation, open them,
+ *		and save information about them in the result RelationInfo.
  *
- *		Note: much of this code duplicates effort done by
- *		the IndexCatalogInformation function in plancat.c
- *		because IndexCatalogInformation is poorly written.
+ *		At entry, caller has already opened and locked
+ *		resultRelationInfo->ri_RelationDesc.
  *
- *		It would be much better if the functionality provided
- *		by this function and IndexCatalogInformation was
- *		in the form of a small set of orthogonal routines..
- *		If you are trying to understand this, I suggest you
- *		look at the code to IndexCatalogInformation and
- *		FormIndexTuple.. -cim 9/27/89
+ *		This used to be horribly ugly code, and slow too because it
+ *		did a sequential scan of pg_index.  Now we rely on the relcache
+ *		to cache a list of the OIDs of the indices associated with any
+ *		specific relation, and we use the pg_index syscache to get the
+ *		entries we need from pg_index.
  * ----------------------------------------------------------------
  */
 void
-ExecOpenIndices(Oid resultRelationOid,
-				RelationInfo *resultRelationInfo)
+ExecOpenIndices(RelationInfo *resultRelationInfo)
 {
-	Relation	indexRd;
-	HeapScanDesc indexSd;
-	ScanKeyData key;
-	HeapTuple	tuple;
-	Form_pg_index indexStruct;
-	Oid			indexOid;
-	List	   *oidList;
-	List	   *nkeyList;
-	List	   *keyList;
-	List	   *fiList;
-	char	   *predString;
-	List	   *predList;
-	List	   *indexoid;
-	List	   *numkeys;
-	List	   *indexkeys;
-	List	   *indexfuncs;
-	List	   *indexpreds;
-	int			len;
-
+	Relation	resultRelation = resultRelationInfo->ri_RelationDesc;
+	List	   *indexoidlist,
+			   *indexoidscan;
+	int			len,
+				i;
 	RelationPtr relationDescs;
 	IndexInfo **indexInfoArray;
-	FuncIndexInfoPtr fInfoP;
-	int			numKeyAtts;
-	AttrNumber *indexKeyAtts;
-	PredInfo   *predicate;
-	int			i;
 
 	resultRelationInfo->ri_NumIndices = 0;
-	if (!RelationGetForm(resultRelationInfo->ri_RelationDesc)->relhasindex)
+
+	/* checks for disabled indexes */
+	if (! RelationGetForm(resultRelation)->relhasindex)
 		return;
 	if (IsIgnoringSystemIndexes() &&
-		IsSystemRelationName(RelationGetRelationName(resultRelationInfo->ri_RelationDesc)))
+		IsSystemRelationName(RelationGetRelationName(resultRelation)))
 		return;
+
 	/* ----------------
-	 *	open pg_index
+	 *	 Get cached list of index OIDs
 	 * ----------------
 	 */
-	indexRd = heap_openr(IndexRelationName, AccessShareLock);
+	indexoidlist = RelationGetIndexList(resultRelation);
+	len = length(indexoidlist);
+	if (len == 0)
+		return;
 
 	/* ----------------
-	 *	form a scan key
+	 *	 allocate space for result arrays
 	 * ----------------
 	 */
-	ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(resultRelationOid));
+	relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
+	indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
+
+	resultRelationInfo->ri_NumIndices = len;
+	resultRelationInfo->ri_IndexRelationDescs = relationDescs;
+	resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
 
 	/* ----------------
-	 *	scan the index relation, looking for indices for our
-	 *	result relation..
+	 *	 For each index, open the index relation and save pg_index info.
 	 * ----------------
 	 */
-	indexSd = heap_beginscan(indexRd,	/* scan desc */
-							 false,		/* scan backward flag */
-							 SnapshotNow,		/* NOW snapshot */
-							 1, /* number scan keys */
-							 &key);		/* scan keys */
-
-	oidList = NIL;
-	nkeyList = NIL;
-	keyList = NIL;
-	fiList = NIL;
-	predList = NIL;
-
-	while (HeapTupleIsValid(tuple = heap_getnext(indexSd, 0)))
+	i = 0;
+	foreach(indexoidscan, indexoidlist)
 	{
+		Oid			indexOid = lfirsti(indexoidscan);
+		Relation	indexDesc;
+		HeapTuple	indexTuple;
+		Form_pg_index indexStruct;
+		int			numKeyAtts;
+		AttrNumber *indexKeyAtts;
+		FuncIndexInfoPtr fInfoP;
+		PredInfo   *predicate;
+		IndexInfo  *ii;
 
 		/* ----------------
-		 *	For each index relation we find, extract the information
-		 *	we need and store it in a list..
+		 * Open (and lock, if necessary) the index relation
 		 *
-		 *	first get the oid of the index relation from the tuple
+		 * Hack for not btree and hash indices: they use relation
+		 * level exclusive locking on update (i.e. - they are not
+		 * ready for MVCC) and so we have to exclusively lock
+		 * indices here to prevent deadlocks if we will scan them
+		 * - index_beginscan places AccessShareLock, indices
+		 * update methods don't use locks at all. We release this
+		 * lock in ExecCloseIndices. Note, that hashes use page
+		 * level locking - i.e. are not deadlock-free, - let's
+		 * them be on their way -:)) vadim 03-12-1998
 		 * ----------------
 		 */
-		indexStruct = (Form_pg_index) GETSTRUCT(tuple);
-		indexOid = indexStruct->indexrelid;
+		indexDesc = index_open(indexOid);
+
+		if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
+			indexDesc->rd_rel->relam != HASH_AM_OID)
+			LockRelation(indexDesc, AccessExclusiveLock);
 
 		/* ----------------
-		 * allocate space for functional index information.
+		 *	Get the pg_index tuple for the index
 		 * ----------------
 		 */
-		fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
+		indexTuple = SearchSysCacheTupleCopy(INDEXRELID,
+											 ObjectIdGetDatum(indexOid),
+											 0, 0, 0);
+		if (!HeapTupleIsValid(indexTuple))
+			elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
+		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 
 		/* ----------------
-		 *	next get the index key information from the tuple
+		 *	extract the index key information from the tuple
 		 * ----------------
 		 */
+		fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
 		ExecGetIndexKeyInfo(indexStruct,
 							&numKeyAtts,
 							&indexKeyAtts,
@@ -844,6 +843,8 @@ ExecOpenIndices(Oid resultRelationOid,
 		 */
 		if (VARSIZE(&indexStruct->indpred) != 0)
 		{
+			char	   *predString;
+
 			predString = textout(&indexStruct->indpred);
 			predicate = (PredInfo *) stringToNode(predString);
 			pfree(predString);
@@ -851,152 +852,21 @@ ExecOpenIndices(Oid resultRelationOid,
 		else
 			predicate = NULL;
 
-		/* ----------------
-		 *	save the index information into lists
-		 * ----------------
-		 */
-		oidList = lconsi(indexOid, oidList);
-		nkeyList = lconsi(numKeyAtts, nkeyList);
-		keyList = lcons(indexKeyAtts, keyList);
-		fiList = lcons(fInfoP, fiList);
-		predList = lcons(predicate, predList);
-	}
-
-	/* ----------------
-	 *	we have the info we need so close the pg_index relation..
-	 * ----------------
-	 */
-	heap_endscan(indexSd);
-	heap_close(indexRd, AccessShareLock);
-
-	/* ----------------
-	 *	Now that we've collected the index information into three
-	 *	lists, we open the index relations and store the descriptors
-	 *	and the key information into arrays.
-	 * ----------------
-	 */
-	len = length(oidList);
-	if (len > 0)
-	{
-		/* ----------------
-		 *	 allocate space for relation descs
-		 * ----------------
-		 */
-		CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
-		relationDescs = (RelationPtr)
-			palloc(len * sizeof(Relation));
-
-		/* ----------------
-		 *	 initialize index info array
-		 * ----------------
-		 */
-		CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
-		indexInfoArray = (IndexInfo **)
-			palloc(len * sizeof(IndexInfo *));
-
-		for (i = 0; i < len; i++)
-		{
-			IndexInfo  *ii = makeNode(IndexInfo);
+		/* Save the index info */
+		ii = makeNode(IndexInfo);
+		ii->ii_NumKeyAttributes = numKeyAtts;
+		ii->ii_KeyAttributeNumbers = indexKeyAtts;
+		ii->ii_FuncIndexInfo = fInfoP;
+		ii->ii_Predicate = (Node *) predicate;
 
-			ii->ii_NumKeyAttributes = 0;
-			ii->ii_KeyAttributeNumbers = (AttrNumber *) NULL;
-			ii->ii_FuncIndexInfo = (FuncIndexInfoPtr) NULL;
-			ii->ii_Predicate = NULL;
-			indexInfoArray[i] = ii;
-		}
+		heap_freetuple(indexTuple);
 
-		/* ----------------
-		 *	 attempt to open each of the indices.  If we succeed,
-		 *	 then store the index relation descriptor into the
-		 *	 relation descriptor array.
-		 * ----------------
-		 */
-		i = 0;
-		foreach(indexoid, oidList)
-		{
-			Relation	indexDesc;
-
-			indexOid = lfirsti(indexoid);
-			indexDesc = index_open(indexOid);
-			if (indexDesc != NULL)
-			{
-				relationDescs[i++] = indexDesc;
-
-				/*
-				 * Hack for not btree and hash indices: they use relation
-				 * level exclusive locking on update (i.e. - they are not
-				 * ready for MVCC) and so we have to exclusively lock
-				 * indices here to prevent deadlocks if we will scan them
-				 * - index_beginscan places AccessShareLock, indices
-				 * update methods don't use locks at all. We release this
-				 * lock in ExecCloseIndices. Note, that hashes use page
-				 * level locking - i.e. are not deadlock-free, - let's
-				 * them be on their way -:)) vadim 03-12-1998
-				 */
-				if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
-					indexDesc->rd_rel->relam != HASH_AM_OID)
-					LockRelation(indexDesc, AccessExclusiveLock);
-			}
-		}
-
-		/* ----------------
-		 *	 store the relation descriptor array and number of
-		 *	 descs into the result relation info.
-		 * ----------------
-		 */
-		resultRelationInfo->ri_NumIndices = i;
-		resultRelationInfo->ri_IndexRelationDescs = relationDescs;
-
-		/* ----------------
-		 *	 store the index key information collected in our
-		 *	 lists into the index info array
-		 * ----------------
-		 */
-		i = 0;
-		foreach(numkeys, nkeyList)
-		{
-			numKeyAtts = lfirsti(numkeys);
-			indexInfoArray[i++]->ii_NumKeyAttributes = numKeyAtts;
-		}
-
-		i = 0;
-		foreach(indexkeys, keyList)
-		{
-			indexKeyAtts = (AttrNumber *) lfirst(indexkeys);
-			indexInfoArray[i++]->ii_KeyAttributeNumbers = indexKeyAtts;
-		}
-
-		i = 0;
-		foreach(indexfuncs, fiList)
-		{
-			FuncIndexInfoPtr fiP = (FuncIndexInfoPtr) lfirst(indexfuncs);
-
-			indexInfoArray[i++]->ii_FuncIndexInfo = fiP;
-		}
-
-		i = 0;
-		foreach(indexpreds, predList)
-			indexInfoArray[i++]->ii_Predicate = lfirst(indexpreds);
-		/* ----------------
-		 *	 store the index info array into relation info
-		 * ----------------
-		 */
-		resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
+		relationDescs[i] = indexDesc;
+		indexInfoArray[i] = ii;
+		i++;
 	}
 
-	/* ----------------
-	 *	All done,  resultRelationInfo now contains complete information
-	 *	on the indices associated with the result relation.
-	 * ----------------
-	 */
-
-	/* should free oidList, nkeyList and keyList here */
-	/* OK - let's do it   -jolly */
-	freeList(oidList);
-	freeList(nkeyList);
-	freeList(keyList);
-	freeList(fiList);
-	freeList(predList);
+	freeList(indexoidlist);
 }
 
 /* ----------------------------------------------------------------
@@ -1035,91 +905,6 @@ ExecCloseIndices(RelationInfo *resultRelationInfo)
 	 */
 }
 
-/* ----------------------------------------------------------------
- *		ExecFormIndexTuple
- *
- *		Most of this code is cannabilized from DefaultBuild().
- *		As said in the comments for ExecOpenIndices, most of
- *		this functionality should be rearranged into a proper
- *		set of routines..
- * ----------------------------------------------------------------
- */
-#ifdef NOT_USED
-IndexTuple
-ExecFormIndexTuple(HeapTuple heapTuple,
-				   Relation heapRelation,
-				   Relation indexRelation,
-				   IndexInfo *indexInfo)
-{
-	IndexTuple	indexTuple;
-	TupleDesc	heapDescriptor;
-	TupleDesc	indexDescriptor;
-	Datum	   *datum;
-	char	   *nulls;
-
-	int			numberOfAttributes;
-	AttrNumber *keyAttributeNumbers;
-	FuncIndexInfoPtr fInfoP;
-
-	/* ----------------
-	 *	get information from index info structure
-	 * ----------------
-	 */
-	numberOfAttributes = indexInfo->ii_NumKeyAttributes;
-	keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
-	fInfoP = indexInfo->ii_FuncIndexInfo;
-
-	/* ----------------
-	 *	datum and null are arrays in which we collect the index attributes
-	 *	when forming a new index tuple.
-	 * ----------------
-	 */
-	CXT1_printf("ExecFormIndexTuple: context is %d\n", CurrentMemoryContext);
-	datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
-	nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
-
-	/* ----------------
-	 *	get the tuple descriptors from the relations so we know
-	 *	how to form the index tuples..
-	 * ----------------
-	 */
-	heapDescriptor = RelationGetDescr(heapRelation);
-	indexDescriptor = RelationGetDescr(indexRelation);
-
-	/* ----------------
-	 *	FormIndexDatum fills in its datum and null parameters
-	 *	with attribute information taken from the given heap tuple.
-	 * ----------------
-	 */
-	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 */
-
-	indexTuple = index_formtuple(indexDescriptor,
-								 datum,
-								 nulls);
-
-	/* ----------------
-	 *	free temporary arrays
-	 *
-	 *	XXX should store these in the IndexInfo instead of allocating
-	 *	   and freeing on every insertion, but efficency here is not
-	 *	   that important and FormIndexTuple is wasteful anyways..
-	 *	   -cim 9/27/89
-	 * ----------------
-	 */
-	pfree(nulls);
-	pfree(datum);
-
-	return indexTuple;
-}
-
-#endif
-
 /* ----------------------------------------------------------------
  *		ExecInsertIndexTuples
  *
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 51e7d4027e6242c78df59bf8794dc0037a2909a4..5e34e806e32d3d43abc66118c1dca8beba2978e1 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.33 2000/06/15 04:09:52 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.34 2000/06/17 21:48:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -285,7 +285,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
 				 * indices, but how to tell that here?
 				 */
 				if (rri->ri_RelationDesc->rd_rel->relhasindex)
-					ExecOpenIndices(reloid, rri);
+					ExecOpenIndices(rri);
 			}
 
 			/*
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 12b2f26bd845448b1da78bb81e8ca9fd7eda5f24..64b47072f71a07d2c4d802cd872672551a6e437f 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,11 +9,7 @@
  *
  *
  * IDENTIFICATION
-<<<<<<< plancat.c
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.56 2000/06/15 03:32:16 momjian Exp $
-=======
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.56 2000/06/15 03:32:16 momjian Exp $
->>>>>>> 1.53
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.57 2000/06/17 21:48:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,6 +28,7 @@
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/relcache.h"
 #include "utils/syscache.h"
 #include "catalog/catalog.h"
 #include "miscadmin.h"
@@ -54,7 +51,7 @@ relation_info(Query *root, Index relid,
 	Form_pg_class relation;
 
 	relationTuple = SearchSysCacheTuple(RELOID,
-									  ObjectIdGetDatum(relationObjectId),
+										ObjectIdGetDatum(relationObjectId),
 										0, 0, 0);
 	if (!HeapTupleIsValid(relationTuple))
 		elog(ERROR, "relation_info: Relation %u not found",
@@ -81,33 +78,40 @@ relation_info(Query *root, Index relid,
 List *
 find_secondary_indexes(Query *root, Index relid)
 {
-	List	   *indexes = NIL;
+	List	   *indexinfos = NIL;
+	List	   *indexoidlist,
+			   *indexoidscan;
 	Oid			indrelid = getrelid(relid, root->rtable);
 	Relation	relation;
-	HeapScanDesc scan;
-	ScanKeyData indexKey;
-	HeapTuple	indexTuple;
-
-	/* Scan pg_index for tuples describing indexes of this rel */
-	relation = heap_openr(IndexRelationName, AccessShareLock);
 
-	ScanKeyEntryInitialize(&indexKey, 0,
-						   Anum_pg_index_indrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(indrelid));
+	/*
+	 * We used to scan pg_index directly, but now the relcache offers
+	 * a cached list of OID indexes for each relation.  So, get that list
+	 * and then use the syscache to obtain pg_index entries.
+	 */
+	relation = heap_open(indrelid, AccessShareLock);
+	indexoidlist = RelationGetIndexList(relation);
 
-	scan = heap_beginscan(relation, 0, SnapshotNow,
-						  1, &indexKey);
-
-	while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
+	foreach(indexoidscan, indexoidlist)
 	{
-		Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
-		IndexOptInfo *info = makeNode(IndexOptInfo);
+		Oid		indexoid = lfirsti(indexoidscan);
+		HeapTuple	indexTuple;
+		Form_pg_index index;
+		IndexOptInfo *info;
 		int			i;
 		Relation	indexRelation;
 		Oid			relam;
 		uint16		amorderstrategy;
 
+		indexTuple = SearchSysCacheTupleCopy(INDEXRELID,
+											 ObjectIdGetDatum(indexoid),
+											 0, 0, 0);
+		if (!HeapTupleIsValid(indexTuple))
+			elog(ERROR, "find_secondary_indexes: index %u not found",
+				 indexoid);
+		index = (Form_pg_index) GETSTRUCT(indexTuple);
+		info = makeNode(IndexOptInfo);
+
 		/*
 		 * Need to make these arrays large enough to be sure there is a
 		 * terminating 0 at the end of each one.
@@ -172,13 +176,17 @@ find_secondary_indexes(Query *root, Index relid)
 			}
 		}
 
-		indexes = lcons(info, indexes);
+		heap_freetuple(indexTuple);
+
+		indexinfos = lcons(info, indexinfos);
 	}
 
-	heap_endscan(scan);
+	freeList(indexoidlist);
+
+	/* XXX keep the lock here? */
 	heap_close(relation, AccessShareLock);
 
-	return indexes;
+	return indexinfos;
 }
 
 /*
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index dbd8faf319b60b05ac067cce55275578f466cab6..8e23170ac8a9ae3b1412dc6605fa7532e283991b 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: analyze.c,v 1.147 2000/06/12 19:40:40 momjian Exp $
+ *	$Id: analyze.c,v 1.148 2000/06/17 21:48:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,8 @@
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/relcache.h"
+#include "utils/syscache.h"
 
 void		CheckSelectForUpdate(Query *qry);	/* no points for style... */
 
@@ -2003,13 +2005,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 {
 	Relation	pkrel;
 	Form_pg_attribute *pkrel_attrs;
-	Relation	indexRd;
-	HeapScanDesc indexSd;
-	ScanKeyData key;
-	HeapTuple	indexTup;
+	List	   *indexoidlist,
+			   *indexoidscan;
 	Form_pg_index indexStruct = NULL;
-	Ident	   *pkattr;
-	int			pkattno;
 	int			i;
 
 	/* ----------
@@ -2023,37 +2021,37 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 	pkrel_attrs = pkrel->rd_att->attrs;
 
 	/* ----------
-	 * Open pg_index and begin a scan for all indices defined on
-	 * the referenced table
+	 * Get the list of index OIDs for the table from the relcache,
+	 * and look up each one in the pg_index syscache until we find one
+	 * marked primary key (hopefully there isn't more than one such).
 	 * ----------
 	 */
-	indexRd = heap_openr(IndexRelationName, AccessShareLock);
-	ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(pkrel->rd_id));
-	indexSd = heap_beginscan(indexRd,	/* scan desc */
-							 false,		/* scan backward flag */
-							 SnapshotNow,		/* NOW snapshot */
-							 1, /* number scan keys */
-							 &key);		/* scan keys */
+	indexoidlist = RelationGetIndexList(pkrel);
 
-	/* ----------
-	 * Fetch the index with indisprimary == true
-	 * ----------
-	 */
-	while (HeapTupleIsValid(indexTup = heap_getnext(indexSd, 0)))
+	foreach(indexoidscan, indexoidlist)
 	{
-		indexStruct = (Form_pg_index) GETSTRUCT(indexTup);
-
+		Oid		indexoid = lfirsti(indexoidscan);
+		HeapTuple	indexTuple;
+
+		indexTuple = SearchSysCacheTuple(INDEXRELID,
+										 ObjectIdGetDatum(indexoid),
+										 0, 0, 0);
+		if (!HeapTupleIsValid(indexTuple))
+			elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
+				 indexoid);
+		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 		if (indexStruct->indisprimary)
 			break;
+		indexStruct = NULL;
 	}
 
+	freeList(indexoidlist);
+
 	/* ----------
 	 * Check that we found it
 	 * ----------
 	 */
-	if (!HeapTupleIsValid(indexTup))
+	if (indexStruct == NULL)
 		elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
 			 fkconstraint->pktable_name);
 
@@ -2064,8 +2062,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 	 */
 	for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
 	{
-		pkattno = indexStruct->indkey[i];
-		pkattr = (Ident *) makeNode(Ident);
+		int			pkattno = indexStruct->indkey[i];
+		Ident	   *pkattr = makeNode(Ident);
+
 		pkattr->name = nameout(&(pkrel_attrs[pkattno - 1]->attname));
 		pkattr->indirection = NIL;
 		pkattr->isRel = false;
@@ -2073,12 +2072,6 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 		fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
 	}
 
-	/* ----------
-	 * End index scan and close relations
-	 * ----------
-	 */
-	heap_endscan(indexSd);
-	heap_close(indexRd, AccessShareLock);
 	heap_close(pkrel, AccessShareLock);
 }
 
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index f86f4eef778f6b659a127289015ed23b072b6857..4fe3e35b1e86dc5f635284b09b41c1f2a236039d 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.100 2000/06/17 04:56:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.101 2000/06/17 21:48:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,7 @@
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_attrdef.h"
+#include "catalog/pg_index.h"
 #include "catalog/pg_log.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_relcheck.h"
@@ -1063,16 +1064,14 @@ formrdesc(char *relationName,
 		  FormData_pg_attribute *att)
 {
 	Relation	relation;
-	Size		len;
 	u_int		i;
 
 	/* ----------------
 	 *	allocate new relation desc
 	 * ----------------
 	 */
-	len = sizeof(RelationData);
-	relation = (Relation) palloc(len);
-	MemSet((char *) relation, 0, len);
+	relation = (Relation) palloc(sizeof(RelationData));
+	MemSet((char *) relation, 0, sizeof(RelationData));
 
 	/* ----------------
 	 *	don't open the unix file yet..
@@ -1090,9 +1089,8 @@ formrdesc(char *relationName,
 	 *	initialize relation tuple form
 	 * ----------------
 	 */
-	relation->rd_rel = (Form_pg_class)
-		palloc((Size) (sizeof(*relation->rd_rel)));
-	MemSet(relation->rd_rel, 0, sizeof(FormData_pg_class));
+	relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
+	MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);
 	strcpy(RelationGetPhysicalRelationName(relation), relationName);
 
 	/* ----------------
@@ -1414,6 +1412,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 		pfree(relation->rd_istrat);
 	if (relation->rd_support)
 		pfree(relation->rd_support);
+	freeList(relation->rd_indexlist);
 
 	/*
 	 * If we're really done with the relcache entry, blow it away. But if
@@ -2075,6 +2074,125 @@ RelCheckFetch(Relation relation)
 	heap_close(rcrel, AccessShareLock);
 }
 
+/*
+ * RelationGetIndexList -- get a list of OIDs of indexes on this relation
+ *
+ * The index list is created only if someone requests it.  We scan pg_index
+ * to find relevant indexes, and add the list to the relcache entry so that
+ * we won't have to compute it again.  Note that shared cache inval of a
+ * relcache entry will delete the old list and set rd_indexfound to false,
+ * so that we must recompute the index list on next request.  This handles
+ * creation or deletion of an index.
+ *
+ * Since shared cache inval causes the relcache's copy of the list to go away,
+ * we return a copy of the list palloc'd in the caller's context.  The caller
+ * may freeList() the returned list after scanning it.  This is necessary
+ * since the caller will typically be doing syscache lookups on the relevant
+ * indexes, and syscache lookup could cause SI messages to be processed!
+ */
+List *
+RelationGetIndexList(Relation relation)
+{
+	Relation	indrel;
+	Relation	irel = (Relation) NULL;
+	ScanKeyData skey;
+	IndexScanDesc sd = (IndexScanDesc) NULL;
+	HeapScanDesc hscan = (HeapScanDesc) NULL;
+	bool		hasindex;
+	List	   *result;
+	MemoryContext oldcxt;
+
+	/* Quick exit if we already computed the list. */
+	if (relation->rd_indexfound)
+		return listCopy(relation->rd_indexlist);
+
+	/* Prepare to scan pg_index for entries having indrelid = this rel. */
+	indrel = heap_openr(IndexRelationName, AccessShareLock);
+	hasindex = (indrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
+	if (hasindex)
+	{
+		irel = index_openr(IndexIndrelidIndex);
+		ScanKeyEntryInitialize(&skey,
+							   (bits16) 0x0,
+							   (AttrNumber) 1,
+							   (RegProcedure) F_OIDEQ,
+							   ObjectIdGetDatum(RelationGetRelid(relation)));
+		sd = index_beginscan(irel, false, 1, &skey);
+	}
+	else
+	{
+		ScanKeyEntryInitialize(&skey,
+							   (bits16) 0x0,
+							   (AttrNumber) Anum_pg_index_indrelid,
+							   (RegProcedure) F_OIDEQ,
+							   ObjectIdGetDatum(RelationGetRelid(relation)));
+		hscan = heap_beginscan(indrel, false, SnapshotNow, 1, &skey);
+	}
+
+	/*
+	 * We build the list we intend to return (in the caller's context) while
+	 * doing the scan.  After successfully completing the scan, we copy that
+	 * list into the relcache entry.  This avoids cache-context memory leakage
+	 * if we get some sort of error partway through.
+	 */
+	result = NIL;
+	
+	for (;;)
+	{
+		HeapTupleData tuple;
+		HeapTuple	htup;
+		Buffer		buffer;
+		Form_pg_index index;
+
+		if (hasindex)
+		{
+			RetrieveIndexResult indexRes;
+
+			indexRes = index_getnext(sd, ForwardScanDirection);
+			if (!indexRes)
+				break;
+			tuple.t_self = indexRes->heap_iptr;
+			tuple.t_datamcxt = NULL;
+			tuple.t_data = NULL;
+			heap_fetch(indrel, SnapshotNow, &tuple, &buffer);
+			pfree(indexRes);
+			if (tuple.t_data == NULL)
+				continue;
+			htup = &tuple;
+		}
+		else
+		{
+			htup = heap_getnext(hscan, 0);
+			if (!HeapTupleIsValid(htup))
+				break;
+		}
+
+		index = (Form_pg_index) GETSTRUCT(htup);
+
+		result = lappendi(result, index->indexrelid);
+
+		if (hasindex)
+			ReleaseBuffer(buffer);
+	}
+
+	if (hasindex)
+	{
+		index_endscan(sd);
+		index_close(irel);
+	}
+	else
+		heap_endscan(hscan);
+	heap_close(indrel, AccessShareLock);
+
+	/* Now we can save the completed list in the relcache entry. */
+	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	relation->rd_indexlist = listCopy(result);
+	relation->rd_indexfound = true;
+	MemoryContextSwitchTo(oldcxt);
+
+	return result;
+}
+
 /*
  *	init_irels(), write_irels() -- handle special-case initialization of
  *								   index relation descriptors.
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 3c85762dfafadb12b1e1f2f0e2650165c4565efa..6d196eb5a2c7fef942211ca2a4eefcca440c7cda 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.43 2000/05/29 01:59:11 tgl Exp $
+ * $Id: executor.h,v 1.44 2000/06/17 21:48:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -142,8 +142,7 @@ extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
 								CommonScanState *csstate);
 extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc);
 
-extern void ExecOpenIndices(Oid resultRelationOid,
-				RelationInfo *resultRelationInfo);
+extern void ExecOpenIndices(RelationInfo *resultRelationInfo);
 extern void ExecCloseIndices(RelationInfo *resultRelationInfo);
 extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
 					  EState *estate, bool is_update);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 1bd2f10376ea0a9ba53691876bb3747c755a6a38..2a585c0e7ea2b710e30ce39d65cb29efdc58f230 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.36 2000/04/12 17:16:55 momjian Exp $
+ * $Id: rel.h,v 1.37 2000/06/17 21:49:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,14 +92,15 @@ typedef struct RelationData
 	bool		rd_isnailed;	/* rel is nailed in cache */
 	bool		rd_isnoname;	/* rel has no name */
 	bool		rd_unlinked;	/* rel already unlinked or not created yet */
+	bool		rd_indexfound;	/* true if rd_indexlist is valid */
 	Form_pg_am	rd_am;			/* AM tuple */
 	Form_pg_class rd_rel;		/* RELATION tuple */
 	Oid			rd_id;			/* relation's object id */
-	LockInfoData rd_lockInfo;	/* lock manager's info for locking
-								 * relation */
+	List	   *rd_indexlist;	/* list of OIDs of indexes on relation */
+	LockInfoData rd_lockInfo;	/* lock mgr's info for locking relation */
 	TupleDesc	rd_att;			/* tuple descriptor */
 	RuleLock   *rd_rules;		/* rewrite rules */
-	IndexStrategy rd_istrat;
+	IndexStrategy rd_istrat;	/* info needed if rel is an index */
 	RegProcedure *rd_support;
 	TriggerDesc *trigdesc;		/* Trigger info, or NULL if rel has none */
 } RelationData;
@@ -138,13 +139,15 @@ typedef Relation *RelationPtr;
  * RelationSetReferenceCount
  *		Sets relation reference count.
  */
-#define RelationSetReferenceCount(relation,count) ((relation)->rd_refcnt = (count))
+#define RelationSetReferenceCount(relation,count) \
+	((relation)->rd_refcnt = (count))
 
 /*
  * RelationIncrementReferenceCount
  *		Increments relation reference count.
  */
-#define RelationIncrementReferenceCount(relation) ((relation)->rd_refcnt += 1)
+#define RelationIncrementReferenceCount(relation) \
+	((relation)->rd_refcnt += 1)
 
 /*
  * RelationDecrementReferenceCount
@@ -199,7 +202,8 @@ typedef Relation *RelationPtr;
  *
  *	  Returns a Relation Name
  */
-#define RelationGetPhysicalRelationName(relation) (NameStr((relation)->rd_rel->relname))
+#define RelationGetPhysicalRelationName(relation) \
+	(NameStr((relation)->rd_rel->relname))
 
 /*
  * RelationGetNumberOfAttributes
@@ -224,9 +228,11 @@ typedef Relation *RelationPtr;
  */
 #define RelationGetIndexStrategy(relation) ((relation)->rd_istrat)
 
-
+/*
+ * Routines in utils/cache/rel.c
+ */
 extern void RelationSetIndexSupport(Relation relation,
-						IndexStrategy strategy,
-						RegProcedure *support);
+									IndexStrategy strategy,
+									RegProcedure *support);
 
 #endif	 /* REL_H */
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index 073c846e4b304ce46b61beac96b98bf7c05c1534..aee58942a64d26fbf7cc55b6108af3d4b2042063 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relcache.h,v 1.19 2000/01/31 04:35:57 tgl Exp $
+ * $Id: relcache.h,v 1.20 2000/06/17 21:49:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,13 +19,20 @@
 /*
  * relation lookup routines
  */
-extern Relation RelationIdCacheGetRelation(Oid relationId);
 extern Relation RelationIdGetRelation(Oid relationId);
 extern Relation RelationNameGetRelation(const char *relationName);
 
+/* finds an existing cache entry, but won't make a new one */
+extern Relation RelationIdCacheGetRelation(Oid relationId);
+
 extern void RelationClose(Relation relation);
 extern void RelationForgetRelation(Oid rid);
 
+/*
+ * Routines to compute/retrieve additional cached information
+ */
+extern List *RelationGetIndexList(Relation relation);
+
 /*
  * Routines for flushing/rebuilding relcache entries in various scenarios
  */