diff --git a/contrib/miscutil/misc_utils.c b/contrib/miscutil/misc_utils.c
index 75184439717c37eb42f006a62794a73b3136abee..d9237bd9dbba10c4e478877a16306c2501406247 100644
--- a/contrib/miscutil/misc_utils.c
+++ b/contrib/miscutil/misc_utils.c
@@ -89,9 +89,8 @@ active_listeners(text *relname)
 	int			ourpid = getpid();
 	char		listen_name[NAMEDATALEN];
 
-	lRel = heap_openr(ListenerRelationName);
+	lRel = heap_openr(ListenerRelationName, AccessShareLock);
 	tdesc = RelationGetDescr(lRel);
-	LockRelation(lRel, AccessShareLock);
 
 	if (relname && (VARSIZE(relname) > VARHDRSZ)) {
 		len = MIN(VARSIZE(relname)-VARHDRSZ, NAMEDATALEN-1);
@@ -110,19 +109,14 @@ active_listeners(text *relname)
 	{
 		d = heap_getattr(lTuple, Anum_pg_listener_pid, tdesc, &isnull);
 		pid = DatumGetInt32(d);
-#ifdef HAVE_KILL
 		if ((pid == ourpid) || (kill(pid, SIGTSTP) == 0)) {
 			/* elog(NOTICE, "%d ok", pid); */
 			count++;
 		}
-#else
-		count++;
-#endif
 	}
 	heap_endscan(sRel);
 
-	UnlockRelation(lRel, AccessShareLock);
-	heap_close(lRel);
+	heap_close(lRel, AccessShareLock);
 
 	return count;
 }
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 3211134742362f54af412aa1ddca2750317b70b5..0535fd6278db7d52c4ab2b57e0a6248f7caef76f 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.44 1999/07/19 02:06:15 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.45 1999/09/18 19:05:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@
 #include "catalog/index.h"
 #include "catalog/pg_index.h"
 #include "executor/executor.h"
+#include "miscadmin.h"
 #include "utils/syscache.h"
 
 
@@ -88,8 +89,6 @@ gistbuild(Relation heap,
 	TupleTableSlot *slot;
 
 #endif
-	Oid			hrelid,
-				irelid;
 	Node	   *pred,
 			   *oldPred;
 	GISTSTATE	giststate;
@@ -271,28 +270,31 @@ gistbuild(Relation heap,
 	}
 
 	/*
-	 * Since we just inted the tuples in the heap, we update its stats in
-	 * pg_relation to guarantee that the planner takes advantage of the
-	 * index we just created.  UpdateStats() does a
-	 * CommandinterIncrement(), which flushes changed entries from the
-	 * system relcache.  The act of constructing an index changes these
-	 * heap and index tuples in the system catalogs, so they need to be
-	 * flushed.  We close them to guarantee that they will be.
+	 * Since we just counted the tuples in the heap, we update its stats
+	 * in pg_class to guarantee that the planner takes advantage of the
+	 * index we just created.  But, only update statistics during
+	 * normal index definitions, not for indices on system catalogs
+	 * created during bootstrap processing.  We must close the relations
+	 * before updating statistics to guarantee that the relcache entries
+	 * are flushed when we increment the command counter in UpdateStats().
+	 * But we do not release any locks on the relations; those will be
+	 * held until end of transaction.
 	 */
-
-	hrelid = RelationGetRelid(heap);
-	irelid = RelationGetRelid(index);
-	heap_close(heap);
-	index_close(index);
-
-	UpdateStats(hrelid, nh, true);
-	UpdateStats(irelid, ni, false);
-
-	if (oldPred != NULL)
+	if (IsNormalProcessingMode())
 	{
-		if (ni == nh)
-			pred = NULL;
-		UpdateIndexPredicate(irelid, oldPred, pred);
+		Oid		hrelid = RelationGetRelid(heap);
+		Oid		irelid = RelationGetRelid(index);
+
+		heap_close(heap, NoLock);
+		index_close(index);
+		UpdateStats(hrelid, nh, true);
+		UpdateStats(irelid, ni, false);
+		if (oldPred != NULL)
+		{
+			if (ni == nh)
+				pred = NULL;
+			UpdateIndexPredicate(irelid, oldPred, pred);
+		}
 	}
 
 	/* be tidy */
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 1130367b65de3c057ec8ca2566ab9447cbe4bc02..6e729008e85b70abea3200becb47eb6672458076 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.30 1999/07/17 20:16:38 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.31 1999/09/18 19:05:52 tgl Exp $
  *
  * NOTES
  *	  This file contains only the public interface routines.
@@ -66,8 +66,6 @@ hashbuild(Relation heap,
 	TupleTableSlot *slot;
 
 #endif
-	Oid			hrelid,
-				irelid;
 	Node	   *pred,
 			   *oldPred;
 
@@ -232,17 +230,20 @@ hashbuild(Relation heap,
 	/*
 	 * Since we just counted the tuples in the heap, we update its stats
 	 * in pg_class to guarantee that the planner takes advantage of the
-	 * index we just created. Finally, only update statistics during
+	 * index we just created.  But, only update statistics during
 	 * normal index definitions, not for indices on system catalogs
 	 * created during bootstrap processing.  We must close the relations
-	 * before updatings statistics to guarantee that the relcache entries
+	 * before updating statistics to guarantee that the relcache entries
 	 * are flushed when we increment the command counter in UpdateStats().
+	 * But we do not release any locks on the relations; those will be
+	 * held until end of transaction.
 	 */
 	if (IsNormalProcessingMode())
 	{
-		hrelid = RelationGetRelid(heap);
-		irelid = RelationGetRelid(index);
-		heap_close(heap);
+		Oid		hrelid = RelationGetRelid(heap);
+		Oid		irelid = RelationGetRelid(index);
+
+		heap_close(heap, NoLock);
 		index_close(index);
 		UpdateStats(hrelid, nhtups, true);
 		UpdateStats(irelid, nitups, false);
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index d8dc24c41f0a4502f04f00c879a6ab7b1e88a5d5..092a23cc0ec8dc48cffe013af73a0c840d7c5d3d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.53 1999/07/19 07:07:18 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.54 1999/09/18 19:05:58 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -486,15 +486,20 @@ heapgettup(Relation relation,
 /* ----------------
  *		heap_open - open a heap relation by relationId
  *
- *		presently the relcache routines do all the work we need
- *		to open/close heap relations.
+ *		If lockmode is "NoLock", no lock is obtained on the relation,
+ *		and the caller must check for a NULL return value indicating
+ *		that no such relation exists.
+ *		Otherwise, an error is raised if the relation does not exist,
+ *		and the specified kind of lock is obtained on the relation.
  * ----------------
  */
 Relation
-heap_open(Oid relationId)
+heap_open(Oid relationId, LOCKMODE lockmode)
 {
 	Relation	r;
 
+	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+
 	/* ----------------
 	 *	increment access statistics
 	 * ----------------
@@ -502,26 +507,41 @@ heap_open(Oid relationId)
 	IncrHeapAccessStat(local_open);
 	IncrHeapAccessStat(global_open);
 
-	r = (Relation) RelationIdGetRelation(relationId);
+	/* The relcache does all the real work... */
+	r = RelationIdGetRelation(relationId);
 
+	/* Under no circumstances will we return an index as a relation. */
 	if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
 		elog(ERROR, "%s is an index relation", r->rd_rel->relname.data);
 
+	if (lockmode == NoLock)
+		return r;				/* caller must check RelationIsValid! */
+
+	if (! RelationIsValid(r))
+		elog(ERROR, "Relation %u does not exist", relationId);
+
+	LockRelation(r, lockmode);
+
 	return r;
 }
 
 /* ----------------
  *		heap_openr - open a heap relation by name
  *
- *		presently the relcache routines do all the work we need
- *		to open/close heap relations.
+ *		If lockmode is "NoLock", no lock is obtained on the relation,
+ *		and the caller must check for a NULL return value indicating
+ *		that no such relation exists.
+ *		Otherwise, an error is raised if the relation does not exist,
+ *		and the specified kind of lock is obtained on the relation.
  * ----------------
  */
 Relation
-heap_openr(char *relationName)
+heap_openr(char *relationName, LOCKMODE lockmode)
 {
 	Relation	r;
 
+	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+
 	/* ----------------
 	 *	increment access statistics
 	 * ----------------
@@ -529,24 +549,37 @@ heap_openr(char *relationName)
 	IncrHeapAccessStat(local_openr);
 	IncrHeapAccessStat(global_openr);
 
+	/* The relcache does all the real work... */
 	r = RelationNameGetRelation(relationName);
 
+	/* Under no circumstances will we return an index as a relation. */
 	if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
 		elog(ERROR, "%s is an index relation", r->rd_rel->relname.data);
 
+	if (lockmode == NoLock)
+		return r;				/* caller must check RelationIsValid! */
+
+	if (! RelationIsValid(r))
+		elog(ERROR, "Relation '%s' does not exist", relationName);
+
+	LockRelation(r, lockmode);
+
 	return r;
 }
 
 /* ----------------
  *		heap_close - close a heap relation
  *
- *		presently the relcache routines do all the work we need
- *		to open/close heap relations.
+ *		If lockmode is not "NoLock", we first release the specified lock.
+ *		Note that it is often sensible to hold a lock beyond heap_close;
+ *		in that case, the lock is released automatically at xact end.
  * ----------------
  */
 void
-heap_close(Relation relation)
+heap_close(Relation relation, LOCKMODE lockmode)
 {
+	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+
 	/* ----------------
 	 *	increment access statistics
 	 * ----------------
@@ -554,6 +587,10 @@ heap_close(Relation relation)
 	IncrHeapAccessStat(local_close);
 	IncrHeapAccessStat(global_close);
 
+	if (lockmode != NoLock)
+		UnlockRelation(relation, lockmode);
+
+	/* The relcache does the real work... */
 	RelationClose(relation);
 }
 
@@ -582,21 +619,29 @@ heap_beginscan(Relation relation,
 	 *	sanity checks
 	 * ----------------
 	 */
-	if (RelationIsValid(relation) == false)
+	if (! RelationIsValid(relation))
 		elog(ERROR, "heap_beginscan: !RelationIsValid(relation)");
 
-	LockRelation(relation, AccessShareLock);
-
-	/* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */
-	if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
-		snapshot = SnapshotSelf;
-
 	/* ----------------
 	 *	increment relation ref count while scanning relation
 	 * ----------------
 	 */
 	RelationIncrementReferenceCount(relation);
 
+	/* ----------------
+	 *	Acquire AccessShareLock for the duration of the scan
+	 *
+	 *	Note: we could get an SI inval message here and consequently have
+	 *	to rebuild the relcache entry.  The refcount increment above
+	 *	ensures that we will rebuild it and not just flush it...
+	 * ----------------
+	 */
+	LockRelation(relation, AccessShareLock);
+
+	/* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */
+	if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
+		snapshot = SnapshotSelf;
+
 	/* ----------------
 	 *	allocate and initialize scan descriptor
 	 * ----------------
@@ -683,15 +728,19 @@ heap_endscan(HeapScanDesc scan)
 	 */
 	unpinscan(scan);
 
+	/* ----------------
+	 *	Release AccessShareLock acquired by heap_beginscan()
+	 * ----------------
+	 */
+	UnlockRelation(scan->rs_rd, AccessShareLock);
+
 	/* ----------------
 	 *	decrement relation reference count and free scan descriptor storage
 	 * ----------------
 	 */
 	RelationDecrementReferenceCount(scan->rs_rd);
 
-	UnlockRelation(scan->rs_rd, AccessShareLock);
-
-	pfree(scan);				/* XXX */
+	pfree(scan);
 }
 
 /* ----------------
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 869e5e1e690354b0a9920f38e2be7311487e3361..6ad242c0c39a5cdbb15dd53bda76ff442c5bdcfd 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.35 1999/07/16 04:58:28 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.36 1999/09/18 19:06:04 tgl Exp $
  *
  * INTERFACE ROUTINES
  *		index_open		- open an index relation by relationId
@@ -129,26 +129,49 @@
  *		index_open - open an index relation by relationId
  *
  *		presently the relcache routines do all the work we need
- *		to open/close index relations.
+ *		to open/close index relations.  However, callers of index_open
+ *		expect it to succeed, so we need to check for a failure return.
+ *
+ *		Note: we acquire no lock on the index.  An AccessShareLock is
+ *		acquired by index_beginscan (and released by index_endscan).
  * ----------------
  */
 Relation
 index_open(Oid relationId)
 {
-	return RelationIdGetRelation(relationId);
+	Relation	r;
+
+	r = RelationIdGetRelation(relationId);
+
+	if (! RelationIsValid(r))
+		elog(ERROR, "Index %u does not exist", relationId);
+
+	if (r->rd_rel->relkind != RELKIND_INDEX)
+		elog(ERROR, "%s is not an index relation", r->rd_rel->relname.data);
+
+	return r;
 }
 
 /* ----------------
  *		index_openr - open a index relation by name
  *
- *		presently the relcache routines do all the work we need
- *		to open/close index relations.
+ *		As above, but lookup by name instead of OID.
  * ----------------
  */
 Relation
 index_openr(char *relationName)
 {
-	return RelationNameGetRelation(relationName);
+	Relation	r;
+
+	r = RelationNameGetRelation(relationName);
+
+	if (! RelationIsValid(r))
+		elog(ERROR, "Index '%s' does not exist", relationName);
+
+	if (r->rd_rel->relkind != RELKIND_INDEX)
+		elog(ERROR, "%s is not an index relation", r->rd_rel->relname.data);
+
+	return r;
 }
 
 /* ----------------
@@ -223,6 +246,16 @@ index_beginscan(Relation relation,
 	RELATION_CHECKS;
 	GET_REL_PROCEDURE(beginscan, ambeginscan);
 
+	RelationIncrementReferenceCount(relation);
+
+	/* ----------------
+	 *	Acquire AccessShareLock for the duration of the scan
+	 *
+	 *	Note: we could get an SI inval message here and consequently have
+	 *	to rebuild the relcache entry.  The refcount increment above
+	 *	ensures that we will rebuild it and not just flush it...
+	 * ----------------
+	 */
 	LockRelation(relation, AccessShareLock);
 
 	scandesc = (IndexScanDesc)
@@ -260,7 +293,11 @@ index_endscan(IndexScanDesc scan)
 
 	fmgr(procedure, scan);
 
+	/* Release lock and refcount acquired by index_beginscan */
+
 	UnlockRelation(scan->relation, AccessShareLock);
+
+	RelationDecrementReferenceCount(scan->relation);
 }
 
 /* ----------------
diff --git a/src/backend/access/index/istrat.c b/src/backend/access/index/istrat.c
index 1cdaadbc0c39fb5ec053d21598a7502526793879..cab6e5846091fb20434b094f37d5b8342a225d27 100644
--- a/src/backend/access/index/istrat.c
+++ b/src/backend/access/index/istrat.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.35 1999/07/16 04:58:28 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.36 1999/09/18 19:06:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -558,7 +558,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 							   F_OIDEQ,
 							   ObjectIdGetDatum(indexObjectId));
 
-		relation = heap_openr(IndexRelationName);
+		relation = heap_openr(IndexRelationName, AccessShareLock);
 		scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
 		tuple = heap_getnext(scan, 0);
 	}
@@ -591,7 +591,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 	if (IsBootstrapProcessingMode())
 	{
 		heap_endscan(scan);
-		heap_close(relation);
+		heap_close(relation, AccessShareLock);
 	}
 
 	/* if support routines exist for this access method, load them */
@@ -604,7 +604,8 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 		ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
 							   F_OIDEQ, 0);
 
-		relation = heap_openr(AccessMethodProcedureRelationName);
+		relation = heap_openr(AccessMethodProcedureRelationName,
+							  AccessShareLock);
 
 		for (attributeNumber = 1; attributeNumber <= maxAttributeNumber;
 			 attributeNumber++)
@@ -631,7 +632,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 
 			heap_endscan(scan);
 		}
-		heap_close(relation);
+		heap_close(relation, AccessShareLock);
 	}
 
 	ScanKeyEntryInitialize(&entry[0], 0,
@@ -643,8 +644,8 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 						   Anum_pg_amop_amopclaid,
 						   F_OIDEQ, 0);
 
-	relation = heap_openr(AccessMethodOperatorRelationName);
-	operatorRelation = heap_openr(OperatorRelationName);
+	relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
+	operatorRelation = heap_openr(OperatorRelationName, AccessShareLock);
 
 	for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
 		 attributeNumber--)
@@ -676,8 +677,8 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 		heap_endscan(scan);
 	}
 
-	heap_close(operatorRelation);
-	heap_close(relation);
+	heap_close(operatorRelation, AccessShareLock);
+	heap_close(relation, AccessShareLock);
 }
 
 /* ----------------
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index c97273f10f0cc0b528f3eb5a3dddfc217351f273..11f527fc3bad21b3b632e6a9efddc999a9ea5fa8 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.45 1999/07/17 20:16:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.46 1999/09/18 19:06:10 tgl Exp $
  *
  * NOTES
  *	  This file contains only the public interface routines.
@@ -74,8 +74,6 @@ btbuild(Relation heap,
 	TupleTableSlot *slot = (TupleTableSlot *) NULL;
 
 #endif
-	Oid			hrelid,
-				irelid;
 	Node	   *pred,
 			   *oldPred;
 	void	   *spool = (void *) NULL;
@@ -301,17 +299,20 @@ btbuild(Relation heap,
 	/*
 	 * Since we just counted the tuples in the heap, we update its stats
 	 * in pg_class to guarantee that the planner takes advantage of the
-	 * index we just created. Finally, only update statistics during
+	 * index we just created.  But, only update statistics during
 	 * normal index definitions, not for indices on system catalogs
 	 * created during bootstrap processing.  We must close the relations
-	 * before updatings statistics to guarantee that the relcache entries
+	 * before updating statistics to guarantee that the relcache entries
 	 * are flushed when we increment the command counter in UpdateStats().
+	 * But we do not release any locks on the relations; those will be
+	 * held until end of transaction.
 	 */
 	if (IsNormalProcessingMode())
 	{
-		hrelid = RelationGetRelid(heap);
-		irelid = RelationGetRelid(index);
-		heap_close(heap);
+		Oid		hrelid = RelationGetRelid(heap);
+		Oid		irelid = RelationGetRelid(index);
+
+		heap_close(heap, NoLock);
 		index_close(index);
 		UpdateStats(hrelid, nhtups, true);
 		UpdateStats(irelid, nitups, false);
diff --git a/src/backend/access/rtree/rtree.c b/src/backend/access/rtree/rtree.c
index 37da716df1d553b0415afd8cf911c90d14e07932..133bbdbc032c9a965d653cfbdd6c1279b65556a7 100644
--- a/src/backend/access/rtree/rtree.c
+++ b/src/backend/access/rtree/rtree.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.36 1999/07/17 20:16:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.37 1999/09/18 19:06:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,7 @@
 #include "access/rtree.h"
 #include "catalog/index.h"
 #include "executor/executor.h"
+#include "miscadmin.h"
 #include "utils/geo_decls.h"
 
 
@@ -89,8 +90,6 @@ rtbuild(Relation heap,
 	TupleTableSlot *slot;
 
 #endif
-	Oid			hrelid,
-				irelid;
 	Node	   *pred,
 			   *oldPred;
 	RTSTATE		rtState;
@@ -248,27 +247,30 @@ rtbuild(Relation heap,
 
 	/*
 	 * Since we just counted the tuples in the heap, we update its stats
-	 * in pg_relation to guarantee that the planner takes advantage of the
-	 * index we just created.  UpdateStats() does a
-	 * CommandCounterIncrement(), which flushes changed entries from the
-	 * system relcache.  The act of constructing an index changes these
-	 * heap and index tuples in the system catalogs, so they need to be
-	 * flushed.  We close them to guarantee that they will be.
+	 * in pg_class to guarantee that the planner takes advantage of the
+	 * index we just created.  But, only update statistics during
+	 * normal index definitions, not for indices on system catalogs
+	 * created during bootstrap processing.  We must close the relations
+	 * before updating statistics to guarantee that the relcache entries
+	 * are flushed when we increment the command counter in UpdateStats().
+	 * But we do not release any locks on the relations; those will be
+	 * held until end of transaction.
 	 */
-
-	hrelid = RelationGetRelid(heap);
-	irelid = RelationGetRelid(index);
-	heap_close(heap);
-	index_close(index);
-
-	UpdateStats(hrelid, nh, true);
-	UpdateStats(irelid, ni, false);
-
-	if (oldPred != NULL)
+	if (IsNormalProcessingMode())
 	{
-		if (ni == nh)
-			pred = NULL;
-		UpdateIndexPredicate(irelid, oldPred, pred);
+		Oid		hrelid = RelationGetRelid(heap);
+		Oid		irelid = RelationGetRelid(index);
+
+		heap_close(heap, NoLock);
+		index_close(index);
+		UpdateStats(hrelid, nh, true);
+		UpdateStats(irelid, ni, false);
+		if (oldPred != NULL)
+		{
+			if (ni == nh)
+				pred = NULL;
+			UpdateIndexPredicate(irelid, oldPred, pred);
+		}
 	}
 
 	/* be tidy */
diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c
index 1f44fb357ac3bc3052deeeabcbc933d288e33240..b26243b4257f8f4536766f07cdf556fc502fd2fe 100644
--- a/src/backend/access/transam/transam.c
+++ b/src/backend/access/transam/transam.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.31 1999/08/08 20:12:52 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.32 1999/09/18 19:06:21 tgl Exp $
  *
  * NOTES
  *	  This file contains the high level access-method interface to the
@@ -405,8 +405,11 @@ InitializeTransactionLog(void)
 	 *	 (these are created by amiint so they are guaranteed to exist)
 	 * ----------------
 	 */
-	logRelation = heap_openr(LogRelationName);
-	VariableRelation = heap_openr(VariableRelationName);
+	logRelation = heap_openr(LogRelationName, NoLock);
+	Assert(logRelation != NULL);
+	VariableRelation = heap_openr(VariableRelationName, NoLock);
+	Assert(VariableRelation != NULL);
+
 	/* ----------------
 	 *	 XXX TransactionLogUpdate requires that LogRelation
 	 *	 is valid so we temporarily set it so we can initialize
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 135912e97de58ec2b4490557b2d4091d561ea339..989b506bb7ffac8c6927f3567b487b228740c535 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.24 1999/07/15 23:03:03 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.25 1999/09/18 19:06:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -441,7 +441,7 @@ GetNewObjectId(Oid *oid_return) /* place to return the new object id */
 		 * ----------------
 		 */
 		if (!RelationIsValid(VariableRelation))
-			VariableRelation = heap_openr(VariableRelationName);
+			VariableRelation = heap_openr(VariableRelationName, NoLock);
 
 		/* ----------------
 		 *		get a new block of prefetched object ids.
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 8db37d0a081d1b379aa10b1d399d4833666821b4..18d9567ab898adeaf2dcf59dd193f0fed7e2c803 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -7,7 +7,7 @@
  * Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.66 1999/07/19 02:27:04 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.67 1999/09/18 19:06:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -396,7 +396,8 @@ boot_openrel(char *relname)
 	if (Typ == (struct typmap **) NULL)
 	{
 		StartPortalAllocMode(DefaultAllocMode, 0);
-		rel = heap_openr(TypeRelationName);
+		rel = heap_openr(TypeRelationName, NoLock);
+		Assert(rel);
 		scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
 		i = 0;
 		while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
@@ -416,7 +417,7 @@ boot_openrel(char *relname)
 					sizeof((*app)->am_typ));
 		}
 		heap_endscan(scan);
-		heap_close(rel);
+		heap_close(rel, NoLock);
 		EndPortalAllocMode();
 	}
 
@@ -427,7 +428,7 @@ boot_openrel(char *relname)
 		printf("Amopen: relation %s. attrsize %d\n", relname ? relname : "(null)",
 			   (int) ATTRIBUTE_TUPLE_SIZE);
 
-	reldesc = heap_openr(relname);
+	reldesc = heap_openr(relname, NoLock);
 	Assert(reldesc);
 	numattr = reldesc->rd_rel->relnatts;
 	for (i = 0; i < numattr; i++)
@@ -490,7 +491,7 @@ closerel(char *name)
 	{
 		if (!Quiet)
 			printf("Amclose: relation %s.\n", relname ? relname : "(null)");
-		heap_close(reldesc);
+		heap_close(reldesc, NoLock);
 		reldesc = (Relation) NULL;
 	}
 }
@@ -737,7 +738,7 @@ cleanup()
 		proc_exit(1);
 	}
 	if (reldesc != (Relation) NULL)
-		heap_close(reldesc);
+		heap_close(reldesc, NoLock);
 	CommitTransactionCommand();
 	proc_exit(Warnings);
 }
@@ -775,7 +776,8 @@ gettype(char *type)
 		}
 		if (DebugMode)
 			printf("bootstrap.c: External Type: %s\n", type);
-		rel = heap_openr(TypeRelationName);
+		rel = heap_openr(TypeRelationName, NoLock);
+		Assert(rel);
 		scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
 		i = 0;
 		while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
@@ -795,7 +797,7 @@ gettype(char *type)
 					sizeof((*app)->am_typ));
 		}
 		heap_endscan(scan);
-		heap_close(rel);
+		heap_close(rel, NoLock);
 		return gettype(type);
 	}
 	elog(ERROR, "Error: unknown type '%s'.\n", type);
@@ -1106,11 +1108,16 @@ build_indices()
 
 	for (; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next)
 	{
-		heap = heap_openr(ILHead->il_heap);
+		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_nparams, ILHead->il_params, ILHead->il_finfo,
 					ILHead->il_predInfo);
+		/* In normal processing mode, index_build would close the heap
+		 * and index, but in bootstrap mode it will not.
+		 */
 
 		/*
 		 * All of the rest of this routine is needed only because in
@@ -1128,9 +1135,9 @@ build_indices()
 		 *
 		 * -mer
 		 */
-		heap = heap_openr(ILHead->il_heap);
-
 		if (!BootstrapAlreadySeen(RelationGetRelid(heap)))
 			UpdateStats(RelationGetRelid(heap), 0, true);
+
+		/* XXX Probably we ought to close the heap and index here? */
 	}
 }
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 186ecd07f324cad17c100cf2c5cf7b781b8818d3..33a589ec88b1b81502b3bc3f09b0325382fc437e 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.27 1999/07/30 18:09:44 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.28 1999/09/18 19:06:33 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -105,19 +105,15 @@ ChangeAcl(char *relname,
 	 * We can't use the syscache here, since we need to do a heap_replace on
 	 * the tuple we find.
 	 */
-	relation = heap_openr(RelationRelationName);
-	if (!RelationIsValid(relation))
-		elog(ERROR, "ChangeAcl: could not open '%s'??",
-			 RelationRelationName);
+	relation = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheTuple(RELNAME,
 								PointerGetDatum(relname),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
-		heap_close(relation);
+		heap_close(relation, RowExclusiveLock);
 		elog(ERROR, "ChangeAcl: class \"%s\" not found",
 			 relname);
-		return;
 	}
 
 	if (!heap_attisnull(tuple, Anum_pg_class_relacl))
@@ -164,7 +160,7 @@ ChangeAcl(char *relname,
 	CatalogIndexInsert(idescs, Num_pg_class_indices, relation, tuple);
 	CatalogCloseIndices(Num_pg_class_indices, idescs);
 
-	heap_close(relation);
+	heap_close(relation, RowExclusiveLock);
 	if (free_old_acl)
 		pfree(old_acl);
 	pfree(new_acl);
@@ -213,13 +209,7 @@ in_group(AclId uid, AclId gid)
 	AclId	   *aidp;
 	int32		found = 0;
 
-	relation = heap_openr(GroupRelationName);
-	if (!RelationIsValid(relation))
-	{
-		elog(NOTICE, "in_group: could not open \"%s\"??",
-			 GroupRelationName);
-		return 0;
-	}
+	relation = heap_openr(GroupRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheTuple(GROSYSID,
 								ObjectIdGetDatum(gid),
 								0, 0, 0);
@@ -242,7 +232,7 @@ in_group(AclId uid, AclId gid)
 	}
 	else
 		elog(NOTICE, "in_group: group %d not found", gid);
-	heap_close(relation);
+	heap_close(relation, RowExclusiveLock);
 	return found;
 }
 
@@ -413,6 +403,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
 	}
 
 #ifndef ACLDEBUG
+	relation = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheTuple(RELNAME,
 								PointerGetDatum(relname),
 								0, 0, 0);
@@ -420,18 +411,15 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
 	{
 		elog(ERROR, "pg_aclcheck: class \"%s\" not found",
 			 relname);
-		/* an elog(ERROR) kills us, so no need to return anything. */
 	}
 	if (!heap_attisnull(tuple, Anum_pg_class_relacl))
 	{
-		relation = heap_openr(RelationRelationName);
 		tmp = (Acl *) heap_getattr(tuple,
 								   Anum_pg_class_relacl,
 								   RelationGetDescr(relation),
 								   (bool *) NULL);
 		acl = makeacl(ACL_NUM(tmp));
 		memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
-		heap_close(relation);
 	}
 	else
 	{
@@ -442,42 +430,29 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
 		 */
 		int4		ownerId;
 
-		relation = heap_openr(RelationRelationName);
 		ownerId = (int4) heap_getattr(tuple,
 									  Anum_pg_class_relowner,
 									  RelationGetDescr(relation),
 									  (bool *) NULL);
 		acl = aclownerdefault(relname, (AclId) ownerId);
-		heap_close(relation);
 	}
+	heap_close(relation, RowExclusiveLock);
 #else
-	{							/* This is why the syscache is great... */
-		static ScanKeyData relkey[1] = {
-			{0, Anum_pg_class_relname, F_NAMEEQ}
-		};
-
-		relation = heap_openr(RelationRelationName);
-		if (!RelationIsValid(relation))
-		{
-			elog(NOTICE, "pg_checkacl: could not open \"%-.*s\"??",
-				 RelationRelationName);
-			return ACLCHECK_NO_CLASS;
-		}
-		tuple = SearchSysCacheTuple(RELNAME,
-									PointerGetDatum(relname),
-									0, 0, 0);
-		if (HeapTupleIsValid(tuple) &&
-			!heap_attisnull(tuple, Anum_pg_class_relacl))
-		{
-			tmp = (Acl *) heap_getattr(tuple,
-									   Anum_pg_class_relacl,
-									   RelationGetDescr(relation),
-									   (bool *) NULL);
-			acl = makeacl(ACL_NUM(tmp));
-			memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
-		}
-		heap_close(relation);
+	relation = heap_openr(RelationRelationName, RowExclusiveLock);
+	tuple = SearchSysCacheTuple(RELNAME,
+								PointerGetDatum(relname),
+								0, 0, 0);
+	if (HeapTupleIsValid(tuple) &&
+		!heap_attisnull(tuple, Anum_pg_class_relacl))
+	{
+		tmp = (Acl *) heap_getattr(tuple,
+								   Anum_pg_class_relacl,
+								   RelationGetDescr(relation),
+								   (bool *) NULL);
+		acl = makeacl(ACL_NUM(tmp));
+		memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
 	}
+	heap_close(relation, RowExclusiveLock);
 #endif
 	result = aclcheck(relname, acl, id, (AclIdType) ACL_IDTYPE_UID, mode);
 	if (acl)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 561cb21a418d2479ad30cdd14eedae3cd5a1e0a9..644f03eba870a0406202ee4d6cd86c1274562f97 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.95 1999/09/05 17:43:47 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.96 1999/09/18 19:06:33 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -243,8 +243,6 @@ heap_create(char *relname,
 
 	/* ----------------
 	 *	allocate a new relation descriptor.
-	 *
-	 *	XXX the length computation may be incorrect, handle elsewhere
 	 * ----------------
 	 */
 	len = sizeof(RelationData);
@@ -474,7 +472,7 @@ RelnameFindRelid(char *relname)
 		ScanKeyData key;
 		HeapScanDesc pg_class_scan;
 
-		pg_class_desc = heap_openr(RelationRelationName);
+		pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
 
 		/* ----------------
 		 *	At bootstrap time, we have to do this the hard way.  Form the
@@ -511,7 +509,7 @@ RelnameFindRelid(char *relname)
 
 		heap_endscan(pg_class_scan);
 
-		heap_close(pg_class_desc);
+		heap_close(pg_class_desc, AccessShareLock);
 	}
 	return relid;
 }
@@ -539,14 +537,12 @@ AddNewAttributeTuples(Oid new_rel_oid,
 	 *	open pg_attribute
 	 * ----------------
 	 */
-	rel = heap_openr(AttributeRelationName);
+	rel = heap_openr(AttributeRelationName, RowExclusiveLock);
 
 	/* -----------------
 	 * Check if we have any indices defined on pg_attribute.
 	 * -----------------
 	 */
-	Assert(rel);
-	Assert(rel->rd_rel);
 	hasindex = RelationGetForm(rel)->relhasindex;
 	if (hasindex)
 		CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
@@ -607,7 +603,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
 		dpp++;
 	}
 
-	heap_close(rel);
+	heap_close(rel, RowExclusiveLock);
 
 	/*
 	 * close pg_attribute indices
@@ -829,7 +825,7 @@ heap_create_with_catalog(char *relname,
 	 *	now update the information in pg_class.
 	 * ----------------
 	 */
-	pg_class_desc = heap_openr(RelationRelationName);
+	pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
 
 	AddNewRelationTuple(pg_class_desc,
 						new_rel_desc,
@@ -853,8 +849,8 @@ heap_create_with_catalog(char *relname,
 	 *	SOMEDAY: fill the STATISTIC relation properly.
 	 * ----------------
 	 */
-	heap_close(new_rel_desc);
-	heap_close(pg_class_desc);
+	heap_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
+	heap_close(pg_class_desc, RowExclusiveLock);
 
 	return new_rel_oid;
 }
@@ -913,7 +909,7 @@ RelationRemoveInheritance(Relation relation)
 	 *	open pg_inherits
 	 * ----------------
 	 */
-	catalogRelation = heap_openr(InheritsRelationName);
+	catalogRelation = heap_openr(InheritsRelationName, RowExclusiveLock);
 
 	/* ----------------
 	 *	form a scan key for the subclasses of this class
@@ -937,13 +933,15 @@ RelationRemoveInheritance(Relation relation)
 	tuple = heap_getnext(scan, 0);
 	if (HeapTupleIsValid(tuple))
 	{
+		Oid		subclass = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrel;
+
 		heap_endscan(scan);
-		heap_close(catalogRelation);
+		heap_close(catalogRelation, RowExclusiveLock);
 
 		elog(ERROR, "Relation '%u' inherits '%s'",
-			 ((Form_pg_inherits) GETSTRUCT(tuple))->inhrel,
-			 RelationGetRelationName(relation));
+			 subclass, RelationGetRelationName(relation));
 	}
+	heap_endscan(scan);
 
 	/* ----------------
 	 *	If we get here, it means the relation has no subclasses
@@ -965,13 +963,14 @@ RelationRemoveInheritance(Relation relation)
 	}
 
 	heap_endscan(scan);
-	heap_close(catalogRelation);
+	heap_close(catalogRelation, RowExclusiveLock);
 
 	/* ----------------
 	 *	now remove dead IPL tuples
 	 * ----------------
 	 */
-	catalogRelation = heap_openr(InheritancePrecidenceListRelationName);
+	catalogRelation = heap_openr(InheritancePrecidenceListRelationName,
+								 RowExclusiveLock);
 
 	entry.sk_attno = Anum_pg_ipl_iplrel;
 
@@ -985,7 +984,7 @@ RelationRemoveInheritance(Relation relation)
 		heap_delete(catalogRelation, &tuple->t_self, NULL);
 
 	heap_endscan(scan);
-	heap_close(catalogRelation);
+	heap_close(catalogRelation, RowExclusiveLock);
 }
 
 /* --------------------------------
@@ -1001,7 +1000,7 @@ RelationRemoveIndexes(Relation relation)
 	HeapScanDesc scan;
 	ScanKeyData entry;
 
-	indexRelation = heap_openr(IndexRelationName);
+	indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
 
 	ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indrelid,
 						   F_OIDEQ,
@@ -1017,7 +1016,7 @@ RelationRemoveIndexes(Relation relation)
 		index_destroy(((Form_pg_index) GETSTRUCT(tuple))->indexrelid);
 
 	heap_endscan(scan);
-	heap_close(indexRelation);
+	heap_close(indexRelation, RowExclusiveLock);
 }
 
 /* --------------------------------
@@ -1035,14 +1034,14 @@ DeleteRelationTuple(Relation rel)
 	 *	open pg_class
 	 * ----------------
 	 */
-	pg_class_desc = heap_openr(RelationRelationName);
+	pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
 
 	tup = SearchSysCacheTupleCopy(RELOID,
 					   ObjectIdGetDatum(rel->rd_att->attrs[0]->attrelid),
 								  0, 0, 0);
 	if (!HeapTupleIsValid(tup))
 	{
-		heap_close(pg_class_desc);
+		heap_close(pg_class_desc, RowExclusiveLock);
 		elog(ERROR, "Relation '%s' does not exist",
 			 &rel->rd_rel->relname);
 	}
@@ -1054,7 +1053,7 @@ DeleteRelationTuple(Relation rel)
 	heap_delete(pg_class_desc, &tup->t_self, NULL);
 	pfree(tup);
 
-	heap_close(pg_class_desc);
+	heap_close(pg_class_desc, RowExclusiveLock);
 }
 
 /* --------------------------------
@@ -1073,13 +1072,7 @@ DeleteAttributeTuples(Relation rel)
 	 *	open pg_attribute
 	 * ----------------
 	 */
-	pg_attribute_desc = heap_openr(AttributeRelationName);
-
-	/* -----------------
-	 * Get a write lock _before_ getting the read lock in the scan
-	 * ----------------
-	 */
-	LockRelation(pg_attribute_desc, AccessExclusiveLock);
+	pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
 
 	for (attnum = FirstLowInvalidHeapAttributeNumber + 1;
 		 attnum <= rel->rd_att->natts;
@@ -1095,12 +1088,7 @@ DeleteAttributeTuples(Relation rel)
 		}
 	}
 
-	/* ----------------
-	 * Release the write lock
-	 * ----------------
-	 */
-	UnlockRelation(pg_attribute_desc, AccessExclusiveLock);
-	heap_close(pg_attribute_desc);
+	heap_close(pg_attribute_desc, RowExclusiveLock);
 }
 
 /* --------------------------------
@@ -1129,7 +1117,7 @@ DeleteTypeTuple(Relation rel)
 	 *	open pg_type
 	 * ----------------
 	 */
-	pg_type_desc = heap_openr(TypeRelationName);
+	pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
 
 	/* ----------------
 	 *	create a scan key to locate the type tuple corresponding
@@ -1157,7 +1145,7 @@ DeleteTypeTuple(Relation rel)
 	if (!HeapTupleIsValid(tup))
 	{
 		heap_endscan(pg_type_scan);
-		heap_close(pg_type_desc);
+		heap_close(pg_type_desc, RowExclusiveLock);
 		elog(ERROR, "DeleteTypeTuple: %s type nonexistent",
 			 &rel->rd_rel->relname);
 	}
@@ -1171,7 +1159,7 @@ DeleteTypeTuple(Relation rel)
 	 */
 	typoid = tup->t_data->t_oid;
 
-	pg_attribute_desc = heap_openr(AttributeRelationName);
+	pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
 
 	ScanKeyEntryInitialize(&attkey,
 						   0,
@@ -1197,16 +1185,16 @@ DeleteTypeTuple(Relation rel)
 	{
 		Oid			relid = ((Form_pg_attribute) GETSTRUCT(atttup))->attrelid;
 
-		heap_endscan(pg_type_scan);
-		heap_close(pg_type_desc);
 		heap_endscan(pg_attribute_scan);
-		heap_close(pg_attribute_desc);
+		heap_close(pg_attribute_desc, RowExclusiveLock);
+		heap_endscan(pg_type_scan);
+		heap_close(pg_type_desc, RowExclusiveLock);
 
 		elog(ERROR, "DeleteTypeTuple: att of type %s exists in relation %u",
 			 &rel->rd_rel->relname, relid);
 	}
 	heap_endscan(pg_attribute_scan);
-	heap_close(pg_attribute_desc);
+	heap_close(pg_attribute_desc, RowExclusiveLock);
 
 	/* ----------------
 	 *	Ok, it's safe so we delete the relation tuple
@@ -1217,7 +1205,7 @@ DeleteTypeTuple(Relation rel)
 	heap_delete(pg_type_desc, &tup->t_self, NULL);
 
 	heap_endscan(pg_type_scan);
-	heap_close(pg_type_desc);
+	heap_close(pg_type_desc, RowExclusiveLock);
 }
 
 /* --------------------------------
@@ -1233,15 +1221,10 @@ heap_destroy_with_catalog(char *relname)
 	bool		istemp = (get_temp_rel_by_name(relname) != NULL);
 
 	/* ----------------
-	 *	first open the relation.  if the relation doesn't exist,
-	 *	heap_openr() returns NULL.
+	 *	Open and lock the relation.
 	 * ----------------
 	 */
-	rel = heap_openr(relname);
-	if (rel == NULL)
-		elog(ERROR, "Relation '%s' does not exist", relname);
-
-	LockRelation(rel, AccessExclusiveLock);
+	rel = heap_openr(relname, AccessExclusiveLock);
 	rid = rel->rd_id;
 
 	/* ----------------
@@ -1249,8 +1232,8 @@ heap_destroy_with_catalog(char *relname)
 	 * ----------------
 	 */
 	/* allow temp of pg_class? Guess so. */
-	if (!istemp &&
-		!allowSystemTableMods && IsSystemRelationName(RelationGetRelationName(rel)->data))
+	if (!istemp && !allowSystemTableMods &&
+		IsSystemRelationName(RelationGetRelationName(rel)->data))
 		elog(ERROR, "System relation '%s' cannot be destroyed",
 			 &rel->rd_rel->relname);
 
@@ -1330,9 +1313,12 @@ heap_destroy_with_catalog(char *relname)
 
 	rel->rd_nonameunlinked = TRUE;
 
-	UnlockRelation(rel, AccessExclusiveLock);
-
-	heap_close(rel);
+	/*
+	 * Close relcache entry, but *keep* AccessExclusiveLock on the
+	 * relation until transaction commit.  This ensures no one else
+	 * will try to do something with the doomed relation.
+	 */
+	heap_close(rel, NoLock);
 
 	/* ----------------
 	 *	flush the relation from the relcache
@@ -1354,7 +1340,7 @@ heap_destroy(Relation rel)
 	if (!(rel->rd_isnoname) || !(rel->rd_nonameunlinked))
 		smgrunlink(DEFAULT_SMGR, rel);
 	rel->rd_nonameunlinked = TRUE;
-	heap_close(rel);
+	heap_close(rel, NoLock);
 	RemoveFromNoNameRelList(rel);
 }
 
@@ -1542,13 +1528,13 @@ start:
 	values[Anum_pg_attrdef_adnum - 1] = attrdef->adnum;
 	values[Anum_pg_attrdef_adbin - 1] = PointerGetDatum(textin(attrdef->adbin));
 	values[Anum_pg_attrdef_adsrc - 1] = PointerGetDatum(textin(attrdef->adsrc));
-	adrel = heap_openr(AttrDefaultRelationName);
+	adrel = heap_openr(AttrDefaultRelationName, RowExclusiveLock);
 	tuple = heap_formtuple(adrel->rd_att, values, nulls);
 	CatalogOpenIndices(Num_pg_attrdef_indices, Name_pg_attrdef_indices, idescs);
 	heap_insert(adrel, tuple);
 	CatalogIndexInsert(idescs, Num_pg_attrdef_indices, adrel, tuple);
 	CatalogCloseIndices(Num_pg_attrdef_indices, idescs);
-	heap_close(adrel);
+	heap_close(adrel, RowExclusiveLock);
 
 	pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
 	pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));
@@ -1605,20 +1591,18 @@ StoreRelCheck(Relation rel, ConstrCheck *check)
 	values[Anum_pg_relcheck_rcname - 1] = PointerGetDatum(namein(check->ccname));
 	values[Anum_pg_relcheck_rcbin - 1] = PointerGetDatum(textin(check->ccbin));
 	values[Anum_pg_relcheck_rcsrc - 1] = PointerGetDatum(textin(check->ccsrc));
-	rcrel = heap_openr(RelCheckRelationName);
+	rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
 	tuple = heap_formtuple(rcrel->rd_att, values, nulls);
 	CatalogOpenIndices(Num_pg_relcheck_indices, Name_pg_relcheck_indices, idescs);
 	heap_insert(rcrel, tuple);
 	CatalogIndexInsert(idescs, Num_pg_relcheck_indices, rcrel, tuple);
 	CatalogCloseIndices(Num_pg_relcheck_indices, idescs);
-	heap_close(rcrel);
+	heap_close(rcrel, RowExclusiveLock);
 
 	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcname - 1]));
 	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcbin - 1]));
 	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcsrc - 1]));
 	pfree(tuple);
-
-	return;
 }
 
 static void
@@ -1653,23 +1637,18 @@ RemoveAttrDefault(Relation rel)
 	ScanKeyData key;
 	HeapTuple	tup;
 
-	adrel = heap_openr(AttrDefaultRelationName);
+	adrel = heap_openr(AttrDefaultRelationName, RowExclusiveLock);
 
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_attrdef_adrelid,
 						   F_OIDEQ, rel->rd_id);
 
-	LockRelation(adrel, AccessExclusiveLock);
-
 	adscan = heap_beginscan(adrel, 0, SnapshotNow, 1, &key);
 
 	while (HeapTupleIsValid(tup = heap_getnext(adscan, 0)))
 		heap_delete(adrel, &tup->t_self, NULL);
 
 	heap_endscan(adscan);
-
-	UnlockRelation(adrel, AccessExclusiveLock);
-	heap_close(adrel);
-
+	heap_close(adrel, RowExclusiveLock);
 }
 
 static void
@@ -1680,23 +1659,18 @@ RemoveRelCheck(Relation rel)
 	ScanKeyData key;
 	HeapTuple	tup;
 
-	rcrel = heap_openr(RelCheckRelationName);
+	rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
 
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_relcheck_rcrelid,
 						   F_OIDEQ, rel->rd_id);
 
-	LockRelation(rcrel, AccessExclusiveLock);
-
 	rcscan = heap_beginscan(rcrel, 0, SnapshotNow, 1, &key);
 
 	while (HeapTupleIsValid(tup = heap_getnext(rcscan, 0)))
 		heap_delete(rcrel, &tup->t_self, NULL);
 
 	heap_endscan(rcscan);
-
-	UnlockRelation(rcrel, AccessExclusiveLock);
-	heap_close(rcrel);
-
+	heap_close(rcrel, RowExclusiveLock);
 }
 
 static void
@@ -1712,6 +1686,4 @@ RemoveConstraints(Relation rel)
 
 	if (constr->num_check > 0)
 		RemoveRelCheck(rel);
-
-	return;
 }
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index c90c27fd5de55c64cfb922714d07e37ceb865e25..912996fb1fc7f8a92882ef64bd91505421a88712 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.89 1999/09/05 17:43:47 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.90 1999/09/18 19:06:33 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -378,7 +378,7 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
 	 *	fetch the desired access method tuple
 	 * ----------------
 	 */
-	pg_am_desc = heap_openr(AccessMethodRelationName);
+	pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
 	pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
 
 	pg_am_tuple = heap_getnext(pg_am_scan, 0);
@@ -390,7 +390,7 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
 	if (!HeapTupleIsValid(pg_am_tuple))
 	{
 		heap_endscan(pg_am_scan);
-		heap_close(pg_am_desc);
+		heap_close(pg_am_desc, AccessShareLock);
 		return NULL;
 	}
 
@@ -402,7 +402,7 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
 	memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
 
 	heap_endscan(pg_am_scan);
-	heap_close(pg_am_desc);
+	heap_close(pg_am_desc, AccessShareLock);
 
 	return aform;
 }
@@ -456,7 +456,7 @@ UpdateRelationRelation(Relation indexRelation, char *temp_relname)
 	Oid			tupleOid;
 	Relation	idescs[Num_pg_class_indices];
 
-	pg_class = heap_openr(RelationRelationName);
+	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
 	/* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
 	tuple = heap_addheader(Natts_pg_class_fixed,
@@ -491,7 +491,7 @@ UpdateRelationRelation(Relation indexRelation, char *temp_relname)
 
 	tupleOid = tuple->t_data->t_oid;
 	pfree(tuple);
-	heap_close(pg_class);
+	heap_close(pg_class, RowExclusiveLock);
 
 	return tupleOid;
 }
@@ -542,7 +542,7 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
 	 *	XXX ADD INDEXING
 	 * ----------------
 	 */
-	pg_attribute = heap_openr(AttributeRelationName);
+	pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
 
 	/* ----------------
 	 *	initialize *null, *replace and *value
@@ -628,7 +628,7 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
 
 	if (cur_tuple)
 		pfree(cur_tuple);
-	heap_close(pg_attribute);
+	heap_close(pg_attribute, RowExclusiveLock);
 	if (hasind)
 		CatalogCloseIndices(Num_pg_attr_indices, idescs);
 
@@ -734,7 +734,7 @@ UpdateIndexRelation(Oid indexoid,
 	 *	open the system catalog index relation
 	 * ----------------
 	 */
-	pg_index = heap_openr(IndexRelationName);
+	pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
 
 	/* ----------------
 	 *	form a tuple to insert into pg_index
@@ -755,7 +755,7 @@ UpdateIndexRelation(Oid indexoid,
 	 *	close the relation and free the tuple
 	 * ----------------
 	 */
-	heap_close(pg_index);
+	heap_close(pg_index, RowExclusiveLock);
 	pfree(predText);
 	pfree(indexForm);
 	pfree(tuple);
@@ -810,7 +810,7 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
 		predText = (text *) fmgr(F_TEXTIN, "");
 
 	/* open the index system catalog relation */
-	pg_index = heap_openr(IndexRelationName);
+	pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
 
 	tuple = SearchSysCacheTuple(INDEXRELID,
 								ObjectIdGetDatum(indexoid),
@@ -832,7 +832,7 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
 	heap_replace(pg_index, &newtup->t_self, newtup, NULL);
 
 	pfree(newtup);
-	heap_close(pg_index);
+	heap_close(pg_index, RowExclusiveLock);
 	pfree(predText);
 }
 
@@ -956,12 +956,10 @@ index_create(char *heapRelationName,
 	 */
 	heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
 
-	heapRelation = heap_open(heapoid);
-
 	/*
-	 * Only SELECT ... FOR UPDATE are allowed
+	 * Only SELECT ... FOR UPDATE are allowed while doing this
 	 */
-	LockRelation(heapRelation, ShareLock);
+	heapRelation = heap_open(heapoid, ShareLock);
 
 	/* ----------------
 	 *	  construct new tuple descriptor
@@ -1070,16 +1068,20 @@ index_create(char *heapRelationName,
 	 * the index yet.  We'll be creating more indices and classes later,
 	 * so we delay filling them in until just before we're done with
 	 * bootstrapping.  Otherwise, we call the routine that constructs the
-	 * index.  The heap and index relations are closed by index_build().
+	 * index.
+	 *
+	 * In normal processing mode, the heap and index relations are closed
+	 * by index_build() --- but we continue to hold the ShareLock on the
+	 * heap that we acquired above, until end of transaction.
 	 */
 	if (IsBootstrapProcessingMode())
 	{
 		index_register(heapRelationName, indexRelationName, numatts, attNums,
 					   parameterCount, parameter, funcInfo, predInfo);
+		/* XXX shouldn't we close the heap and index rels here? */
 	}
 	else
 	{
-		heapRelation = heap_openr(heapRelationName);
 		index_build(heapRelation, indexRelation, numatts, attNums,
 					parameterCount, parameter, funcInfo, predInfo);
 	}
@@ -1103,9 +1105,13 @@ index_destroy(Oid indexId)
 
 	Assert(OidIsValid(indexId));
 
-	/* Open now to obtain lock by referencing table?  bjm */
 	userindexRelation = index_open(indexId);
 
+	/*
+	 * Get exclusive lock to ensure no one else is scanning this index.
+	 */
+	LockRelation(userindexRelation, AccessExclusiveLock);
+
 	/* ----------------
 	 *	We do not allow DROP INDEX within a transaction block, because
 	 *	if the transaction is later rolled back there would be no way to
@@ -1121,7 +1127,7 @@ index_destroy(Oid indexId)
 	 * fix RELATION relation
 	 * ----------------
 	 */
-	relationRelation = heap_openr(RelationRelationName);
+	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
 
 	tuple = SearchSysCacheTupleCopy(RELOID,
 									ObjectIdGetDatum(indexId),
@@ -1131,13 +1137,13 @@ index_destroy(Oid indexId)
 
 	heap_delete(relationRelation, &tuple->t_self, NULL);
 	pfree(tuple);
-	heap_close(relationRelation);
+	heap_close(relationRelation, RowExclusiveLock);
 
 	/* ----------------
 	 * fix ATTRIBUTE relation
 	 * ----------------
 	 */
-	attributeRelation = heap_openr(AttributeRelationName);
+	attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
 
 	attnum = 1;					/* indexes start at 1 */
 
@@ -1150,7 +1156,7 @@ index_destroy(Oid indexId)
 		pfree(tuple);
 		attnum++;
 	}
-	heap_close(attributeRelation);
+	heap_close(attributeRelation, RowExclusiveLock);
 
 	/* does something only if it is a temp index */
 	remove_temp_relation(indexId);
@@ -1159,16 +1165,16 @@ index_destroy(Oid indexId)
 	 * fix INDEX relation
 	 * ----------------
 	 */
+	indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
+
 	tuple = SearchSysCacheTupleCopy(INDEXRELID,
 									ObjectIdGetDatum(indexId),
 									0, 0, 0);
 	Assert(HeapTupleIsValid(tuple));
 
-	indexRelation = heap_openr(IndexRelationName);
-
 	heap_delete(indexRelation, &tuple->t_self, NULL);
 	pfree(tuple);
-	heap_close(indexRelation);
+	heap_close(indexRelation, RowExclusiveLock);
 
 	/*
 	 * flush cache and physically remove the file
@@ -1179,7 +1185,8 @@ index_destroy(Oid indexId)
 		elog(ERROR, "index_destroy: unlink: %m");
 
 	index_close(userindexRelation);
-	RelationForgetRelation(RelationGetRelid(userindexRelation));
+
+	RelationForgetRelation(indexId);
 }
 
 /* ----------------------------------------------------------------
@@ -1264,16 +1271,21 @@ UpdateStats(Oid relid, long reltuples, bool hasindex)
 	 * ----------------
 	 */
 
+	/*
+	 * Can't use heap_open here since we don't know if it's an index...
+	 */
 	whichRel = RelationIdGetRelation(relid);
 
 	if (!RelationIsValid(whichRel))
 		elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
 
+	LockRelation(whichRel, ShareLock);
+
 	/* ----------------
 	 * Find the RELATION relation tuple for the given relation.
 	 * ----------------
 	 */
-	pg_class = heap_openr(RelationRelationName);
+	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 	if (!RelationIsValid(pg_class))
 		elog(ERROR, "UpdateStats: could not open RELATION relation");
 
@@ -1300,7 +1312,7 @@ UpdateStats(Oid relid, long reltuples, bool hasindex)
 	{
 		if (IsBootstrapProcessingMode())
 			heap_endscan(pg_class_scan);
-		heap_close(pg_class);
+		heap_close(pg_class, RowExclusiveLock);
 		elog(ERROR, "UpdateStats: cannot scan RELATION relation");
 	}
 
@@ -1391,8 +1403,9 @@ UpdateStats(Oid relid, long reltuples, bool hasindex)
 	else
 		heap_endscan(pg_class_scan);
 
-	heap_close(pg_class);
-	heap_close(whichRel);
+	heap_close(pg_class, RowExclusiveLock);
+	/* Cheating a little bit since we didn't open it with heap_open... */
+	heap_close(whichRel, ShareLock);
 }
 
 
@@ -1600,20 +1613,31 @@ DefaultBuild(Relation heapRelation,
 	pfree(datum);
 
 	/*
-	 * Okay, now update the reltuples and relpages statistics for both the
-	 * heap relation and the index.  These statistics are used by the
-	 * planner to choose a scan type.  They are maintained generally by
-	 * the vacuum daemon, but we update them here to make the index useful
-	 * as soon as possible.
-	 */
-	UpdateStats(RelationGetRelid(heapRelation), reltuples, true);
-	UpdateStats(RelationGetRelid(indexRelation), indtuples, false);
-	if (oldPred != NULL)
+	 * Since we just counted the tuples in the heap, we update its stats
+	 * in pg_class to guarantee that the planner takes advantage of the
+	 * index we just created.  But, only update statistics during
+	 * normal index definitions, not for indices on system catalogs
+	 * created during bootstrap processing.  We must close the relations
+	 * before updating statistics to guarantee that the relcache entries
+	 * are flushed when we increment the command counter in UpdateStats().
+	 * But we do not release any locks on the relations; those will be
+	 * held until end of transaction.
+	 */
+	if (IsNormalProcessingMode())
 	{
-		if (indtuples == reltuples)
-			predicate = NULL;
-		UpdateIndexPredicate(RelationGetRelid(indexRelation),
-							 oldPred, predicate);
+		Oid		hrelid = RelationGetRelid(heapRelation);
+		Oid		irelid = RelationGetRelid(indexRelation);
+
+		heap_close(heapRelation, NoLock);
+		index_close(indexRelation);
+		UpdateStats(hrelid, reltuples, true);
+		UpdateStats(irelid, indtuples, false);
+		if (oldPred != NULL)
+		{
+			if (indtuples == reltuples)
+				predicate = NULL;
+			UpdateIndexPredicate(irelid, oldPred, predicate);
+		}
 	}
 }
 
@@ -1715,7 +1739,7 @@ IndexIsUniqueNoCache(Oid indexId)
 	Form_pg_index index;
 	bool		isunique;
 
-	pg_index = heap_openr(IndexRelationName);
+	pg_index = heap_openr(IndexRelationName, AccessShareLock);
 
 	ScanKeyEntryInitialize(&skey[0], (bits16) 0x0,
 						   Anum_pg_index_indexrelid,
@@ -1734,6 +1758,6 @@ IndexIsUniqueNoCache(Oid indexId)
 	isunique = index->indisunique;
 
 	heap_endscan(scandesc);
-	heap_close(pg_index);
+	heap_close(pg_index, AccessShareLock);
 	return isunique;
 }
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 9007258f2e81792cc2f2ed1dc1fdf3d6fc1c8404..75799e55570fddc561657cf3d7a7c28aec1556be 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.44 1999/09/04 22:00:29 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.45 1999/09/18 19:06:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -193,9 +193,9 @@ CatalogHasIndex(char *catName, Oid catId)
 		return false;
 	}
 
-	pg_class = heap_openr(RelationRelationName);
+	pg_class = heap_openr(RelationRelationName, AccessShareLock);
 	htup = ClassOidIndexScan(pg_class, catId);
-	heap_close(pg_class);
+	heap_close(pg_class, AccessShareLock);
 
 	if (!HeapTupleIsValid(htup))
 	{
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index c8f02287cb80741545f1b69621af1abc01e3b823..0f2b98da906c2ec0c5f24b185613b23b5e90e28e 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.24 1999/07/17 20:16:49 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.25 1999/09/18 19:06:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -234,10 +234,7 @@ AggregateCreate(char *aggName,
 	else
 		nulls[Anum_pg_aggregate_agginitval2 - 1] = 'n';
 
-	if (!RelationIsValid(aggdesc = heap_openr(AggregateRelationName)))
-		elog(ERROR, "AggregateCreate: could not open '%s'",
-			 AggregateRelationName);
-
+	aggdesc = heap_openr(AggregateRelationName, RowExclusiveLock);
 	tupDesc = aggdesc->rd_att;
 	if (!HeapTupleIsValid(tup = heap_formtuple(tupDesc,
 											   values,
@@ -245,8 +242,7 @@ AggregateCreate(char *aggName,
 		elog(ERROR, "AggregateCreate: heap_formtuple failed");
 	if (!OidIsValid(heap_insert(aggdesc, tup)))
 		elog(ERROR, "AggregateCreate: heap_insert failed");
-	heap_close(aggdesc);
-
+	heap_close(aggdesc, RowExclusiveLock);
 }
 
 char *
@@ -264,6 +260,14 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
 	Assert(PointerIsValid(isNull));
 	Assert(xfuncno == 1 || xfuncno == 2);
 
+	/*
+	 * since we will have to use fastgetattr (in case one or both init vals
+	 * are NULL), we will need to open the relation.  Do that first to
+	 * ensure we don't get a stale tuple from the cache.
+	 */
+
+	aggRel = heap_openr(AggregateRelationName, AccessShareLock);
+
 	tup = SearchSysCacheTuple(AGGNAME,
 							  PointerGetDatum(aggName),
 							  ObjectIdGetDatum(basetype),
@@ -277,21 +281,12 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
 		initValAttno = Anum_pg_aggregate_agginitval1;
 	}
 	else
-		/* can only be 1 or 2 */
 	{
+		/* can only be 1 or 2 */
 		transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
 		initValAttno = Anum_pg_aggregate_agginitval2;
 	}
 
-	aggRel = heap_openr(AggregateRelationName);
-	if (!RelationIsValid(aggRel))
-		elog(ERROR, "AggNameGetInitVal: could not open \"%-.*s\"",
-			 AggregateRelationName);
-
-	/*
-	 * must use fastgetattr in case one or other of the init values is
-	 * NULL
-	 */
 	textInitVal = (text *) fastgetattr(tup, initValAttno,
 									   RelationGetDescr(aggRel),
 									   isNull);
@@ -299,11 +294,12 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
 		*isNull = true;
 	if (*isNull)
 	{
-		heap_close(aggRel);
+		heap_close(aggRel, AccessShareLock);
 		return (char *) NULL;
 	}
 	strInitVal = textout(textInitVal);
-	heap_close(aggRel);
+
+	heap_close(aggRel, AccessShareLock);
 
 	tup = SearchSysCacheTuple(TYPOID,
 							  ObjectIdGetDatum(transtype),
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 8cab520f520fa2013734b5840969063c5be752f7..53b250fe3fabb7c26769a0f935140d274d47cccd 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.41 1999/07/17 20:16:49 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.42 1999/09/18 19:06:33 tgl Exp $
  *
  * NOTES
  *	  these routines moved here from commands/define.c and somewhat cleaned up.
@@ -199,7 +199,7 @@ OperatorGet(char *operatorName,
 	 *	open the pg_operator relation
 	 * ----------------
 	 */
-	pg_operator_desc = heap_openr(OperatorRelationName);
+	pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
 
 	/* ----------------
 	 *	get the oid for the operator with the appropriate name
@@ -216,7 +216,7 @@ OperatorGet(char *operatorName,
 	 *	close the relation and return the operator oid.
 	 * ----------------
 	 */
-	heap_close(pg_operator_desc);
+	heap_close(pg_operator_desc, AccessShareLock);
 
 	return operatorObjectId;
 }
@@ -341,7 +341,7 @@ OperatorShellMake(char *operatorName,
 	 *	open pg_operator
 	 * ----------------
 	 */
-	pg_operator_desc = heap_openr(OperatorRelationName);
+	pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
 
 	/* ----------------
 	 *	add a "shell" operator tuple to the operator relation
@@ -356,7 +356,7 @@ OperatorShellMake(char *operatorName,
 	 *	close the operator relation and return the oid.
 	 * ----------------
 	 */
-	heap_close(pg_operator_desc);
+	heap_close(pg_operator_desc, RowExclusiveLock);
 
 	return operatorObjectId;
 }
@@ -754,10 +754,11 @@ OperatorDef(char *operatorName,
 
 	/* last three fields were filled in above */
 
+	pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
+
 	/*
 	 * If we are adding to an operator shell, get its t_self
 	 */
-	pg_operator_desc = heap_openr(OperatorRelationName);
 
 	if (operatorObjectId)
 	{
@@ -798,7 +799,7 @@ OperatorDef(char *operatorName,
 		operatorObjectId = tup->t_data->t_oid;
 	}
 
-	heap_close(pg_operator_desc);
+	heap_close(pg_operator_desc, RowExclusiveLock);
 
 	/*
 	 * If a commutator and/or negator link is provided, update the other
@@ -853,7 +854,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
 		nulls[i] = ' ';
 	}
 
-	pg_operator_desc = heap_openr(OperatorRelationName);
+	pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
 
 	/* check and update the commutator, if necessary */
 	opKey[0].sk_argument = ObjectIdGetDatum(commId);
@@ -908,7 +909,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
 		}
 		heap_endscan(pg_operator_scan);
 
-		heap_close(pg_operator_desc);
+		heap_close(pg_operator_desc, RowExclusiveLock);
 
 		return;
 	}
@@ -964,7 +965,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
 
 	heap_endscan(pg_operator_scan);
 
-	heap_close(pg_operator_desc);
+	heap_close(pg_operator_desc, RowExclusiveLock);
 }
 
 
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index f0a10cf8f89092871099f2e220c33912b98fd413..b71f36e6618858f4624982564bee0075dfe063d2 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.33 1999/07/17 20:16:49 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.34 1999/09/18 19:06:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -277,7 +277,7 @@ ProcedureCreate(char *procedureName,
 	values[i++] = (Datum) fmgr(F_TEXTIN, prosrc);		/* prosrc */
 	values[i++] = (Datum) fmgr(F_TEXTIN, probin);		/* probin */
 
-	rel = heap_openr(ProcedureRelationName);
+	rel = heap_openr(ProcedureRelationName, RowExclusiveLock);
 
 	tupDesc = rel->rd_att;
 	tup = heap_formtuple(tupDesc,
@@ -294,6 +294,6 @@ ProcedureCreate(char *procedureName,
 		CatalogIndexInsert(idescs, Num_pg_proc_indices, rel, tup);
 		CatalogCloseIndices(Num_pg_proc_indices, idescs);
 	}
-	heap_close(rel);
+	heap_close(rel, RowExclusiveLock);
 	return tup->t_data->t_oid;
 }
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index a219767858c1c225478a288aeedd461da30bb348..91c7cd995ba47254a3659d2204144e101390db8c 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.40 1999/07/17 20:16:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.41 1999/09/18 19:06:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,7 +119,7 @@ TypeGet(char *typeName,			/* name of type to be fetched */
 	 *	open the pg_type relation
 	 * ----------------
 	 */
-	pg_type_desc = heap_openr(TypeRelationName);
+	pg_type_desc = heap_openr(TypeRelationName, AccessShareLock);
 
 	/* ----------------
 	 *	scan the type relation for the information we want
@@ -133,7 +133,7 @@ TypeGet(char *typeName,			/* name of type to be fetched */
 	 *	close the type relation and return the type oid.
 	 * ----------------
 	 */
-	heap_close(pg_type_desc);
+	heap_close(pg_type_desc, AccessShareLock);
 
 	return typeoid;
 }
@@ -248,7 +248,7 @@ TypeShellMake(char *typeName)
 	 *	open pg_type
 	 * ----------------
 	 */
-	pg_type_desc = heap_openr(TypeRelationName);
+	pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
 
 	/* ----------------
 	 *	insert the shell tuple
@@ -260,7 +260,7 @@ TypeShellMake(char *typeName)
 	 *	close pg_type and return the tuple's oid.
 	 * ----------------
 	 */
-	heap_close(pg_type_desc);
+	heap_close(pg_type_desc, RowExclusiveLock);
 
 	return typoid;
 }
@@ -457,14 +457,7 @@ TypeCreate(char *typeName,
 	 *	open pg_type and begin a scan for the type name.
 	 * ----------------
 	 */
-	pg_type_desc = heap_openr(TypeRelationName);
-
-	/* -----------------
-	 * Set a write lock initially so as not upgrade a read to a write
-	 * when the heap_insert() or heap_replace() is called.
-	 * -----------------
-	 */
-	LockRelation(pg_type_desc, AccessExclusiveLock);
+	pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
 
 	typeKey[0].sk_argument = PointerGetDatum(typeName);
 	pg_type_scan = heap_beginscan(pg_type_desc,
@@ -521,8 +514,8 @@ TypeCreate(char *typeName,
 		CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
 		CatalogCloseIndices(Num_pg_type_indices, idescs);
 	}
-	UnlockRelation(pg_type_desc, AccessExclusiveLock);
-	heap_close(pg_type_desc);
+
+	heap_close(pg_type_desc, RowExclusiveLock);
 
 	return typeObjectId;
 }
@@ -541,7 +534,7 @@ TypeRename(char *oldTypeName, char *newTypeName)
 	HeapTuple	oldtup,
 				newtup;
 
-	pg_type_desc = heap_openr(TypeRelationName);
+	pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
 
 	oldtup = SearchSysCacheTupleCopy(TYPNAME,
 									 PointerGetDatum(oldTypeName),
@@ -549,7 +542,7 @@ TypeRename(char *oldTypeName, char *newTypeName)
 
 	if (!HeapTupleIsValid(oldtup))
 	{
-		heap_close(pg_type_desc);
+		heap_close(pg_type_desc, RowExclusiveLock);
 		elog(ERROR, "TypeRename: type %s not defined", oldTypeName);
 	}
 
@@ -559,7 +552,7 @@ TypeRename(char *oldTypeName, char *newTypeName)
 	if (HeapTupleIsValid(newtup))
 	{
 		pfree(oldtup);
-		heap_close(pg_type_desc);
+		heap_close(pg_type_desc, RowExclusiveLock);
 		elog(ERROR, "TypeRename: type %s already defined", newTypeName);
 	}
 
@@ -575,7 +568,7 @@ TypeRename(char *oldTypeName, char *newTypeName)
 	CatalogCloseIndices(Num_pg_type_indices, idescs);
 
 	pfree(oldtup);
-	heap_close(pg_type_desc);
+	heap_close(pg_type_desc, RowExclusiveLock);
 }
 
 /*
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index ebdd045ce4fa2a9c8fb9fbe3550557b38c07655c..f8196f86ab3e88b71ad95b2c246367269d271f5d 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -6,7 +6,7 @@
  * Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.53 1999/07/18 18:03:49 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.54 1999/09/18 19:06:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,16 +51,9 @@
  *	  transaction, since by assumption it is only called from outside any
  *	  transaction.
  *
- * Note that the system's use of pg_listener is confined to very short
- * intervals at the end of a transaction that contains NOTIFY statements,
- * or during the transaction caused by an inbound SIGUSR2.	So the fact that
- * pg_listener is a global resource shouldn't cause too much performance
- * problem.  But application authors ought to be discouraged from doing
- * LISTEN or UNLISTEN near the start of a long transaction --- that would
- * result in holding the pg_listener write lock for a long time, possibly
- * blocking unrelated activity.  It could even lead to deadlock against another
- * transaction that touches the same user tables and then tries to NOTIFY.
- * Probably best to do LISTEN or UNLISTEN outside of transaction blocks.
+ * Although we grab AccessExclusiveLock on pg_listener for any operation,
+ * the lock is never held very long, so it shouldn't cause too much of
+ * a performance problem.
  *
  * An application that listens on the same relname it notifies will get
  * NOTIFY messages for its own NOTIFYs.  These can be ignored, if not useful,
@@ -155,26 +148,21 @@ Async_Notify(char *relname)
 
 	TPRINTF(TRACE_NOTIFY, "Async_Notify: %s", relname);
 
-	/*
-	 * We allocate list memory from the global malloc pool to ensure that
-	 * it will live until we want to use it.  This is probably not
-	 * necessary any longer, since we will use it before the end of the
-	 * transaction. DLList only knows how to use malloc() anyway, but we
-	 * could probably palloc() the strings...
-	 */
 	if (!pendingNotifies)
 		pendingNotifies = DLNewList();
-	notifyName = strdup(relname);
-	DLAddHead(pendingNotifies, DLNewElem(notifyName));
-
-	/*
-	 * NOTE: we could check to see if pendingNotifies already has an entry
-	 * for relname, and thus avoid making duplicate entries.  However,
-	 * most apps probably don't notify the same name multiple times per
-	 * transaction, so we'd likely just be wasting cycles to make such a
-	 * check. AsyncExistsPendingNotify() doesn't really care whether the
-	 * list contains duplicates...
-	 */
+	/* no point in making duplicate entries in the list ... */
+	if (!AsyncExistsPendingNotify(relname))
+	{
+		/*
+		 * We allocate list memory from the global malloc pool to ensure
+		 * that it will live until we want to use it.  This is probably not
+		 * necessary any longer, since we will use it before the end of the
+		 * transaction. DLList only knows how to use malloc() anyway, but we
+		 * could probably palloc() the strings...
+		 */
+		notifyName = strdup(relname);
+		DLAddHead(pendingNotifies, DLNewElem(notifyName));
+	}
 }
 
 /*
@@ -212,8 +200,7 @@ Async_Listen(char *relname, int pid)
 
 	TPRINTF(TRACE_NOTIFY, "Async_Listen: %s", relname);
 
-	lRel = heap_openr(ListenerRelationName);
-	LockRelation(lRel, AccessExclusiveLock);
+	lRel = heap_openr(ListenerRelationName, AccessExclusiveLock);
 	tdesc = RelationGetDescr(lRel);
 
 	/* Detect whether we are already listening on this relname */
@@ -236,9 +223,8 @@ Async_Listen(char *relname, int pid)
 
 	if (alreadyListener)
 	{
+		heap_close(lRel, AccessExclusiveLock);
 		elog(NOTICE, "Async_Listen: We are already listening on %s", relname);
-		UnlockRelation(lRel, AccessExclusiveLock);
-		heap_close(lRel);
 		return;
 	}
 
@@ -262,8 +248,7 @@ Async_Listen(char *relname, int pid)
 	heap_insert(lRel, newtup);
 	pfree(newtup);
 
-	UnlockRelation(lRel, AccessExclusiveLock);
-	heap_close(lRel);
+	heap_close(lRel, AccessExclusiveLock);
 
 	/*
 	 * now that we are listening, make sure we will unlisten before dying.
@@ -308,18 +293,14 @@ Async_Unlisten(char *relname, int pid)
 
 	TPRINTF(TRACE_NOTIFY, "Async_Unlisten %s", relname);
 
+	lRel = heap_openr(ListenerRelationName, AccessExclusiveLock);
 	/* Note we assume there can be only one matching tuple. */
 	lTuple = SearchSysCacheTuple(LISTENREL, PointerGetDatum(relname),
 								 Int32GetDatum(pid),
 								 0, 0);
 	if (lTuple != NULL)
-	{
-		lRel = heap_openr(ListenerRelationName);
-		LockRelation(lRel, AccessExclusiveLock);
 		heap_delete(lRel, &lTuple->t_self, NULL);
-		UnlockRelation(lRel, AccessExclusiveLock);
-		heap_close(lRel);
-	}
+	heap_close(lRel, AccessExclusiveLock);
 
 	/*
 	 * We do not complain about unlistening something not being listened;
@@ -354,8 +335,7 @@ Async_UnlistenAll()
 
 	TPRINTF(TRACE_NOTIFY, "Async_UnlistenAll");
 
-	lRel = heap_openr(ListenerRelationName);
-	LockRelation(lRel, AccessExclusiveLock);
+	lRel = heap_openr(ListenerRelationName, AccessExclusiveLock);
 	tdesc = RelationGetDescr(lRel);
 
 	/* Find and delete all entries with my listenerPID */
@@ -369,8 +349,7 @@ Async_UnlistenAll()
 		heap_delete(lRel, &lTuple->t_self, NULL);
 
 	heap_endscan(sRel);
-	UnlockRelation(lRel, AccessExclusiveLock);
-	heap_close(lRel);
+	heap_close(lRel, AccessExclusiveLock);
 }
 
 /*
@@ -462,8 +441,7 @@ AtCommit_Notify()
 
 	TPRINTF(TRACE_NOTIFY, "AtCommit_Notify");
 
-	lRel = heap_openr(ListenerRelationName);
-	LockRelation(lRel, AccessExclusiveLock);
+	lRel = heap_openr(ListenerRelationName, AccessExclusiveLock);
 	tdesc = RelationGetDescr(lRel);
 	sRel = heap_beginscan(lRel, 0, SnapshotNow, 0, (ScanKey) NULL);
 
@@ -542,10 +520,13 @@ AtCommit_Notify()
 	heap_endscan(sRel);
 
 	/*
-	 * We do not do RelationUnsetLockForWrite(lRel) here, because the
-	 * transaction is about to be committed anyway.
+	 * We do NOT release the lock on pg_listener here; we need to hold it
+	 * until end of transaction (which is about to happen, anyway) to
+	 * ensure that notified backends see our tuple updates when they look.
+	 * Else they might disregard the signal, which would make the
+	 * application programmer very unhappy.
 	 */
-	heap_close(lRel);
+	heap_close(lRel, NoLock);
 
 	ClearPendingNotifies();
 
@@ -756,8 +737,7 @@ ProcessIncomingNotify(void)
 
 	StartTransactionCommand();
 
-	lRel = heap_openr(ListenerRelationName);
-	LockRelation(lRel, AccessExclusiveLock);
+	lRel = heap_openr(ListenerRelationName, AccessExclusiveLock);
 	tdesc = RelationGetDescr(lRel);
 
 	/* Scan only entries with my listenerPID */
@@ -794,10 +774,13 @@ ProcessIncomingNotify(void)
 	heap_endscan(sRel);
 
 	/*
-	 * We do not do RelationUnsetLockForWrite(lRel) here, because the
-	 * transaction is about to be committed anyway.
+	 * We do NOT release the lock on pg_listener here; we need to hold it
+	 * until end of transaction (which is about to happen, anyway) to
+	 * ensure that other backends see our tuple updates when they look.
+	 * Otherwise, a transaction started after this one might mistakenly
+	 * think it doesn't need to send this backend a new NOTIFY.
 	 */
-	heap_close(lRel);
+	heap_close(lRel, NoLock);
 
 	CommitTransactionCommand();
 
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 6f99a920f5a3ec5a69dda786bc090f9eda7fe2bc..d578fc263f030aa4ccd6904bec26b2bb9e2a7848 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.44 1999/07/17 20:16:51 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.45 1999/09/18 19:06:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -101,29 +101,20 @@ cluster(char *oldrelname, char *oldindexname)
 
 	/*
 	 * Like vacuum, cluster spans transactions, so I'm going to handle it
-	 * in the same way.
+	 * in the same way: commit and restart transactions where needed.
+	 *
+	 * We grab exclusive access to the target rel and index for the
+	 * duration of the initial transaction.
 	 */
 
-	/* matches the StartTransaction in PostgresMain() */
-
-	OldHeap = heap_openr(oldrelname);
-	if (!RelationIsValid(OldHeap))
-	{
-		elog(ERROR, "cluster: unknown relation: \"%s\"",
-			 oldrelname);
-	}
-	OIDOldHeap = RelationGetRelid(OldHeap);		/* Get OID for the index
-												 * scan    */
+	OldHeap = heap_openr(oldrelname, AccessExclusiveLock);
+	OIDOldHeap = RelationGetRelid(OldHeap);
 
 	OldIndex = index_openr(oldindexname);		/* Open old index relation	*/
-	if (!RelationIsValid(OldIndex))
-	{
-		elog(ERROR, "cluster: unknown index: \"%s\"",
-			 oldindexname);
-	}
-	OIDOldIndex = RelationGetRelid(OldIndex);	/* OID for the index scan		  */
+	LockRelation(OldIndex, AccessExclusiveLock);
+	OIDOldIndex = RelationGetRelid(OldIndex);
 
-	heap_close(OldHeap);
+	heap_close(OldHeap, NoLock); /* do NOT give up the locks */
 	index_close(OldIndex);
 
 	/*
@@ -132,7 +123,7 @@ cluster(char *oldrelname, char *oldindexname)
 	 * will get the lock after being blocked and add rows which won't be
 	 * present in the new table. Bleagh! I'd be best to try and ensure
 	 * that no-one's in the tables for the entire duration of this process
-	 * with a pg_vlock.
+	 * with a pg_vlock.  XXX Isn't the above comment now invalid?
 	 */
 	NewHeap = copy_heap(OIDOldHeap);
 	OIDNewHeap = RelationGetRelid(NewHeap);
@@ -171,7 +162,7 @@ cluster(char *oldrelname, char *oldindexname)
 	renamerel(NewIndexName, saveoldindexname);
 
 	/*
-	 * Again flush all the buffers.
+	 * Again flush all the buffers.  XXX perhaps not needed?
 	 */
 	CommitTransactionCommand();
 	StartTransactionCommand();
@@ -193,7 +184,7 @@ copy_heap(Oid OIDOldHeap)
 	 */
 	snprintf(NewName, NAMEDATALEN, "temp_%x", OIDOldHeap);
 
-	OldHeap = heap_open(OIDOldHeap);
+	OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
 	OldHeapDesc = RelationGetDescr(OldHeap);
 
 	/*
@@ -209,10 +200,11 @@ copy_heap(Oid OIDOldHeap)
 	if (!OidIsValid(OIDNewHeap))
 		elog(ERROR, "clusterheap: cannot create temporary heap relation\n");
 
-	NewHeap = heap_open(OIDNewHeap);
+	/* XXX why are we bothering to do this: */
+	NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
 
-	heap_close(NewHeap);
-	heap_close(OldHeap);
+	heap_close(NewHeap, AccessExclusiveLock);
+	heap_close(OldHeap, AccessExclusiveLock);
 
 	return NewHeap;
 }
@@ -233,7 +225,7 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
 	int			natts;
 	FuncIndexInfo *finfo;
 
-	NewHeap = heap_open(OIDNewHeap);
+	NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
 	OldIndex = index_open(OIDOldIndex);
 
 	/*
@@ -305,8 +297,8 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
 				 Old_pg_index_Form->indisunique,
 				 Old_pg_index_Form->indisprimary);
 
-	heap_close(OldIndex);
-	heap_close(NewHeap);
+	index_close(OldIndex);
+	heap_close(NewHeap, AccessExclusiveLock);
 }
 
 
@@ -326,8 +318,8 @@ rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
 	 * Open the relations I need. Scan through the OldHeap on the OldIndex
 	 * and insert each tuple into the NewHeap.
 	 */
-	LocalNewHeap = (Relation) heap_open(OIDNewHeap);
-	LocalOldHeap = (Relation) heap_open(OIDOldHeap);
+	LocalNewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
+	LocalOldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
 	LocalOldIndex = (Relation) index_open(OIDOldIndex);
 
 	ScanDesc = index_beginscan(LocalOldIndex, false, 0, (ScanKey) NULL);
@@ -344,6 +336,6 @@ rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
 	index_endscan(ScanDesc);
 
 	index_close(LocalOldIndex);
-	heap_close(LocalOldHeap);
-	heap_close(LocalNewHeap);
+	heap_close(LocalOldHeap, AccessExclusiveLock);
+	heap_close(LocalNewHeap, AccessExclusiveLock);
 }
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 7fe62cf1246b1937908b5c1df0976516dcdec1c3..8872bcdfac72ab79a8682c12256a87c8a0eeed60 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.53 1999/09/04 21:19:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.54 1999/09/18 19:06:40 tgl Exp $
  *
  * NOTES
  *	  The PortalExecutorHeapMemory crap needs to be eliminated
@@ -283,6 +283,7 @@ PerformAddAttribute(char *relationName,
 {
 	Relation	rel,
 				attrdesc;
+	Oid			myrelid;
 	HeapTuple	reltup;
 	HeapTuple	attributeTuple;
 	Form_pg_attribute attribute;
@@ -310,6 +311,14 @@ PerformAddAttribute(char *relationName,
 			 relationName);
 #endif
 
+	/*
+	 * Grab an exclusive lock on the target table, which we will NOT release
+	 * until end of transaction.
+	 */
+	rel = heap_openr(relationName, AccessExclusiveLock);
+	myrelid = RelationGetRelid(rel);
+	heap_close(rel, NoLock);	/* close rel but keep lock! */
+
 	/*
 	 * we can't add a not null attribute
 	 */
@@ -331,20 +340,10 @@ PerformAddAttribute(char *relationName,
 	{
 		if (inherits)
 		{
-			Oid			myrelid,
-						childrelid;
+			Oid			childrelid;
 			List	   *child,
 					   *children;
 
-			rel = heap_openr(relationName);
-			if (!RelationIsValid(rel))
-			{
-				elog(ERROR, "PerformAddAttribute: unknown relation: \"%s\"",
-					 relationName);
-			}
-			myrelid = RelationGetRelid(rel);
-			heap_close(rel);
-
 			/* this routine is actually in the planner */
 			children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
 
@@ -358,31 +357,23 @@ PerformAddAttribute(char *relationName,
 				childrelid = lfirsti(child);
 				if (childrelid == myrelid)
 					continue;
-				rel = heap_open(childrelid);
-				if (!RelationIsValid(rel))
-				{
-					elog(ERROR, "PerformAddAttribute: can't find catalog entry for inheriting class with oid %u",
-						 childrelid);
-				}
+				rel = heap_open(childrelid, AccessExclusiveLock);
 				PerformAddAttribute((rel->rd_rel->relname).data,
 									userName, false, colDef);
-				heap_close(rel);
+				heap_close(rel, AccessExclusiveLock);
 			}
 		}
 	}
 
-	rel = heap_openr(RelationRelationName);
+	rel = heap_openr(RelationRelationName, RowExclusiveLock);
 
 	reltup = SearchSysCacheTupleCopy(RELNAME,
 									 PointerGetDatum(relationName),
 									 0, 0, 0);
 
 	if (!HeapTupleIsValid(reltup))
-	{
-		heap_close(rel);
 		elog(ERROR, "PerformAddAttribute: relation \"%s\" not found",
 			 relationName);
-	}
 
 	/*
 	 * XXX is the following check sufficient?
@@ -391,23 +382,15 @@ PerformAddAttribute(char *relationName,
 	{
 		elog(ERROR, "PerformAddAttribute: index relation \"%s\" not changed",
 			 relationName);
-		return;
 	}
 
 	minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
 	maxatts = minattnum + 1;
 	if (maxatts > MaxHeapAttributeNumber)
-	{
-		pfree(reltup);
-		heap_close(rel);
 		elog(ERROR, "PerformAddAttribute: relations limited to %d attributes",
 			 MaxHeapAttributeNumber);
-	}
-
-	attrdesc = heap_openr(AttributeRelationName);
 
-	Assert(attrdesc);
-	Assert(RelationGetForm(attrdesc));
+	attrdesc = heap_openr(AttributeRelationName, RowExclusiveLock);
 
 	/*
 	 * Open all (if any) pg_attribute indices
@@ -438,12 +421,8 @@ PerformAddAttribute(char *relationName,
 								  0, 0);
 
 		if (HeapTupleIsValid(tup))
-		{
-			heap_close(attrdesc);
-			heap_close(rel);
 			elog(ERROR, "PerformAddAttribute: attribute \"%s\" already exists in class \"%s\"",
 				 colDef->colname, relationName);
-		}
 
 		/*
 		 * check to see if it is an array attribute.
@@ -490,7 +469,8 @@ PerformAddAttribute(char *relationName,
 
 	if (hasindex)
 		CatalogCloseIndices(Num_pg_attr_indices, idescs);
-	heap_close(attrdesc);
+
+	heap_close(attrdesc, RowExclusiveLock);
 
 	((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
 	heap_replace(rel, &reltup->t_self, reltup, NULL);
@@ -501,7 +481,7 @@ PerformAddAttribute(char *relationName,
 	CatalogCloseIndices(Num_pg_class_indices, ridescs);
 
 	pfree(reltup);
-	heap_close(rel);
+	heap_close(rel, RowExclusiveLock);
 }
 
 void
@@ -510,9 +490,9 @@ LockTableCommand(LockStmt *lockstmt)
 	Relation	rel;
 	int			aclresult;
 
-	rel = heap_openr(lockstmt->relname);
-	if (rel == NULL)
-		elog(ERROR, "LOCK TABLE: relation %s can't be openned", lockstmt->relname);
+	rel = heap_openr(lockstmt->relname, NoLock);
+	if (! RelationIsValid(rel))
+		elog(ERROR, "Relation '%s' does not exist", lockstmt->relname);
 
 	if (lockstmt->mode == AccessShareLock)
 		aclresult = pg_aclcheck(lockstmt->relname, GetPgUserName(), ACL_RD);
@@ -524,4 +504,5 @@ LockTableCommand(LockStmt *lockstmt)
 
 	LockRelation(rel, lockstmt->mode);
 
+	heap_close(rel, NoLock);	/* close rel, keep lock */
 }
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 35f3d6da0b31470ac617aa0b01fb98a2a353886b..493d2a170e10662ba23b337e0883cd9698cce6a6 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.87 1999/09/11 22:28:11 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.88 1999/09/18 19:06:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -251,22 +251,22 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
 	Relation	rel;
 	extern char *UserName;		/* defined in global.c */
 	const AclMode required_access = from ? ACL_WR : ACL_RD;
+	LOCKMODE	required_lock = from ? AccessExclusiveLock : AccessShareLock;
+	/* Note: AccessExclusive is probably overkill for copying to a relation,
+	 * but that's what the existing code grabs on the rel's indices.  If
+	 * this is relaxed then I think the index locks need relaxed also.
+	 */
 	int			result;
 
-	rel = heap_openr(relname);
-	if (rel == NULL)
-		elog(ERROR, "COPY command failed.  Class %s "
-			 "does not exist.", relname);
+	rel = heap_openr(relname, required_lock);
 
 	result = pg_aclcheck(relname, UserName, required_access);
 	if (result != ACLCHECK_OK)
 		elog(ERROR, "%s: %s", relname, aclcheck_error_strings[result]);
-	/* Above should not return */
-	else if (!superuser() && !pipe)
+	else if (!pipe && !superuser())
 		elog(ERROR, "You must have Postgres superuser privilege to do a COPY "
 			 "directly to or from a file.  Anyone can COPY to stdout or "
 			 "from stdin.  Psql's \\copy command also works for anyone.");
-	/* Above should not return. */
 	else
 	{
 		if (from)
@@ -342,6 +342,8 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
 				pq_endcopyout(false);
 		}
 	}
+
+	heap_close(rel, required_lock);
 }
 
 
@@ -500,8 +502,6 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
 		pfree(elements);
 		pfree(typmod);
 	}
-
-	heap_close(rel);
 }
 
 static void
@@ -905,20 +905,19 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
 		pfree(typmod);
 	}
 
-	/* comments in execUtils.c */
 	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]);
 		}
 	}
-	heap_close(rel);
 }
 
 
@@ -991,7 +990,7 @@ IsTypeByVal(Oid type)
 /*
  * 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 heap_open().
+ * using index_open().
  *
  * Space for the array itself is palloc'ed.
  */
@@ -1017,7 +1016,7 @@ GetIndexRelations(Oid main_relation_oid,
 	int			i;
 	bool		isnull;
 
-	pg_index_rel = heap_openr(IndexRelationName);
+	pg_index_rel = heap_openr(IndexRelationName, AccessShareLock);
 	scandesc = heap_beginscan(pg_index_rel, 0, SnapshotNow, 0, NULL);
 	tupDesc = RelationGetDescr(pg_index_rel);
 
@@ -1044,7 +1043,7 @@ GetIndexRelations(Oid main_relation_oid,
 	}
 
 	heap_endscan(scandesc);
-	heap_close(pg_index_rel);
+	heap_close(pg_index_rel, AccessShareLock);
 
 	/* We cannot trust to relhasindex of the main_relation now, so... */
 	if (*n_indices == 0)
@@ -1055,7 +1054,7 @@ GetIndexRelations(Oid main_relation_oid,
 	for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
 	{
 		(*index_rels)[i] = index_open(scan->index_rel_oid);
-		/* comments in execUtils.c */
+		/* 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)
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
index b93a40e7ba326629e1f7981aa1f1f2d400c736cd..c1069dd41e6948f78d576be7a07c9b22f428c8ed 100644
--- a/src/backend/commands/creatinh.c
+++ b/src/backend/commands/creatinh.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.45 1999/07/17 20:16:52 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.46 1999/09/18 19:06:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -202,14 +202,13 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
 	 */
 	foreach(entry, schema)
 	{
-		List	   *rest;
 		ColumnDef  *coldef = lfirst(entry);
+		List	   *rest;
 
 		foreach(rest, lnext(entry))
 		{
-
 			/*
-			 * check for duplicated relation names
+			 * check for duplicated names within the new relation
 			 */
 			ColumnDef  *restdef = lfirst(rest);
 
@@ -246,17 +245,14 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
 		TupleDesc	tupleDesc;
 		TupleConstr *constr;
 
-		relation = heap_openr(name);
-		if (relation == NULL)
-		{
-			elog(ERROR,
-				 "MergeAttr: Can't inherit from non-existent superclass '%s'", name);
-		}
-		if (relation->rd_rel->relkind == 'S')
-			elog(ERROR, "MergeAttr: Can't inherit from sequence superclass '%s'", name);
+		relation = heap_openr(name, AccessShareLock);
 		tupleDesc = RelationGetDescr(relation);
 		constr = tupleDesc->constr;
 
+		/* XXX shouldn't this test be stricter?  No indexes, for example? */
+		if (relation->rd_rel->relkind == 'S')
+			elog(ERROR, "MergeAttr: Can't inherit from sequence superclass '%s'", name);
+
 		for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--)
 		{
 			Form_pg_attribute attribute = tupleDesc->attrs[attrno];
@@ -340,9 +336,11 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
 		}
 
 		/*
-		 * iteration cleanup and result collection
+		 * Close the parent rel, but keep our AccessShareLock on it until
+		 * xact commit.  That will prevent someone else from deleting or
+		 * ALTERing the parent before the child is committed.
 		 */
-		heap_close(relation);
+		heap_close(relation, NoLock);
 
 		/*
 		 * wants the inherited schema to appear in the order they are
@@ -386,7 +384,7 @@ StoreCatalogInheritance(Oid relationId, List *supers)
 	 * Catalog INHERITS information.
 	 * ----------------
 	 */
-	relation = heap_openr(InheritsRelationName);
+	relation = heap_openr(InheritsRelationName, RowExclusiveLock);
 	desc = RelationGetDescr(relation);
 
 	seqNumber = 1;
@@ -422,7 +420,7 @@ StoreCatalogInheritance(Oid relationId, List *supers)
 		seqNumber += 1;
 	}
 
-	heap_close(relation);
+	heap_close(relation, RowExclusiveLock);
 
 	/* ----------------
 	 * Catalog IPL information.
@@ -510,7 +508,7 @@ again:
 	 *	3.
 	 * ----------------
 	 */
-	relation = heap_openr(InheritancePrecidenceListRelationName);
+	relation = heap_openr(InheritancePrecidenceListRelationName, RowExclusiveLock);
 	desc = RelationGetDescr(relation);
 
 	seqNumber = 1;
@@ -537,7 +535,7 @@ again:
 		seqNumber += 1;
 	}
 
-	heap_close(relation);
+	heap_close(relation, RowExclusiveLock);
 }
 
 /*
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index b779715fe8e3863847ffccffa656c7dc35294b8e..24eb5b531d392f4a014a965951aacf68f582b5a4 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.39 1999/07/17 20:16:52 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.40 1999/09/18 19:06:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -103,6 +103,8 @@ destroydb(char *dbname, CommandDest dest)
 	/* stop the vacuum daemon */
 	stop_vacuum(dbpath, dbname);
 
+	/* XXX what about stopping backends connected to the target database? */
+
 	path = ExpandDatabasePath(dbpath);
 	if (path == NULL)
 		elog(ERROR, "Unable to locate path '%s'"
@@ -189,6 +191,7 @@ check_permissions(char *command,
 	utup = SearchSysCacheTuple(USENAME,
 							   PointerGetDatum(userName),
 							   0, 0, 0);
+	Assert(utup);
 	*userIdP = ((Form_pg_shadow) GETSTRUCT(utup))->usesysid;
 	use_super = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
 	use_createdb = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;
@@ -211,22 +214,13 @@ check_permissions(char *command,
 	/* Check to make sure database is owned by this user */
 
 	/*
-	 * need the reldesc to get the database owner out of dbtup and to set
-	 * a write lock on it.
+	 * Acquire exclusive lock on pg_database from the beginning, even though
+	 * we only need read access right here, to avoid potential deadlocks
+	 * from upgrading our lock later.  (Is this still necessary?  Could we
+	 * use something weaker than exclusive lock?)
 	 */
-	dbrel = heap_openr(DatabaseRelationName);
-
-	if (!RelationIsValid(dbrel))
-		elog(FATAL, "%s: cannot open relation \"%-.*s\"",
-			 command, DatabaseRelationName);
+	dbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
 
-	/*
-	 * Acquire a write lock on pg_database from the beginning to avoid
-	 * upgrading a read lock to a write lock.  Upgrading causes long
-	 * delays when multiple 'createdb's or 'destroydb's are run simult.
-	 * -mer 7/3/91
-	 */
-	LockRelation(dbrel, AccessExclusiveLock);
 	dbtup = get_pg_dbtup(command, dbname, dbrel);
 	dbfound = HeapTupleIsValid(dbtup);
 
@@ -248,7 +242,8 @@ check_permissions(char *command,
 	else
 		*dbIdP = InvalidOid;
 
-	heap_close(dbrel);
+	/* We will keep the lock on dbrel until end of transaction. */
+	heap_close(dbrel, NoLock);
 
 	/*
 	 * Now be sure that the user is allowed to do this.
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 3b1da18783dad53e12e926077ba588938eaa993a..11e5c39423918fa3ba8081eff5e4ae95647698c8 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 1994-5, Regents of the University of California
  *
- *	  $Id: explain.c,v 1.47 1999/09/11 19:06:36 tgl Exp $
+ *	  $Id: explain.c,v 1.48 1999/09/18 19:06:40 tgl Exp $
  *
  */
 
@@ -211,11 +211,14 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
 			i = 0;
 			foreach(l, ((IndexScan *) plan)->indxid)
 			{
-				relation = RelationIdCacheGetRelation((int) lfirst(l));
+				relation = RelationIdGetRelation(lfirsti(l));
+				Assert(relation);
 				if (++i > 1)
 					appendStringInfo(str, ", ");
 				appendStringInfo(str,
 								 stringStringInfo((RelationGetRelationName(relation))->data));
+				/* drop relcache refcount from RelationIdGetRelation */
+				RelationDecrementReferenceCount(relation);
 			}
 		case T_SeqScan:
 			if (((Scan *) plan)->scanrelid > 0)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 31d3419bee671b5e2773ca7d6368dfcabd75d800..113854311d6aaf22b855fd59077154e7f3241812 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.10 1999/08/22 20:14:37 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.11 1999/09/18 19:06:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -324,15 +324,15 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
 		FIsetProcOid(funcInfo, tuple->t_data->t_oid);
 	}
 
-	heapRelation = heap_open(relationId);
+	heapRelation = heap_open(relationId, ShareLock);
 	indexRelation = index_open(indexId);
 
-	LockRelation(heapRelation, ShareLock);
-
 	InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
 
 	index_build(heapRelation, indexRelation, numberOfAttributes,
 				attributeNumberA, 0, NULL, funcInfo, predInfo);
+
+	/* heap and index rels are closed as a side-effect of index_build */
 }
 
 
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 21fde2af57997bbceeb1d8280f61d6e6c2a432a0..b2fc76f090bc0b0fd60d249b73c2e2e6a03cb164 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -120,15 +120,14 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	values[i++] = ObjectIdGetDatum(procTup->t_data->t_oid);
 	values[i++] = (Datum) fmgr(F_TEXTIN, stmt->plcompiler);
 
-	rel = heap_openr(LanguageRelationName);
+	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
 
 	tupDesc = rel->rd_att;
 	tup = heap_formtuple(tupDesc, values, nulls);
 
 	heap_insert(rel, tup);
 
-	heap_close(rel);
-	return;
+	heap_close(rel, RowExclusiveLock);
 }
 
 
@@ -160,6 +159,8 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 	 */
 	case_translate_language_name(stmt->plname, languageName);
 
+	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
+
 	langTup = SearchSysCacheTupleCopy(LANNAME,
 									  PointerGetDatum(languageName),
 									  0, 0, 0);
@@ -167,14 +168,11 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 		elog(ERROR, "Language %s doesn't exist", languageName);
 
 	if (!((Form_pg_language) GETSTRUCT(langTup))->lanispl)
-	{
 		elog(ERROR, "Language %s isn't a created procedural language",
 			 languageName);
-	}
 
-	rel = heap_openr(LanguageRelationName);
 	heap_delete(rel, &langTup->t_self, NULL);
 
 	pfree(langTup);
-	heap_close(rel);
+	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index af20c79f17db8a7b13a7bac6ffa5d71efe8cc30a..a73964cb02c3b1908afa842afdb31865b667c13b 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.36 1999/07/17 20:16:53 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.37 1999/09/18 19:06:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,13 +75,14 @@ RemoveOperator(char *operatorName,		/* operator name */
 	else
 		oprtype = 'r';
 
+	relation = heap_openr(OperatorRelationName, RowExclusiveLock);
+
 	tup = SearchSysCacheTupleCopy(OPRNAME,
 								  PointerGetDatum(operatorName),
 								  ObjectIdGetDatum(typeId1),
 								  ObjectIdGetDatum(typeId2),
 								  CharGetDatum(oprtype));
 
-	relation = heap_openr(OperatorRelationName);
 	if (HeapTupleIsValid(tup))
 	{
 #ifndef NO_SECURITY
@@ -117,7 +118,7 @@ RemoveOperator(char *operatorName,		/* operator name */
 		}
 	}
 	pfree(tup);
-	heap_close(relation);
+	heap_close(relation, RowExclusiveLock);
 }
 
 #ifdef NOTYET
@@ -141,7 +142,7 @@ SingleOpOperatorRemove(Oid typeOid)
 
 	ScanKeyEntryInitialize(&key[0],
 						   0, 0, F_OIDEQ, (Datum) typeOid);
-	rel = heap_openr(OperatorRelationName);
+	rel = heap_openr(OperatorRelationName, RowExclusiveLock);
 	for (i = 0; i < 3; ++i)
 	{
 		key[0].sk_attno = attnums[i];
@@ -150,7 +151,7 @@ SingleOpOperatorRemove(Oid typeOid)
 			heap_delete(rel, &tup->t_self, NULL);
 		heap_endscan(scan);
 	}
-	heap_close(rel);
+	heap_close(rel, RowExclusiveLock);
 }
 
 /*
@@ -187,7 +188,7 @@ AttributeAndRelationRemove(Oid typeOid)
 	oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
 	oidptr->next = NULL;
 	optr = oidptr;
-	rel = heap_openr(AttributeRelationName);
+	rel = heap_openr(AttributeRelationName, AccessShareLock);
 	scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
 	while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
 	{
@@ -197,14 +198,15 @@ AttributeAndRelationRemove(Oid typeOid)
 	}
 	optr->next = NULL;
 	heap_endscan(scan);
-	heap_close(rel);
+	heap_close(rel, AccessShareLock);
 
+	optr = oidptr;
 
 	ScanKeyEntryInitialize(&key[0], 0,
 						   ObjectIdAttributeNumber,
 						   F_OIDEQ, (Datum) 0);
-	optr = oidptr;
-	rel = heap_openr(RelationRelationName);
+	/* get RowExclusiveLock because heap_destroy will need it */
+	rel = heap_openr(RelationRelationName, RowExclusiveLock);
 	while (PointerIsValid((char *) optr->next))
 	{
 		key[0].sk_argument = (Datum) (optr++)->reloid;
@@ -217,9 +219,9 @@ AttributeAndRelationRemove(Oid typeOid)
 			name = (((Form_pg_class) GETSTRUCT(tup))->relname).data;
 			heap_destroy_with_catalog(name);
 		}
+		heap_endscan(scan);
 	}
-	heap_endscan(scan);
-	heap_close(rel);
+	heap_close(rel, RowExclusiveLock);
 }
 
 #endif	 /* NOTYET */
@@ -245,18 +247,17 @@ RemoveType(char *typeName)		/* type name to be removed */
 			 typeName);
 #endif
 
-	relation = heap_openr(TypeRelationName);
+	relation = heap_openr(TypeRelationName, RowExclusiveLock);
+
 	tup = SearchSysCacheTuple(TYPNAME,
 							  PointerGetDatum(typeName),
 							  0, 0, 0);
-
 	if (!HeapTupleIsValid(tup))
 	{
-		heap_close(relation);
+		heap_close(relation, RowExclusiveLock);
 		elog(ERROR, "RemoveType: type '%s' does not exist", typeName);
 	}
 
-	relation = heap_openr(TypeRelationName);
 	typeOid = tup->t_data->t_oid;
 	heap_delete(relation, &tup->t_self, NULL);
 
@@ -267,14 +268,13 @@ RemoveType(char *typeName)		/* type name to be removed */
 							  0, 0, 0);
 	if (!HeapTupleIsValid(tup))
 	{
-		heap_close(relation);
-		elog(ERROR, "RemoveType: type '%s' does not exist", typeName);
+		heap_close(relation, RowExclusiveLock);
+		elog(ERROR, "RemoveType: type '%s' does not exist", shadow_type);
 	}
 
-	typeOid = tup->t_data->t_oid;
 	heap_delete(relation, &tup->t_self, NULL);
 
-	heap_close(relation);
+	heap_close(relation, RowExclusiveLock);
 }
 
 /*
@@ -328,7 +328,7 @@ RemoveFunction(char *functionName,		/* function name to be removed */
 	}
 #endif
 
-	relation = heap_openr(ProcedureRelationName);
+	relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
 	tup = SearchSysCacheTuple(PRONAME,
 							  PointerGetDatum(functionName),
 							  Int32GetDatum(nargs),
@@ -337,19 +337,19 @@ RemoveFunction(char *functionName,		/* function name to be removed */
 
 	if (!HeapTupleIsValid(tup))
 	{
-		heap_close(relation);
+		heap_close(relation, RowExclusiveLock);
 		func_error("RemoveFunction", functionName, nargs, argList, NULL);
 	}
 
 	if ((((Form_pg_proc) GETSTRUCT(tup))->prolang) == INTERNALlanguageId)
 	{
-		heap_close(relation);
+		heap_close(relation, RowExclusiveLock);
 		elog(ERROR, "RemoveFunction: function \"%s\" is built-in", functionName);
 	}
 
 	heap_delete(relation, &tup->t_self, NULL);
 
-	heap_close(relation);
+	heap_close(relation, RowExclusiveLock);
 }
 
 void
@@ -398,7 +398,7 @@ RemoveAggregate(char *aggName, char *aggType)
 	}
 #endif
 
-	relation = heap_openr(AggregateRelationName);
+	relation = heap_openr(AggregateRelationName, RowExclusiveLock);
 	tup = SearchSysCacheTuple(AGGNAME,
 							  PointerGetDatum(aggName),
 							  ObjectIdGetDatum(basetypeID),
@@ -406,7 +406,7 @@ RemoveAggregate(char *aggName, char *aggType)
 
 	if (!HeapTupleIsValid(tup))
 	{
-		heap_close(relation);
+		heap_close(relation, RowExclusiveLock);
 		if (aggType)
 		{
 			elog(ERROR, "RemoveAggregate: aggregate '%s' for '%s' does not exist",
@@ -420,5 +420,5 @@ RemoveAggregate(char *aggName, char *aggType)
 	}
 	heap_delete(relation, &tup->t_self, NULL);
 
-	heap_close(relation);
+	heap_close(relation, RowExclusiveLock);
 }
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
index 1a93027b4a3c412e47047c0461b1e50cac26dfd1..3a822bd4e49ce6c2782440124fa3657b8a201460 100644
--- a/src/backend/commands/rename.c
+++ b/src/backend/commands/rename.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.32 1999/07/17 20:16:53 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.33 1999/09/18 19:06:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,6 +48,7 @@ renameatt(char *relname,
 		  char *userName,
 		  int recurse)
 {
+	Relation	targetrelation;
 	Relation	attrelation;
 	HeapTuple	reltup,
 				oldatttup,
@@ -71,6 +72,14 @@ renameatt(char *relname,
 			 relname);
 #endif
 
+	/*
+	 * Grab an exclusive lock on the target table, which we will NOT release
+	 * until end of transaction.
+	 */
+	targetrelation = heap_openr(relname, AccessExclusiveLock);
+	relid = RelationGetRelid(targetrelation);
+	heap_close(targetrelation, NoLock);	/* close rel but keep lock! */
+
 	/*
 	 * if the 'recurse' flag is set then we are supposed to rename this
 	 * attribute in all classes that inherit from 'relname' (as well as in
@@ -82,16 +91,11 @@ renameatt(char *relname,
 	 */
 	if (recurse)
 	{
-		Oid			myrelid,
-					childrelid;
 		List	   *child,
 				   *children;
 
-		if ((myrelid = RelnameFindRelid(relname)) == InvalidOid)
-			elog(ERROR, "renameatt: unknown relation: \"%s\"", relname);
-
 		/* this routine is actually in the planner */
-		children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
+		children = find_all_inheritors(lconsi(relid, NIL), NIL);
 
 		/*
 		 * find_all_inheritors does the recursive search of the
@@ -100,10 +104,11 @@ renameatt(char *relname,
 		 */
 		foreach(child, children)
 		{
+			Oid			childrelid;
 			char		childname[NAMEDATALEN];
 
 			childrelid = lfirsti(child);
-			if (childrelid == myrelid)
+			if (childrelid == relid)
 				continue;
 			reltup = SearchSysCacheTuple(RELOID,
 										 ObjectIdGetDatum(childrelid),
@@ -117,14 +122,12 @@ renameatt(char *relname,
 			StrNCpy(childname,
 					((Form_pg_class) GETSTRUCT(reltup))->relname.data,
 					NAMEDATALEN);
-			/* no more recursion! */
+			/* note we need not recurse again! */
 			renameatt(childname, oldattname, newattname, userName, 0);
 		}
 	}
 
-
-	if ((relid = RelnameFindRelid(relname)) == InvalidOid)
-		elog(ERROR, "renameatt: relation \"%s\" nonexistent", relname);
+	attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
 
 	oldatttup = SearchSysCacheTupleCopy(ATTNAME,
 										ObjectIdGetDatum(relid),
@@ -150,7 +153,6 @@ renameatt(char *relname,
 	StrNCpy((((Form_pg_attribute) (GETSTRUCT(oldatttup)))->attname.data),
 			newattname, NAMEDATALEN);
 
-	attrelation = heap_openr(AttributeRelationName);
 	heap_replace(attrelation, &oldatttup->t_self, oldatttup, NULL);
 
 	/* keep system catalog indices current */
@@ -159,7 +161,7 @@ renameatt(char *relname,
 	CatalogCloseIndices(Num_pg_attr_indices, irelations);
 
 	pfree(oldatttup);
-	heap_close(attrelation);
+	heap_close(attrelation, RowExclusiveLock);
 }
 
 /*
@@ -182,6 +184,7 @@ void
 renamerel(char *oldrelname, char *newrelname)
 {
 	int			i;
+	Relation	targetrelation;
 	Relation	relrelation;	/* for RELATION relation */
 	HeapTuple	oldreltup;
 	char		oldpath[MAXPGPATH],
@@ -198,6 +201,15 @@ renamerel(char *oldrelname, char *newrelname)
 		elog(ERROR, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
 			 newrelname);
 
+	/*
+	 * Grab an exclusive lock on the target table, which we will NOT release
+	 * until end of transaction.
+	 */
+	targetrelation = heap_openr(oldrelname, AccessExclusiveLock);
+	heap_close(targetrelation, NoLock);	/* close rel but keep lock! */
+
+	relrelation = heap_openr(RelationRelationName, RowExclusiveLock);
+
 	oldreltup = SearchSysCacheTupleCopy(RELNAME,
 										PointerGetDatum(oldrelname),
 										0, 0, 0);
@@ -207,12 +219,17 @@ renamerel(char *oldrelname, char *newrelname)
 	if (RelnameFindRelid(newrelname) != InvalidOid)
 		elog(ERROR, "renamerel: relation \"%s\" exists", newrelname);
 
+	/*
+	 * XXX need to close relation and flush dirty buffers here!
+	 */
+
 	/* rename the path first, so if this fails the rename's not done */
 	strcpy(oldpath, relpath(oldrelname));
 	strcpy(newpath, relpath(newrelname));
 	if (rename(oldpath, newpath) < 0)
 		elog(ERROR, "renamerel: unable to rename file: %s", oldpath);
 
+	/* rename additional segments of relation, too */
 	for (i = 1;; i++)
 	{
 		sprintf(toldpath, "%s.%d", oldpath, i);
@@ -225,7 +242,6 @@ renamerel(char *oldrelname, char *newrelname)
 			newrelname, NAMEDATALEN);
 
 	/* insert fixed rel tuple */
-	relrelation = heap_openr(RelationRelationName);
 	heap_replace(relrelation, &oldreltup->t_self, oldreltup, NULL);
 
 	/* keep the system catalog indices current */
@@ -233,5 +249,5 @@ renamerel(char *oldrelname, char *newrelname)
 	CatalogIndexInsert(irelations, Num_pg_class_indices, relrelation, oldreltup);
 	CatalogCloseIndices(Num_pg_class_indices, irelations);
 
-	heap_close(relrelation);
+	heap_close(relrelation, RowExclusiveLock);
 }
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index b7f959cd65eed7a01a76cde6c2093f5a17340640..be47d32f9f9abbbb9615aff038de5f0a4227a19c 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -153,10 +153,7 @@ DefineSequence(CreateSeqStmt *seq)
 
 	DefineRelation(stmt, RELKIND_SEQUENCE);
 
-	rel = heap_openr(seq->seqname);
-	Assert(RelationIsValid(rel));
-
-	LockRelation(rel, AccessExclusiveLock);
+	rel = heap_openr(seq->seqname, AccessExclusiveLock);
 
 	tupDesc = RelationGetDescr(rel);
 
@@ -179,11 +176,7 @@ DefineSequence(CreateSeqStmt *seq)
 	if (WriteBuffer(buf) == STATUS_ERROR)
 		elog(ERROR, "DefineSequence: WriteBuffer failed");
 
-	UnlockRelation(rel, AccessExclusiveLock);
-	heap_close(rel);
-
-	return;
-
+	heap_close(rel, AccessExclusiveLock);
 }
 
 
@@ -422,12 +415,7 @@ init_sequence(char *caller, char *name)
 		temp = elm;
 	}
 
-	temp->rel = heap_openr(name);
-
-	if (!RelationIsValid(temp->rel))
-		elog(ERROR, "%s.%s: sequence does not exist", name, caller);
-
-	LockRelation(temp->rel, AccessShareLock);
+	temp->rel = heap_openr(name, AccessShareLock);
 
 	if (temp->rel->rd_rel->relkind != RELKIND_SEQUENCE)
 		elog(ERROR, "%s.%s: %s is not sequence !", name, caller, name);
@@ -453,7 +441,6 @@ init_sequence(char *caller, char *name)
 	}
 
 	return elm;
-
 }
 
 
@@ -467,20 +454,15 @@ CloseSequences(void)
 	SeqTable	elm;
 	Relation	rel;
 
-	for (elm = seqtab; elm != (SeqTable) NULL;)
+	for (elm = seqtab; elm != (SeqTable) NULL; elm = elm->next)
 	{
 		if (elm->rel != (Relation) NULL)		/* opened in current xact */
 		{
 			rel = elm->rel;
 			elm->rel = (Relation) NULL;
-			UnlockRelation(rel, AccessShareLock);
-			heap_close(rel);
+			heap_close(rel, AccessShareLock);
 		}
-		elm = elm->next;
 	}
-
-	return;
-
 }
 
 
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 55f67711c77514c2eae9fbe1713edcb982c66978..aa7a0b56c1d0988e2e208b384db0ba2e8599496b 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -63,11 +63,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 		elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
 #endif
 
-	rel = heap_openr(stmt->relname);
-	if (!RelationIsValid(rel))
-		elog(ERROR, "CreateTrigger: there is no relation %s", stmt->relname);
-
-	LockRelation(rel, AccessExclusiveLock);
+	rel = heap_openr(stmt->relname, AccessExclusiveLock);
 
 	TRIGGER_CLEAR_TYPE(tgtype);
 	if (stmt->before)
@@ -103,8 +99,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 	}
 
 	/* Scan pg_trigger */
-	tgrel = heap_openr(TriggerRelationName);
-	LockRelation(tgrel, AccessExclusiveLock);
+	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
 						   F_OIDEQ, RelationGetRelid(rel));
 	tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
@@ -203,20 +198,19 @@ CreateTrigger(CreateTrigStmt *stmt)
 	CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
 	CatalogCloseIndices(Num_pg_trigger_indices, idescs);
 	pfree(tuple);
-	UnlockRelation(tgrel, AccessExclusiveLock);
-	heap_close(tgrel);
+	heap_close(tgrel, RowExclusiveLock);
 
 	pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
 	pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
 
 	/* update pg_class */
+	pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheTupleCopy(RELNAME,
 									PointerGetDatum(stmt->relname),
 									0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "CreateTrigger: relation %s not found in pg_class", stmt->relname);
 
-	pgrel = heap_openr(RelationRelationName);
 	((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
 	RelationInvalidateHeapTuple(pgrel, tuple);
 	heap_replace(pgrel, &tuple->t_self, tuple, NULL);
@@ -224,7 +218,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 	CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
 	CatalogCloseIndices(Num_pg_class_indices, ridescs);
 	pfree(tuple);
-	heap_close(pgrel);
+	heap_close(pgrel, RowExclusiveLock);
 
 	CommandCounterIncrement();
 	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
@@ -232,8 +226,8 @@ CreateTrigger(CreateTrigStmt *stmt)
 	rel->rd_rel->reltriggers = found + 1;
 	RelationBuildTriggers(rel);
 	MemoryContextSwitchTo(oldcxt);
-	heap_close(rel);
-	return;
+	/* Keep lock on target rel until end of xact */
+	heap_close(rel, NoLock);
 }
 
 void
@@ -255,14 +249,9 @@ DropTrigger(DropTrigStmt *stmt)
 		elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
 #endif
 
-	rel = heap_openr(stmt->relname);
-	if (!RelationIsValid(rel))
-		elog(ERROR, "DropTrigger: there is no relation %s", stmt->relname);
+	rel = heap_openr(stmt->relname, AccessExclusiveLock);
 
-	LockRelation(rel, AccessExclusiveLock);
-
-	tgrel = heap_openr(TriggerRelationName);
-	LockRelation(tgrel, AccessExclusiveLock);
+	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
 						   F_OIDEQ, RelationGetRelid(rel));
 	tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
@@ -282,20 +271,19 @@ DropTrigger(DropTrigStmt *stmt)
 		elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
 			 stmt->trigname, stmt->relname);
 	if (tgfound > 1)
-		elog(NOTICE, "DropTrigger: found (and deleted) %d trigger %s on relation %s",
+		elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
 			 tgfound, stmt->trigname, stmt->relname);
 	heap_endscan(tgscan);
-	UnlockRelation(tgrel, AccessExclusiveLock);
-	heap_close(tgrel);
+	heap_close(tgrel, RowExclusiveLock);
 
+	/* update pg_class */
+	pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheTupleCopy(RELNAME,
 									PointerGetDatum(stmt->relname),
 									0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "DropTrigger: relation %s not found in pg_class", stmt->relname);
 
-	/* update pg_class */
-	pgrel = heap_openr(RelationRelationName);
 	((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
 	RelationInvalidateHeapTuple(pgrel, tuple);
 	heap_replace(pgrel, &tuple->t_self, tuple, NULL);
@@ -303,7 +291,7 @@ DropTrigger(DropTrigStmt *stmt)
 	CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
 	CatalogCloseIndices(Num_pg_class_indices, ridescs);
 	pfree(tuple);
-	heap_close(pgrel);
+	heap_close(pgrel, RowExclusiveLock);
 
 	CommandCounterIncrement();
 	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
@@ -312,8 +300,8 @@ DropTrigger(DropTrigStmt *stmt)
 	if (found > 0)
 		RelationBuildTriggers(rel);
 	MemoryContextSwitchTo(oldcxt);
-	heap_close(rel);
-	return;
+	/* Keep lock on target rel until end of xact */
+	heap_close(rel, NoLock);
 }
 
 void
@@ -324,8 +312,7 @@ RelationRemoveTriggers(Relation rel)
 	ScanKeyData key;
 	HeapTuple	tup;
 
-	tgrel = heap_openr(TriggerRelationName);
-	LockRelation(tgrel, AccessExclusiveLock);
+	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
 	ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
 						   F_OIDEQ, RelationGetRelid(rel));
 
@@ -335,9 +322,7 @@ RelationRemoveTriggers(Relation rel)
 		heap_delete(tgrel, &tup->t_self, NULL);
 
 	heap_endscan(tgscan);
-	UnlockRelation(tgrel, AccessExclusiveLock);
-	heap_close(tgrel);
-
+	heap_close(tgrel, RowExclusiveLock);
 }
 
 void
@@ -367,7 +352,7 @@ RelationBuildTriggers(Relation relation)
 						   (RegProcedure) F_OIDEQ,
 						   ObjectIdGetDatum(RelationGetRelid(relation)));
 
-	tgrel = heap_openr(TriggerRelationName);
+	tgrel = heap_openr(TriggerRelationName, AccessShareLock);
 	irel = index_openr(TriggerRelidIndex);
 	sd = index_beginscan(irel, false, 1, &skey);
 
@@ -441,7 +426,7 @@ RelationBuildTriggers(Relation relation)
 	index_endscan(sd);
 	pfree(sd);
 	index_close(irel);
-	heap_close(tgrel);
+	heap_close(tgrel, AccessShareLock);
 
 	/* Build trigdesc */
 	trigdesc->triggers = triggers;
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 1b0d972839e40cab6a009758176807ae88590d5a..c05b6da58562893b1dfab6b31e1a436572141162 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: user.c,v 1.33 1999/07/30 18:09:47 momjian Exp $
+ * $Id: user.c,v 1.34 1999/09/18 19:06:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,13 +36,15 @@ static void CheckPgUserAclNotNull(void);
  *
  * copy the modified contents of pg_shadow to a file used by the postmaster
  * for user authentication.  The file is stored as $PGDATA/pg_pwd.
+ *
+ * NB: caller is responsible for ensuring that only one backend can
+ * execute this routine at a time.  Acquiring AccessExclusiveLock on
+ * pg_shadow is the standard way to do that.
  *---------------------------------------------------------------------
  */
-static
-void
+static void
 UpdatePgPwdFile(char *sql, CommandDest dest)
 {
-
 	char	   *filename,
 			   *tempname;
 	int			bufsize;
@@ -125,17 +127,13 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
 
 	/*
 	 * Scan the pg_shadow relation to be certain the user doesn't already
-	 * exist.
+	 * exist.  Note we secure exclusive lock, because we also need to be
+	 * sure of what the next usesysid should be, and we need to protect
+	 * our update of the flat password file.
 	 */
-	pg_shadow_rel = heap_openr(ShadowRelationName);
+	pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
 	pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
 
-	/*
-	 * Secure a write lock on pg_shadow so we can be sure of what the next
-	 * usesysid should be.
-	 */
-	LockRelation(pg_shadow_rel, AccessExclusiveLock);
-
 	scan = heap_beginscan(pg_shadow_rel, false, SnapshotNow, 0, NULL);
 	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
 	{
@@ -152,8 +150,7 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
 
 	if (exists)
 	{
-		UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
-		heap_close(pg_shadow_rel);
+		heap_close(pg_shadow_rel, AccessExclusiveLock);
 		UserAbortTransactionBlock();
 		elog(ERROR,
 		 "defineUser: user \"%s\" has already been created", stmt->user);
@@ -165,6 +162,12 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
 	 *
 	 * XXX Ugly as this code is, it still fails to cope with ' or \ in any of
 	 * the provided strings.
+	 *
+	 * XXX This routine would be *lots* better if it inserted the new
+	 * tuple with formtuple/heap_insert.  For one thing, all of the
+	 * transaction-block gamesmanship could be eliminated, because
+	 * it's only there to make the world safe for a recursive call
+	 * to pg_exec_query_dest().
 	 */
 	snprintf(sql, SQL_LENGTH,
 			 "insert into %s (usename,usesysid,usecreatedb,usetrace,"
@@ -189,17 +192,21 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
 	pg_exec_query_dest(sql, dest, false);
 
 	/*
-	 * Add the stuff here for groups.
+	 * Add stuff here for groups?
 	 */
 
+	/*
+	 * Write the updated pg_shadow data to the flat password file.
+	 * Because we are still holding AccessExclusiveLock on pg_shadow,
+	 * we can be sure no other backend will try to write the flat
+	 * file at the same time.
+	 */
 	UpdatePgPwdFile(sql, dest);
 
 	/*
-	 * This goes after the UpdatePgPwdFile to be certain that two backends
-	 * to not attempt to write to the pg_pwd file at the same time.
+	 * Now we can clean up.
 	 */
-	UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
-	heap_close(pg_shadow_rel);
+	heap_close(pg_shadow_rel, AccessExclusiveLock);
 
 	if (IsTransactionBlock() && !inblock)
 		EndTransactionBlock();
@@ -237,70 +244,79 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest)
 
 	/*
 	 * Scan the pg_shadow relation to be certain the user exists.
+	 * Note we secure exclusive lock to protect our update of the
+	 * flat password file.
 	 */
-	pg_shadow_rel = heap_openr(ShadowRelationName);
+	pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
 	pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
 
-	/*
-	 * Secure a write lock on pg_shadow so we can be sure that when the
-	 * dump of the pg_pwd file is done, there is not another backend doing
-	 * the same.
-	 */
-	LockRelation(pg_shadow_rel, AccessExclusiveLock);
-
 	tuple = SearchSysCacheTuple(USENAME,
 								PointerGetDatum(stmt->user),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
-		UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
-		heap_close(pg_shadow_rel);
-		UserAbortTransactionBlock();	/* needed? */
+		heap_close(pg_shadow_rel, AccessExclusiveLock);
+		UserAbortTransactionBlock();
 		elog(ERROR, "alterUser: user \"%s\" does not exist", stmt->user);
-		return;
 	}
 
 	/*
 	 * Create the update statement to modify the user.
+	 *
+	 * XXX see diatribe in preceding routine.  This code is just as bogus.
 	 */
 	snprintf(sql, SQL_LENGTH, "update %s set", ShadowRelationName);
 
 	if (stmt->password)
-		snprintf(sql, SQL_LENGTH, "%s passwd = '%s'", pstrdup(sql), stmt->password);
+		snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
+				 " passwd = '%s'", stmt->password);
 
 	if (stmt->createdb)
 	{
-		snprintf(sql, SQL_LENGTH, "%s %susecreatedb='%s'",
-				 pstrdup(sql), stmt->password ? "," : "",
+		snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
+				 "%s usecreatedb='%s'",
+				 stmt->password ? "," : "",
 				 *stmt->createdb ? "t" : "f");
 	}
 
 	if (stmt->createuser)
 	{
-		snprintf(sql, SQL_LENGTH, "%s %susesuper='%s'",
-			 pstrdup(sql), (stmt->password || stmt->createdb) ? "," : "",
+		snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
+				 "%s usesuper='%s'",
+				 (stmt->password || stmt->createdb) ? "," : "",
 				 *stmt->createuser ? "t" : "f");
 	}
 
 	if (stmt->validUntil)
 	{
-		snprintf(sql, SQL_LENGTH, "%s %svaluntil='%s'",
-				 pstrdup(sql),
+		snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
+				 "%s valuntil='%s'",
 		(stmt->password || stmt->createdb || stmt->createuser) ? "," : "",
 				 stmt->validUntil);
 	}
 
-	snprintf(sql, SQL_LENGTH, "%s where usename = '%s'",
-			 pstrdup(sql), stmt->user);
+	snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
+			 " where usename = '%s'",
+			 stmt->user);
 
 	pg_exec_query_dest(sql, dest, false);
 
-	/* do the pg_group stuff here */
+	/*
+	 * Add stuff here for groups?
+	 */
 
+	/*
+	 * Write the updated pg_shadow data to the flat password file.
+	 * Because we are still holding AccessExclusiveLock on pg_shadow,
+	 * we can be sure no other backend will try to write the flat
+	 * file at the same time.
+	 */
 	UpdatePgPwdFile(sql, dest);
 
-	UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
-	heap_close(pg_shadow_rel);
+	/*
+	 * Now we can clean up.
+	 */
+	heap_close(pg_shadow_rel, AccessExclusiveLock);
 
 	if (IsTransactionBlock() && !inblock)
 		EndTransactionBlock();
@@ -310,7 +326,6 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest)
 extern void
 RemoveUser(char *user, CommandDest dest)
 {
-
 	char	   *pg_shadow;
 	Relation	pg_shadow_rel,
 				pg_rel;
@@ -318,7 +333,7 @@ RemoveUser(char *user, CommandDest dest)
 	HeapScanDesc scan;
 	HeapTuple	tuple;
 	Datum		datum;
-	char		sql[512];
+	char		sql[SQL_LENGTH];
 	bool		n,
 				inblock;
 	int32		usesysid;
@@ -341,27 +356,19 @@ RemoveUser(char *user, CommandDest dest)
 	}
 
 	/*
-	 * Perform a scan of the pg_shadow relation to find the usesysid of
-	 * the user to be deleted.	If it is not found, then return a warning
-	 * message.
+	 * Scan the pg_shadow relation to find the usesysid of the user to be
+	 * deleted.  Note we secure exclusive lock, because we need to protect
+	 * our update of the flat password file.
 	 */
-	pg_shadow_rel = heap_openr(ShadowRelationName);
+	pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
 	pg_dsc = RelationGetDescr(pg_shadow_rel);
 
-	/*
-	 * Secure a write lock on pg_shadow so we can be sure that when the
-	 * dump of the pg_pwd file is done, there is not another backend doing
-	 * the same.
-	 */
-	LockRelation(pg_shadow_rel, AccessExclusiveLock);
-
 	tuple = SearchSysCacheTuple(USENAME,
 								PointerGetDatum(user),
 								0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
-		UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
-		heap_close(pg_shadow_rel);
+		heap_close(pg_shadow_rel, AccessExclusiveLock);
 		UserAbortTransactionBlock();
 		elog(ERROR, "removeUser: user \"%s\" does not exist", user);
 	}
@@ -372,7 +379,7 @@ RemoveUser(char *user, CommandDest dest)
 	 * Perform a scan of the pg_database relation to find the databases
 	 * owned by usesysid.  Then drop them.
 	 */
-	pg_rel = heap_openr(DatabaseRelationName);
+	pg_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
 	pg_dsc = RelationGetDescr(pg_rel);
 
 	scan = heap_beginscan(pg_rel, false, SnapshotNow, 0, NULL);
@@ -383,7 +390,7 @@ RemoveUser(char *user, CommandDest dest)
 		if ((int) datum == usesysid)
 		{
 			datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n);
-			if (memcmp((void *) datum, "template1", 9))
+			if (memcmp((void *) datum, "template1", 9) != 0)
 			{
 				dbase =
 					(char **) repalloc((void *) dbase, sizeof(char *) * (ndbase + 1));
@@ -394,12 +401,12 @@ RemoveUser(char *user, CommandDest dest)
 		}
 	}
 	heap_endscan(scan);
-	heap_close(pg_rel);
+	heap_close(pg_rel, AccessExclusiveLock);
 
 	while (ndbase--)
 	{
 		elog(NOTICE, "Dropping database %s", dbase[ndbase]);
-		snprintf(sql, SQL_LENGTH, "drop database %s", dbase[ndbase]);
+		snprintf(sql, SQL_LENGTH, "DROP DATABASE %s", dbase[ndbase]);
 		pfree((void *) dbase[ndbase]);
 		pg_exec_query_dest(sql, dest, false);
 	}
@@ -431,10 +438,18 @@ RemoveUser(char *user, CommandDest dest)
 		"delete from %s where usename = '%s'", ShadowRelationName, user);
 	pg_exec_query_dest(sql, dest, false);
 
+	/*
+	 * Write the updated pg_shadow data to the flat password file.
+	 * Because we are still holding AccessExclusiveLock on pg_shadow,
+	 * we can be sure no other backend will try to write the flat
+	 * file at the same time.
+	 */
 	UpdatePgPwdFile(sql, dest);
 
-	UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
-	heap_close(pg_shadow_rel);
+	/*
+	 * Now we can clean up.
+	 */
+	heap_close(pg_shadow_rel, AccessExclusiveLock);
 
 	if (IsTransactionBlock() && !inblock)
 		EndTransactionBlock();
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 55ec864fca5b02559e3f450ce4af72c51f899ed3..3027763b46861368eaf2f585795ec2b9440f185c 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.119 1999/08/25 12:20:57 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.120 1999/09/18 19:06:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -304,7 +304,7 @@ vc_getrels(NameData *VacRelP)
 	portalmem = PortalGetVariableMemory(vc_portal);
 	vrl = cur = (VRelList) NULL;
 
-	rel = heap_openr(RelationRelationName);
+	rel = heap_openr(RelationRelationName, AccessShareLock);
 	tupdesc = RelationGetDescr(rel);
 
 	scan = heap_beginscan(rel, false, SnapshotNow, 1, &key);
@@ -343,9 +343,8 @@ vc_getrels(NameData *VacRelP)
 	if (found == false)
 		elog(NOTICE, "Vacuum: table not found");
 
-
 	heap_endscan(scan);
-	heap_close(rel);
+	heap_close(rel, AccessShareLock);
 
 	CommitTransactionCommand();
 
@@ -395,8 +394,10 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
 		return;
 	}
 
-	/* now open the class and vacuum it */
-	onerel = heap_open(relid);
+	/*
+	 * Open the class, get an exclusive lock on it, and vacuum it
+	 */
+	onerel = heap_open(relid, AccessExclusiveLock);
 
 	vacrelstats = (VRelStats *) palloc(sizeof(VRelStats));
 	vacrelstats->relid = relid;
@@ -509,9 +510,6 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
 		vacrelstats->vacattrstats = (VacAttrStats *) NULL;
 	}
 
-	/* we require the relation to be locked until the indices are cleaned */
-	LockRelation(onerel, AccessExclusiveLock);
-
 	GetXmaxRecent(&XmaxRecent);
 
 	/* scan it */
@@ -565,13 +563,13 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
 			pfree(fraged_pages.vpl_pagedesc);
 	}
 
-	/* all done with this class */
-	heap_close(onerel);
-
 	/* update statistics in pg_class */
 	vc_updstats(vacrelstats->relid, vacrelstats->num_pages,
 			vacrelstats->num_tuples, vacrelstats->hasindex, vacrelstats);
 
+	/* all done with this class, but hold lock until commit */
+	heap_close(onerel, NoLock);
+
 	/* next command frees attribute stats */
 	CommitTransactionCommand();
 }
@@ -2281,6 +2279,8 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
 	/*
 	 * update number of tuples and number of pages in pg_class
 	 */
+	rd = heap_openr(RelationRelationName, RowExclusiveLock);
+
 	ctup = SearchSysCacheTupleCopy(RELOID,
 								   ObjectIdGetDatum(relid),
 								   0, 0, 0);
@@ -2288,8 +2288,6 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
 		elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
 			 relid);
 
-	rd = heap_openr(RelationRelationName);
-
 	/* get the buffer cache tuple */
 	rtup.t_self = ctup->t_self;
 	heap_fetch(rd, SnapshotNow, &rtup, &buffer);
@@ -2306,8 +2304,8 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
 		VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
 		int			natts = vacrelstats->va_natts;
 
-		ad = heap_openr(AttributeRelationName);
-		sd = heap_openr(StatisticRelationName);
+		ad = heap_openr(AttributeRelationName, RowExclusiveLock);
+		sd = heap_openr(StatisticRelationName, RowExclusiveLock);
 		ScanKeyEntryInitialize(&askey, 0, Anum_pg_attribute_attrelid,
 							   F_INT4EQ, relid);
 
@@ -2458,8 +2456,8 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
 			}
 		}
 		heap_endscan(scan);
-		heap_close(ad);
-		heap_close(sd);
+		heap_close(ad, RowExclusiveLock);
+		heap_close(sd, RowExclusiveLock);
 	}
 
 	/*
@@ -2469,7 +2467,7 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
 
 	WriteBuffer(buffer);
 
-	heap_close(rd);
+	heap_close(rd, RowExclusiveLock);
 }
 
 /*
@@ -2484,7 +2482,7 @@ vc_delhilowstats(Oid relid, int attcnt, int *attnums)
 	HeapTuple	tuple;
 	ScanKeyData key;
 
-	pgstatistic = heap_openr(StatisticRelationName);
+	pgstatistic = heap_openr(StatisticRelationName, RowExclusiveLock);
 
 	if (relid != InvalidOid)
 	{
@@ -2515,7 +2513,7 @@ vc_delhilowstats(Oid relid, int attcnt, int *attnums)
 	}
 
 	heap_endscan(scan);
-	heap_close(pgstatistic);
+	heap_close(pgstatistic, RowExclusiveLock);
 }
 
 /*
@@ -2721,7 +2719,7 @@ vc_getindices(Oid relid, int *nindices, Relation **Irel)
 	ioid = (Oid *) palloc(10 * sizeof(Oid));
 
 	/* prepare a heap scan on the pg_index relation */
-	pgindex = heap_openr(IndexRelationName);
+	pgindex = heap_openr(IndexRelationName, AccessShareLock);
 	tupdesc = RelationGetDescr(pgindex);
 
 	ScanKeyEntryInitialize(&key, 0x0, Anum_pg_index_indrelid,
@@ -2741,7 +2739,7 @@ vc_getindices(Oid relid, int *nindices, Relation **Irel)
 	}
 
 	heap_endscan(scan);
-	heap_close(pgindex);
+	heap_close(pgindex, AccessShareLock);
 
 	if (i == 0)
 	{							/* No one index found */
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 40a94fd02c85021c143e85890be6a198a45be4be..9c1b7b8bb41ae19405de1579bd071c1764521f44 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -1,11 +1,11 @@
 /*-------------------------------------------------------------------------
  *
  * execAmi.c
- *	  miscellanious executor access method routines
+ *	  miscellaneous executor access method routines
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: execAmi.c,v 1.41 1999/07/17 20:16:56 momjian Exp $
+ *	$Id: execAmi.c,v 1.42 1999/09/18 19:06:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,7 +52,6 @@
 
 static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
 			  bool isindex, ScanDirection dir, Snapshot snapshot);
-static Relation ExecOpenR(Oid relationOid, bool isindex);
 
 /* ----------------------------------------------------------------
  *		ExecOpenScanR
@@ -90,47 +89,33 @@ ExecOpenScanR(Oid relOid,
 	 *		  abstraction someday -cim 9/9/89
 	 * ----------------
 	 */
-	relation = ExecOpenR(relOid, isindex);
-	scanDesc = ExecBeginScan(relation,
-							 nkeys,
-							 skeys,
-							 isindex,
-							 dir,
-							 snapshot);
-
-	if (returnRelation != NULL)
-		*returnRelation = relation;
-	if (scanDesc != NULL)
-		*returnScanDesc = scanDesc;
-}
-
-/* ----------------------------------------------------------------
- *		ExecOpenR
- *
- *		returns a relation descriptor given an object id.
- * ----------------------------------------------------------------
- */
-static Relation
-ExecOpenR(Oid relationOid, bool isindex)
-{
-	Relation	relation;
-
-	relation = (Relation) NULL;
 
 	/* ----------------
 	 *	open the relation with the correct call depending
 	 *	on whether this is a heap relation or an index relation.
+	 *
+	 *	Do not lock the rel here; beginscan will acquire AccessShareLock.
 	 * ----------------
 	 */
 	if (isindex)
-		relation = index_open(relationOid);
+		relation = index_open(relOid);
 	else
-		relation = heap_open(relationOid);
+		relation = heap_open(relOid, NoLock);
 
 	if (relation == NULL)
-		elog(DEBUG, "ExecOpenR: relation == NULL, heap_open failed.");
+		elog(ERROR, "ExecOpenScanR: failed to open relation %u", relOid);
+
+	scanDesc = ExecBeginScan(relation,
+							 nkeys,
+							 skeys,
+							 isindex,
+							 dir,
+							 snapshot);
 
-	return relation;
+	if (returnRelation != NULL)
+		*returnRelation = relation;
+	if (scanDesc != NULL)
+		*returnScanDesc = scanDesc;
 }
 
 /* ----------------------------------------------------------------
@@ -243,15 +228,20 @@ ExecCloseR(Plan *node)
 	if (scanDesc != NULL)
 		heap_endscan(scanDesc);
 
+	/*
+	 * endscan released AccessShareLock acquired by beginscan.  If we are
+	 * holding any stronger locks on the rel, they should be held till end of
+	 * xact.  Therefore, we need only close the rel and not release locks.
+	 */
 	if (relation != NULL)
-		heap_close(relation);
+		heap_close(relation, NoLock);
 
 	/* ----------------
 	 *	if this is an index scan then we have to take care
 	 *	of the index relations as well..
 	 * ----------------
 	 */
-	if (nodeTag(node) == T_IndexScan)
+	if (IsA(node, IndexScan))
 	{
 		IndexScan  *iscan = (IndexScan *) node;
 		IndexScanState *indexstate;
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 48c0a885f3c27e1334ce8c47d3063c720935ce97..97dffe548f74577027a585331782d70d9ba4b1da 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.93 1999/07/17 20:16:57 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.94 1999/09/18 19:06:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -587,14 +587,12 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 		resultRelationIndex = resultRelation;
 		rtentry = rt_fetch(resultRelationIndex, rangeTable);
 		resultRelationOid = rtentry->relid;
-		resultRelationDesc = heap_open(resultRelationOid);
+		resultRelationDesc = heap_open(resultRelationOid, RowExclusiveLock);
 
 		if (resultRelationDesc->rd_rel->relkind == RELKIND_SEQUENCE)
 			elog(ERROR, "You can't change sequence relation %s",
 				 resultRelationDesc->rd_rel->relname.data);
 
-		LockRelation(resultRelationDesc, RowExclusiveLock);
-
 		resultRelationInfo = makeNode(RelationInfo);
 		resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
 		resultRelationInfo->ri_RelationDesc = resultRelationDesc;
@@ -636,8 +634,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 		{
 			rm = lfirst(l);
 			relid = ((RangeTblEntry *) nth(rm->rti - 1, rangeTable))->relid;
-			relation = heap_open(relid);
-			LockRelation(relation, RowShareLock);
+			relation = heap_open(relid, RowShareLock);
 			if (!(rm->info & ROW_MARK_FOR_UPDATE))
 				continue;
 			erm = (execRowMark *) palloc(sizeof(execRowMark));
@@ -758,7 +755,8 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 				 */
 				setheapoverride(true);
 
-				intoRelationDesc = heap_open(intoRelationId);
+				intoRelationDesc = heap_open(intoRelationId,
+											 AccessExclusiveLock);
 
 				setheapoverride(false);
 			}
@@ -809,14 +807,15 @@ EndPlan(Plan *plan, EState *estate)
 	}
 
 	/*
-	 * close the result relations if necessary
+	 * close the result relations if necessary,
+	 * but hold locks on them until xact commit
 	 */
 	if (resultRelationInfo != NULL)
 	{
 		Relation	resultRelationDesc;
 
 		resultRelationDesc = resultRelationInfo->ri_RelationDesc;
-		heap_close(resultRelationDesc);
+		heap_close(resultRelationDesc, NoLock);
 
 		/*
 		 * close indices on the result relation
@@ -828,7 +827,7 @@ EndPlan(Plan *plan, EState *estate)
 	 * close the "into" relation if necessary
 	 */
 	if (intoRelationDesc != NULL)
-		heap_close(intoRelationDesc);
+		heap_close(intoRelationDesc, NoLock);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 4bacf3f7bdbcc97980d138e49ed5245c631e8bcc..197995c346228efce0a8d30bc2ad71d0f02574a7 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.48 1999/07/16 04:58:47 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.49 1999/09/18 19:06:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -772,7 +772,7 @@ ExecOpenIndices(Oid resultRelationOid,
 	 *	open pg_index
 	 * ----------------
 	 */
-	indexRd = heap_openr(IndexRelationName);
+	indexRd = heap_openr(IndexRelationName, AccessShareLock);
 
 	/* ----------------
 	 *	form a scan key
@@ -856,7 +856,7 @@ ExecOpenIndices(Oid resultRelationOid,
 	 * ----------------
 	 */
 	heap_endscan(indexSd);
-	heap_close(indexRd);
+	heap_close(indexRd, AccessShareLock);
 
 	/* ----------------
 	 *	Now that we've collected the index information into three
@@ -913,7 +913,7 @@ ExecOpenIndices(Oid resultRelationOid,
 
 				/*
 				 * Hack for not btree and hash indices: they use relation
-				 * level exclusive locking on updation (i.e. - they are
+				 * 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
@@ -1010,7 +1010,7 @@ ExecCloseIndices(RelationInfo *resultRelationInfo)
 			continue;
 
 		/*
-		 * Notes in ExecOpenIndices.
+		 * See notes in ExecOpenIndices.
 		 */
 		if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID &&
 			relationDescs[i]->rd_rel->relam != HASH_AM_OID)
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 19a1e53b69fef29d28ae407145306cf3a935a165..bd515d51f97af7525138f828934cc24abd28d7c8 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.24 1999/07/17 19:01:21 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.25 1999/09/18 19:06:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -257,7 +257,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
 			reloid = rtentry->relid;
 			rri = makeNode(RelationInfo);
 			rri->ri_RangeTableIndex = es_rri->ri_RangeTableIndex;
-			rri->ri_RelationDesc = heap_open(reloid);
+			rri->ri_RelationDesc = heap_open(reloid, RowExclusiveLock);
 			rri->ri_NumIndices = 0;
 			rri->ri_IndexRelationDescs = NULL;	/* index descs */
 			rri->ri_IndexRelationInfo = NULL;	/* index key info */
@@ -484,7 +484,7 @@ ExecEndAppend(Append *node)
 
 		resultRelationInfo = (RelationInfo *) lfirst(resultRelationInfoList);
 		resultRelationDesc = resultRelationInfo->ri_RelationDesc;
-		heap_close(resultRelationDesc);
+		heap_close(resultRelationDesc, NoLock);
 		pfree(resultRelationInfo);
 		resultRelationInfoList = lnext(resultRelationInfoList);
 	}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 68fb4eda07e7f7820363b6373c59757fe67237c6..3964d5d5bbe9d234f6b8682bac54194ba458d815 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.71 1999/09/13 00:17:19 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.72 1999/09/18 19:06:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1163,7 +1163,7 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
 						   F_OIDEQ,
 						   ObjectIdGetDatum(pred_op));
 
-	relation = heap_openr(AccessMethodOperatorRelationName);
+	relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
 
 	/*
 	 * The following assumes that any given operator will only be in a
@@ -1178,6 +1178,8 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
 	if (!HeapTupleIsValid(tuple))
 	{
 		elog(DEBUG, "clause_pred_clause_test: unknown pred_op");
+		heap_endscan(scan);
+		heap_close(relation, AccessShareLock);
 		return false;
 	}
 	aform = (Form_pg_amop) GETSTRUCT(tuple);
@@ -1209,6 +1211,8 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
 	if (!HeapTupleIsValid(tuple))
 	{
 		elog(DEBUG, "clause_pred_clause_test: unknown clause_op");
+		heap_endscan(scan);
+		heap_close(relation, AccessShareLock);
 		return false;
 	}
 	aform = (Form_pg_amop) GETSTRUCT(tuple);
@@ -1224,8 +1228,10 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
 
 	test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
 	if (test_strategy == 0)
+	{
+		heap_close(relation, AccessShareLock);
 		return false;			/* the implication cannot be determined */
-
+	}
 
 	/*
 	 * 4. From the same opclass, find the operator for the test strategy
@@ -1241,14 +1247,18 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
 	if (!HeapTupleIsValid(tuple))
 	{
 		elog(DEBUG, "clause_pred_clause_test: unknown test_op");
+		heap_endscan(scan);
+		heap_close(relation, AccessShareLock);
 		return false;
 	}
 	aform = (Form_pg_amop) GETSTRUCT(tuple);
 
 	/* Get the test operator */
 	test_op = aform->amopopr;
+
 	heap_endscan(scan);
 
+	heap_close(relation, AccessShareLock);
 
 	/*
 	 * 5. Evaluate the test
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a22d3ed43ae8bbe247f1dc505f3073e067529b71..32a5bb52cda04e18c8e18205e259150b19e2d69c 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.67 1999/09/13 00:17:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.68 1999/09/18 19:07:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -627,7 +627,6 @@ pg_checkretval(Oid rettype, List *queryTreeList)
 	Resdom	   *resnode;
 	Relation	reln;
 	Oid			relid;
-	Oid			tletype;
 	int			relnatts;
 	int			i;
 
@@ -713,11 +712,7 @@ pg_checkretval(Oid rettype, List *queryTreeList)
 	 * declared return type, and be sure that attributes 1 .. n in the
 	 * target list match the declared types.
 	 */
-	reln = heap_open(typeTypeRelid(typ));
-
-	if (!RelationIsValid(reln))
-		elog(ERROR, "cannot open relation relid %u", typeTypeRelid(typ));
-
+	reln = heap_open(typeTypeRelid(typ), AccessShareLock);
 	relid = reln->rd_id;
 	relnatts = reln->rd_rel->relnatts;
 
@@ -729,41 +724,12 @@ pg_checkretval(Oid rettype, List *queryTreeList)
 	{
 		TargetEntry *tle = lfirst(tlist);
 		Node	   *thenode = tle->expr;
+		Oid			tletype = exprType(thenode);
 
-		tlist = lnext(tlist);
-		tletype = exprType(thenode);
-
-#ifdef NOT_USED					/* fix me */
-		/* this is tedious */
-		if (IsA(thenode, Var))
-			tletype = (Oid) ((Var *) thenode)->vartype;
-		else if (IsA(thenode, Const))
-			tletype = (Oid) ((Const *) thenode)->consttype;
-		else if (IsA(thenode, Param))
-			tletype = (Oid) ((Param *) thenode)->paramtype;
-		else if (IsA(thenode, Expr))
-			tletype = Expr;
-
-		else if (IsA(thenode, LispList))
-		{
-			thenode = lfirst(thenode);
-			if (IsA(thenode, Oper))
-				tletype = (Oid) get_opresulttype((Oper *) thenode);
-			else if (IsA(thenode, Func))
-				tletype = (Oid) get_functype((Func *) thenode);
-			else
-				elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
-		}
-		else
-			elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
-#endif
-		/* reach right in there, why don't you? */
 		if (tletype != reln->rd_att->attrs[i - 1]->atttypid)
 			elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
+		tlist = lnext(tlist);
 	}
 
-	heap_close(reln);
-
-	/* success */
-	return;
+	heap_close(reln, AccessShareLock);
 }
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 9ca188bce62d42e8c7c8ac60a50400fdeaf71cd0..ef120f8d2fe513df543ac5203102e955391ac782 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.37 1999/09/09 02:35:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.38 1999/09/18 19:07:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -126,17 +126,19 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
 	/* Find an index on the given relation */
 	if (first)
 	{
-		if (RelationIsValid(relation))
-			heap_close(relation);
 		if (HeapScanIsValid(scan))
 			heap_endscan(scan);
+		scan = (HeapScanDesc) NULL;
+		if (RelationIsValid(relation))
+			heap_close(relation, AccessShareLock);
+		relation = (Relation) NULL;
 
 		ScanKeyEntryInitialize(&indexKey, 0,
 							   Anum_pg_index_indrelid,
 							   F_OIDEQ,
 							   ObjectIdGetDatum(indrelid));
 
-		relation = heap_openr(IndexRelationName);
+		relation = heap_openr(IndexRelationName, AccessShareLock);
 		scan = heap_beginscan(relation, 0, SnapshotNow,
 							  1, &indexKey);
 	}
@@ -146,7 +148,7 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
 	if (!HeapTupleIsValid(indexTuple))
 	{
 		heap_endscan(scan);
-		heap_close(relation);
+		heap_close(relation, AccessShareLock);
 		scan = (HeapScanDesc) NULL;
 		relation = (Relation) NULL;
 		return 0;
@@ -190,7 +192,7 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
 	info->relam = relam;
 	info->pages = indexRelation->rd_rel->relpages;
 	info->tuples = indexRelation->rd_rel->reltuples;
-	heap_close(indexRelation);
+	index_close(indexRelation);
 
 	/*
 	 * Find the index ordering keys
@@ -390,7 +392,7 @@ find_inheritance_children(Oid inhparent)
 	key[0].sk_nargs = key[0].sk_func.fn_nargs;
 
 	key[0].sk_argument = ObjectIdGetDatum((Oid) inhparent);
-	relation = heap_openr(InheritsRelationName);
+	relation = heap_openr(InheritsRelationName, AccessShareLock);
 	scan = heap_beginscan(relation, 0, SnapshotNow, 1, key);
 	while (HeapTupleIsValid(inheritsTuple = heap_getnext(scan, 0)))
 	{
@@ -398,7 +400,7 @@ find_inheritance_children(Oid inhparent)
 		list = lappendi(list, inhrelid);
 	}
 	heap_endscan(scan);
-	heap_close(relation);
+	heap_close(relation, AccessShareLock);
 	return list;
 }
 
@@ -424,8 +426,8 @@ VersionGetParents(Oid verrelid)
 
 	fmgr_info(F_OIDEQ, &key[0].sk_func);
 	key[0].sk_nargs = key[0].sk_func.fn_nargs;
-	relation = heap_openr(VersionRelationName);
 	key[0].sk_argument = ObjectIdGetDatum(verrelid);
+	relation = heap_openr(VersionRelationName, AccessShareLock);
 	scan = heap_beginscan(relation, 0, SnapshotNow, 1, key);
 	while (HeapTupleIsValid(versionTuple = heap_getnext(scan, 0)))
 	{
@@ -438,7 +440,7 @@ VersionGetParents(Oid verrelid)
 		heap_rescan(scan, 0, key);
 	}
 	heap_endscan(scan);
-	heap_close(relation);
+	heap_close(relation, AccessShareLock);
 	return list;
 }
 
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 2c4d1c7a7e824fc8535bee0a86f1db8825652a09..276d28b3aa14e9474e887af207190ff0dac9daa8 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: analyze.c,v 1.118 1999/08/21 03:48:55 tgl Exp $
+ *	$Id: analyze.c,v 1.119 1999/09/18 19:07:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,7 +64,7 @@ parse_analyze(List *pl, ParseState *parentParseState)
 
 		parsetree = transformStmt(pstate, lfirst(pl));
 		if (pstate->p_target_relation != NULL)
-			heap_close(pstate->p_target_relation);
+			heap_close(pstate->p_target_relation, AccessShareLock);
 		pstate->p_target_relation = NULL;
 		pstate->p_target_rangetblentry = NULL;
 
@@ -73,7 +73,7 @@ parse_analyze(List *pl, ParseState *parentParseState)
 			result = lappend(result,
 							 transformStmt(pstate, lfirst(extras_before)));
 			if (pstate->p_target_relation != NULL)
-				heap_close(pstate->p_target_relation);
+				heap_close(pstate->p_target_relation, AccessShareLock);
 			pstate->p_target_relation = NULL;
 			pstate->p_target_rangetblentry = NULL;
 			extras_before = lnext(extras_before);
@@ -86,7 +86,7 @@ parse_analyze(List *pl, ParseState *parentParseState)
 			result = lappend(result,
 							 transformStmt(pstate, lfirst(extras_after)));
 			if (pstate->p_target_relation != NULL)
-				heap_close(pstate->p_target_relation);
+				heap_close(pstate->p_target_relation, AccessShareLock);
 			pstate->p_target_relation = NULL;
 			pstate->p_target_rangetblentry = NULL;
 			extras_after = lnext(extras_after);
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 234987fb5f0472ba7ea3e545575b251169dc2e5d..bae53ebbd875e1761b4fff0aa5201dc74ef3001b 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.44 1999/08/21 03:48:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.45 1999/09/18 19:07:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,11 +75,11 @@ setTargetTable(ParseState *pstate, char *relname)
 
 	/* This could only happen for multi-action rules */
 	if (pstate->p_target_relation != NULL)
-		heap_close(pstate->p_target_relation);
+		heap_close(pstate->p_target_relation, AccessShareLock);
 
 	pstate->p_target_rangetblentry = rte;
-	pstate->p_target_relation = heap_open(rte->relid);
-	/* will close relation later */
+	pstate->p_target_relation = heap_open(rte->relid, AccessShareLock);
+	/* will close relation later, see analyze.c */
 }
 
 /*
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 19a287d99e882fb5bb7637cbadb0ab83a09c7295..15e63f7c98fa461995a65224aac5d3f91fa7bfd5 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.54 1999/08/22 20:15:03 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.55 1999/09/18 19:07:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -139,7 +139,7 @@ agg_get_candidates(char *aggname,
 	fmgr_info(F_NAMEEQ, (FmgrInfo *) &aggKey[0].sk_func);
 	aggKey[0].sk_argument = NameGetDatum(aggname);
 
-	pg_aggregate_desc = heap_openr(AggregateRelationName);
+	pg_aggregate_desc = heap_openr(AggregateRelationName, AccessShareLock);
 	pg_aggregate_scan = heap_beginscan(pg_aggregate_desc,
 									   0,
 									   SnapshotSelf,	/* ??? */
@@ -159,7 +159,7 @@ agg_get_candidates(char *aggname,
 	}
 
 	heap_endscan(pg_aggregate_scan);
-	heap_close(pg_aggregate_desc);
+	heap_close(pg_aggregate_desc, AccessShareLock);
 
 	return ncandidates;
 }	/* agg_get_candidates() */
@@ -310,11 +310,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 			if (attisset)
 			{
 				toid = exprType(first_arg);
-				rd = heap_openr(typeidTypeName(toid));
+				rd = heap_openr(typeidTypeName(toid), NoLock);
 				if (RelationIsValid(rd))
 				{
 					relname = RelationGetRelationName(rd)->data;
-					heap_close(rd);
+					heap_close(rd, NoLock);
 				}
 				else
 					elog(ERROR, "Type '%s' is not a relation type",
@@ -646,7 +646,7 @@ func_get_candidates(char *funcname, int nargs)
 	CandidateList current_candidate;
 	int			i;
 
-	heapRelation = heap_openr(ProcedureRelationName);
+	heapRelation = heap_openr(ProcedureRelationName, AccessShareLock);
 	ScanKeyEntryInitialize(&skey,
 						   (bits16) 0x0,
 						   (AttrNumber) 1,
@@ -690,7 +690,7 @@ func_get_candidates(char *funcname, int nargs)
 
 	index_endscan(sd);
 	index_close(idesc);
-	heap_close(heapRelation);
+	heap_close(heapRelation, AccessShareLock);
 
 	return candidates;
 }
@@ -1086,7 +1086,7 @@ find_inheritors(Oid relid, Oid **supervec)
 	visited = DLNewList();
 
 
-	inhrel = heap_openr(InheritsRelationName);
+	inhrel = heap_openr(InheritsRelationName, AccessShareLock);
 	inhtupdesc = RelationGetDescr(inhrel);
 
 	/*
@@ -1140,12 +1140,12 @@ find_inheritors(Oid relid, Oid **supervec)
 
 		if (qentry != (SuperQE *) NULL)
 		{
-
 			/* save the type id, rather than the relation id */
-			if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)
+			rd = heap_open(qentry->sqe_relid, NoLock);
+			if (! RelationIsValid(rd))
 				elog(ERROR, "Relid %u does not exist", qentry->sqe_relid);
 			qentry->sqe_relid = typeTypeId(typenameType(RelationGetRelationName(rd)->data));
-			heap_close(rd);
+			heap_close(rd, NoLock);
 
 			DLAddTail(visited, qe);
 
@@ -1153,7 +1153,7 @@ find_inheritors(Oid relid, Oid **supervec)
 		}
 	} while (qentry != (SuperQE *) NULL);
 
-	heap_close(inhrel);
+	heap_close(inhrel, AccessShareLock);
 
 	if (nvisited > 0)
 	{
@@ -1370,16 +1370,13 @@ ParseComplexProjection(ParseState *pstate,
 					 */
 
 					/* add a tlist to the func node and return the Iter */
-					rd = heap_openr(typeidTypeName(argtype));
+					rd = heap_openr(typeidTypeName(argtype), NoLock);
 					if (RelationIsValid(rd))
 					{
 						relid = RelationGetRelid(rd);
-						heap_close(rd);
-					}
-					if (RelationIsValid(rd))
-					{
 						func->func_tlist = setup_tlist(funcname, argrelid);
 						iter->itertype = attnumTypeId(rd, attnum);
+						heap_close(rd, NoLock);
 						return (Node *) iter;
 					}
 					else
@@ -1427,16 +1424,12 @@ ParseComplexProjection(ParseState *pstate,
 				{
 
 					/* add a tlist to the func node */
-					rd = heap_openr(typeidTypeName(argtype));
-					if (RelationIsValid(rd))
-					{
-						relid = RelationGetRelid(rd);
-						heap_close(rd);
-					}
+					rd = heap_openr(typeidTypeName(argtype), NoLock);
 					if (RelationIsValid(rd))
 					{
 						Expr	   *newexpr;
 
+						relid = RelationGetRelid(rd);
 						funcnode->func_tlist = setup_tlist(funcname, argrelid);
 						funcnode->functype = attnumTypeId(rd, attnum);
 
@@ -1446,8 +1439,11 @@ ParseComplexProjection(ParseState *pstate,
 						newexpr->oper = (Node *) funcnode;
 						newexpr->args = expr->args;
 
+						heap_close(rd, NoLock);
+
 						return (Node *) newexpr;
 					}
+					/* XXX why not an error condition if it's not there? */
 
 				}
 
@@ -1461,18 +1457,19 @@ ParseComplexProjection(ParseState *pstate,
 				 * If the Param is a complex type, this could be a
 				 * projection
 				 */
-				rd = heap_openr(typeidTypeName(param->paramtype));
+				rd = heap_openr(typeidTypeName(param->paramtype), NoLock);
 				if (RelationIsValid(rd))
 				{
 					relid = RelationGetRelid(rd);
-					heap_close(rd);
 					if ((attnum = get_attnum(relid, funcname))
 						!= InvalidAttrNumber)
 					{
 						param->paramtype = attnumTypeId(rd, attnum);
 						param->param_tlist = setup_tlist(funcname, relid);
+						heap_close(rd, NoLock);
 						return (Node *) param;
 					}
+					heap_close(rd, NoLock);
 				}
 				break;
 			}
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 8f82e58517d748728586d18cc61278eac4a98b9e..5a5c8709969b36bce1b016157ad78f5379229ae4 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.31 1999/08/26 04:59:15 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.32 1999/09/18 19:07:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,7 +75,6 @@ binary_oper_get_candidates(char *opname,
 	HeapScanDesc pg_operator_scan;
 	HeapTuple	tup;
 	Form_pg_operator oper;
-	int			nkeys;
 	int			ncandidates = 0;
 	ScanKeyData opKey[3];
 
@@ -91,13 +90,11 @@ binary_oper_get_candidates(char *opname,
 						   F_CHAREQ,
 						   CharGetDatum('b'));
 
-	nkeys = 2;
-
-	pg_operator_desc = heap_openr(OperatorRelationName);
+	pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
 	pg_operator_scan = heap_beginscan(pg_operator_desc,
 									  0,
 									  SnapshotSelf,		/* ??? */
-									  nkeys,
+									  2,
 									  opKey);
 
 	while (HeapTupleIsValid(tup = heap_getnext(pg_operator_scan, 0)))
@@ -114,7 +111,7 @@ binary_oper_get_candidates(char *opname,
 	}
 
 	heap_endscan(pg_operator_scan);
-	heap_close(pg_operator_desc);
+	heap_close(pg_operator_desc, AccessShareLock);
 
 	return ncandidates;
 }	/* binary_oper_get_candidates() */
@@ -522,7 +519,7 @@ unary_oper_get_candidates(char *op,
 	fmgr_info(F_CHAREQ, (FmgrInfo *) &opKey[1].sk_func);
 	opKey[1].sk_argument = CharGetDatum(rightleft);
 
-	pg_operator_desc = heap_openr(OperatorRelationName);
+	pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
 	pg_operator_scan = heap_beginscan(pg_operator_desc,
 									  0,
 									  SnapshotSelf,		/* ??? */
@@ -545,7 +542,7 @@ unary_oper_get_candidates(char *op,
 	}
 
 	heap_endscan(pg_operator_scan);
-	heap_close(pg_operator_desc);
+	heap_close(pg_operator_desc, AccessShareLock);
 
 	return ncandidates;
 }	/* unary_oper_get_candidates() */
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 79b08635f0273ada348dedccc34bfc1d798c0480..af18087aa58db82b41e690aed4f77beff19b8600 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.26 1999/07/19 00:26:20 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.27 1999/09/18 19:07:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -202,14 +202,9 @@ addRangeTableEntry(ParseState *pstate,
 	rte->relname = pstrdup(relname);
 	rte->refname = pstrdup(refname);
 
-	relation = heap_openr(relname);
-	if (relation == NULL)
-		elog(ERROR, "%s: %s",
-			 relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]);
-
+	relation = heap_openr(relname, AccessShareLock);
 	rte->relid = RelationGetRelid(relation);
-
-	heap_close(relation);
+	heap_close(relation, AccessShareLock);
 
 	/*
 	 * Flags - zero or more from inheritance,union,version or recursive
@@ -246,10 +241,7 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
 	if (rte == NULL)
 		rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE);
 
-	rel = heap_open(rte->relid);
-	if (rel == NULL)
-		elog(ERROR, "Unable to expand all -- heap_open failed on %s",
-			 rte->refname);
+	rel = heap_open(rte->relid, AccessShareLock);
 
 	maxattrs = RelationGetNumberOfAttributes(rel);
 
@@ -278,7 +270,7 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
 		te_list = lappend(te_list, te);
 	}
 
-	heap_close(rel);
+	heap_close(rel, AccessShareLock);
 
 	return te_list;
 }
diff --git a/src/backend/rewrite/locks.c b/src/backend/rewrite/locks.c
index c478a7facee76ce525d9f5c335d3d74927405730..ef96b85210c48c36d3d69166d25559babbfcaee8 100644
--- a/src/backend/rewrite/locks.c
+++ b/src/backend/rewrite/locks.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.21 1999/07/16 04:59:39 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.22 1999/09/18 19:07:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -184,7 +184,7 @@ checkLockPerms(List *locks, Query *parsetree, int rt_index)
 	 * Get the usename of the rules event relation owner
 	 */
 	rte = (RangeTblEntry *) nth(rt_index - 1, parsetree->rtable);
-	ev_rel = heap_openr(rte->relname);
+	ev_rel = heap_openr(rte->relname, AccessShareLock);
 	usertup = SearchSysCacheTuple(USESYSID,
 							  ObjectIdGetDatum(ev_rel->rd_rel->relowner),
 								  0, 0, 0);
@@ -193,7 +193,7 @@ checkLockPerms(List *locks, Query *parsetree, int rt_index)
 		elog(ERROR, "cache lookup for userid %d failed",
 			 ev_rel->rd_rel->relowner);
 	}
-	heap_close(ev_rel);
+	heap_close(ev_rel, AccessShareLock);
 	evowner = nameout(&(((Form_pg_shadow) GETSTRUCT(usertup))->usename));
 
 	/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index b118bf8de5dc7bda56100dd7fcf94141c4b46dd0..c9be17151a900c04390f4b22751bc48964228cd6 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.35 1999/07/19 07:07:21 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.36 1999/09/18 19:07:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -78,9 +78,7 @@ InsertRule(char *rulname,
 	extern void eval_as_new_xact();
 	char	   *template;
 
-	eventrel = heap_openr(evobj);
-	if (eventrel == NULL)
-		elog(ERROR, "rules cannot be defined on relations not in schema");
+	eventrel = heap_openr(evobj, AccessShareLock);
 	eventrel_oid = RelationGetRelid(eventrel);
 
 	/*
@@ -90,7 +88,7 @@ InsertRule(char *rulname,
 		evslot_index = -1;
 	else
 		evslot_index = attnameAttNum(eventrel, (char *) evslot);
-	heap_close(eventrel);
+	heap_close(eventrel, AccessShareLock);
 
 	if (evinstead)
 		is_instead = "t";
@@ -258,9 +256,7 @@ DefineQueryRewrite(RuleStmt *stmt)
 		 * ... the targetlist of the SELECT action must exactly match the
 		 * event relation, ...
 		 */
-		event_relation = heap_openr(event_obj->relname);
-		if (event_relation == NULL)
-			elog(ERROR, "virtual relations not supported yet");
+		event_relation = heap_openr(event_obj->relname, AccessShareLock);
 
 		if (event_relation->rd_att->natts != length(query->targetList))
 			elog(ERROR, "select rules target list must match event relations structure");
@@ -297,7 +293,7 @@ DefineQueryRewrite(RuleStmt *stmt)
 			}
 		}
 
-		heap_close(event_relation);
+		heap_close(event_relation, AccessShareLock);
 
 		/*
 		 * LIMIT in view is not supported
@@ -332,9 +328,7 @@ DefineQueryRewrite(RuleStmt *stmt)
 	 * This rule is allowed - install it.
 	 */
 
-	event_relation = heap_openr(event_obj->relname);
-	if (event_relation == NULL)
-		elog(ERROR, "virtual relations not supported yet");
+	event_relation = heap_openr(event_obj->relname, AccessShareLock);
 	ev_relid = RelationGetRelid(event_relation);
 
 	if (eslot_string == NULL)
@@ -347,7 +341,7 @@ DefineQueryRewrite(RuleStmt *stmt)
 		event_attno = attnameAttNum(event_relation, eslot_string);
 		event_attype = attnumTypeId(event_relation, event_attno);
 	}
-	heap_close(event_relation);
+	heap_close(event_relation, AccessShareLock);
 
 	/* fix bug about instead nothing */
 	ValidateRule(event_type, event_obj->relname,
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 0fa7fd72d43681bfef5a290d7f857c40f8577ab8..b13cb5e3ed1cd5db2f142db51cf15e8aa1681bb0 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.55 1999/08/25 23:21:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.56 1999/09/18 19:07:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2059,10 +2059,10 @@ fireRIRrules(Query *parsetree)
 			continue;
 		}
 
-		rel = heap_openr(rte->relname);
+		rel = heap_openr(rte->relname, AccessShareLock);
 		if (rel->rd_rules == NULL)
 		{
-			heap_close(rel);
+			heap_close(rel, AccessShareLock);
 			continue;
 		}
 
@@ -2112,7 +2112,7 @@ fireRIRrules(Query *parsetree)
 							  &modified);
 		}
 
-		heap_close(rel);
+		heap_close(rel, AccessShareLock);
 	}
 
 	fireRIRonSubselect((Node *) parsetree);
@@ -2452,9 +2452,9 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
 	 * the statement is an update, insert or delete - fire rules on it.
 	 */
 	rt_entry = rt_fetch(result_relation, parsetree->rtable);
-	rt_entry_relation = heap_openr(rt_entry->relname);
+	rt_entry_relation = heap_openr(rt_entry->relname, AccessShareLock);
 	rt_entry_locks = rt_entry_relation->rd_rules;
-	heap_close(rt_entry_relation);
+	heap_close(rt_entry_relation, AccessShareLock);
 
 	if (rt_entry_locks != NULL)
 	{
@@ -2469,7 +2469,6 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
 	}
 
 	return product_queries;
-
 }
 
 
@@ -2585,7 +2584,7 @@ RewritePreprocessQuery(Query *parsetree)
 
 		rte = (RangeTblEntry *) nth(parsetree->resultRelation - 1,
 									parsetree->rtable);
-		rd = heap_openr(rte->relname);
+		rd = heap_openr(rte->relname, AccessShareLock);
 
 		foreach(tl, parsetree->targetList)
 		{
@@ -2597,7 +2596,7 @@ RewritePreprocessQuery(Query *parsetree)
 				tle->resdom->resno = 0;
 		}
 
-		heap_close(rd);
+		heap_close(rd, AccessShareLock);
 	}
 }
 
diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c
index 14ceeead8486e5068ad685fda9b74f171da0a6ad..50e6c62c027beac0af47d36a97574e7bcfeb955f 100644
--- a/src/backend/rewrite/rewriteRemove.c
+++ b/src/backend/rewrite/rewriteRemove.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.28 1999/07/17 20:17:39 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.29 1999/09/18 19:07:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -76,7 +76,7 @@ RemoveRewriteRule(char *ruleName)
 	/*
 	 * Open the pg_rewrite relation.
 	 */
-	RewriteRelation = heap_openr(RewriteRelationName);
+	RewriteRelation = heap_openr(RewriteRelationName, RowExclusiveLock);
 
 	/*
 	 * Scan the RuleRelation ('pg_rewrite') until we find a tuple
@@ -90,7 +90,7 @@ RemoveRewriteRule(char *ruleName)
 	 */
 	if (!HeapTupleIsValid(tuple))
 	{
-		heap_close(RewriteRelation);
+		heap_close(RewriteRelation, RowExclusiveLock);
 		elog(ERROR, "Rule '%s' not found\n", ruleName);
 	}
 
@@ -125,7 +125,7 @@ RemoveRewriteRule(char *ruleName)
 	heap_delete(RewriteRelation, &tuple->t_self, NULL);
 
 	pfree(tuple);
-	heap_close(RewriteRelation);
+	heap_close(RewriteRelation, RowExclusiveLock);
 }
 
 /*
@@ -144,7 +144,7 @@ RelationRemoveRules(Oid relid)
 	/*
 	 * Open the pg_rewrite relation.
 	 */
-	RewriteRelation = heap_openr(RewriteRelationName);
+	RewriteRelation = heap_openr(RewriteRelationName, RowExclusiveLock);
 
 	/*
 	 * Scan the RuleRelation ('pg_rewrite') for all the tuples that has
@@ -162,5 +162,5 @@ RelationRemoveRules(Oid relid)
 		heap_delete(RewriteRelation, &tuple->t_self, NULL);
 
 	heap_endscan(scanDesc);
-	heap_close(RewriteRelation);
+	heap_close(RewriteRelation, RowExclusiveLock);
 }
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index c8d9d023efed6c0d014594b054d4f3529ed9f89c..c089be56d31c55dfa8c38182abc86373c8d2921f 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.36 1999/07/16 04:59:41 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.37 1999/09/18 19:07:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,7 +40,7 @@ RuleIdGetActionInfo(Oid ruleoid, bool *instead_flag, Query **parseTrees)
 	char	   *rule_evqual_string = NULL;
 	Node	   *rule_evqual = NULL;
 
-	ruleRelation = heap_openr(RewriteRelationName);
+	ruleRelation = heap_openr(RewriteRelationName, AccessShareLock);
 	ruleTupdesc = RelationGetDescr(ruleRelation);
 	ruletuple = SearchSysCacheTuple(RULOID,
 									ObjectIdGetDatum(ruleoid),
@@ -68,7 +68,7 @@ RuleIdGetActionInfo(Oid ruleoid, bool *instead_flag, Query **parseTrees)
 	ruleparse = (Query *) stringToNode(ruleaction);
 	rule_evqual = (Node *) stringToNode(rule_evqual_string);
 
-	heap_close(ruleRelation);
+	heap_close(ruleRelation, AccessShareLock);
 
 	*parseTrees = ruleparse;
 	return rule_evqual;
@@ -79,23 +79,11 @@ RuleIdGetActionInfo(Oid ruleoid, bool *instead_flag, Query **parseTrees)
 int
 IsDefinedRewriteRule(char *ruleName)
 {
-	Relation	RewriteRelation = NULL;
 	HeapTuple	tuple;
 
-
-	/*
-	 * Open the pg_rewrite relation.
-	 */
-	RewriteRelation = heap_openr(RewriteRelationName);
-
 	tuple = SearchSysCacheTuple(REWRITENAME,
 								PointerGetDatum(ruleName),
 								0, 0, 0);
-
-	/*
-	 * return whether or not the rewrite rule existed
-	 */
-	heap_close(RewriteRelation);
 	return HeapTupleIsValid(tuple);
 }
 
@@ -111,12 +99,12 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
 	 * pg_relation), find the appropriate tuple, and add the specified
 	 * lock to it.
 	 */
+	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheTupleCopy(RELOID,
 									ObjectIdGetDatum(relationId),
 									0, 0, 0);
 	Assert(HeapTupleIsValid(tuple));
 
-	relationRelation = heap_openr(RelationRelationName);
 	((Form_pg_class) GETSTRUCT(tuple))->relhasrules = relhasrules;
 	heap_replace(relationRelation, &tuple->t_self, tuple, NULL);
 
@@ -126,7 +114,7 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
 	CatalogCloseIndices(Num_pg_class_indices, idescs);
 
 	pfree(tuple);
-	heap_close(relationRelation);
+	heap_close(relationRelation, RowExclusiveLock);
 }
 
 void
@@ -162,7 +150,7 @@ prs2_addToRelation(Oid relid,
 	thisRule->actions = actions;
 	thisRule->isInstead = isInstead;
 
-	relation = heap_open(relid);
+	relation = heap_open(relid, AccessShareLock);
 
 	/*
 	 * modify or create a RuleLock cached by Relation
@@ -200,9 +188,7 @@ prs2_addToRelation(Oid relid,
 		rulelock->numLocks++;
 	}
 
-	heap_close(relation);
-
-	return;
+	heap_close(relation, AccessShareLock);
 }
 
 void
@@ -214,7 +200,7 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId)
 	int			i;
 	MemoryContext oldcxt;
 
-	relation = heap_open(relid);
+	relation = heap_open(relid, AccessShareLock);
 	rulelock = relation->rd_rules;
 	Assert(rulelock != NULL);
 
@@ -245,5 +231,5 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId)
 		rulelock->numLocks--;
 	}
 
-	heap_close(relation);
+	heap_close(relation, AccessShareLock);
 }
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index de0d803efe23215870a2d0d24a5df977e51506b2..b435dd53cac10ed46b5c9b3b20620769ae41e296 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.61 1999/07/17 20:17:40 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.62 1999/09/18 19:07:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -109,7 +109,7 @@ RelationGetBufferWithBuffer(Relation relation,
 	{
 		if (!BufferIsLocal(buffer))
 		{
-			LockRelId  *lrelId = &(((LockInfo) (relation->lockInfo))->lockRelId);
+			LockRelId  *lrelId = & relation->rd_lockInfo.lockRelId;
 
 			bufHdr = &BufferDescriptors[buffer - 1];
 			SpinAcquire(BufMgrLock);
@@ -813,6 +813,7 @@ FlushBuffer(Buffer buffer, bool release)
 	status = smgrflush(DEFAULT_SMGR, bufrel, bufHdr->tag.blockNum,
 					   (char *) MAKE_PTR(bufHdr->data));
 
+	/* drop relcache refcount incremented by RelationIdCacheGetRelation */
 	RelationDecrementReferenceCount(bufrel);
 
 	if (status == SM_FAIL)
@@ -993,6 +994,7 @@ BufferSync()
 						elog(ERROR, "BufferSync: write error %u for %s",
 							 bufHdr->tag.blockNum, bufHdr->sb_relname);
 					}
+					/* drop refcount from RelationIdCacheGetRelation */
 					if (reln != (Relation) NULL)
 						RelationDecrementReferenceCount(reln);
 					continue;
@@ -1047,6 +1049,7 @@ BufferSync()
 				 */
 				if (!(bufHdr->flags & BM_JUST_DIRTIED))
 					bufHdr->flags &= ~BM_DIRTY;
+				/* drop refcount from RelationIdCacheGetRelation */
 				if (reln != (Relation) NULL)
 					RelationDecrementReferenceCount(reln);
 			}
@@ -1282,14 +1285,16 @@ BufferGetRelation(Buffer buffer)
 	/* XXX should be a critical section */
 	relid = BufferDescriptors[buffer - 1].tag.relId.relId;
 	relation = RelationIdGetRelation(relid);
+	Assert(relation);
 
+	/* drop relcache refcount incremented by RelationIdGetRelation */
 	RelationDecrementReferenceCount(relation);
 
 	if (RelationHasReferenceCountZero(relation))
 	{
 
 		/*
-		 * elog(NOTICE, "BufferGetRelation: 0->1");
+		 * XXX why??
 		 */
 
 		RelationIncrementReferenceCount(relation);
@@ -1342,7 +1347,6 @@ BufferReplace(BufferDesc *bufHdr, bool bufferLockHeld)
 	}
 	else
 	{
-
 		/* blind write always flushes */
 		status = smgrblindwrt(DEFAULT_SMGR, bufHdr->sb_dbname,
 							  bufHdr->sb_relname, bufdb, bufrel,
@@ -1350,6 +1354,7 @@ BufferReplace(BufferDesc *bufHdr, bool bufferLockHeld)
 							  (char *) MAKE_PTR(bufHdr->data));
 	}
 
+	/* drop relcache refcount incremented by RelationIdCacheGetRelation */
 	if (reln != (Relation) NULL)
 		RelationDecrementReferenceCount(reln);
 
diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c
index a6a2d456b26c6ef920bed9e2da9f114427e6ecc3..e003595beda6d0395bccdfd9ac0665468b205e0c 100644
--- a/src/backend/storage/buffer/localbuf.c
+++ b/src/backend/storage/buffer/localbuf.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.26 1999/07/17 20:17:41 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.27 1999/09/18 19:07:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -109,6 +109,8 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
 		smgrwrite(DEFAULT_SMGR, bufrel, bufHdr->tag.blockNum,
 				  (char *) MAKE_PTR(bufHdr->data));
 		LocalBufferFlushCount++;
+
+		/* drop relcache refcount incremented by RelationIdCacheGetRelation */
 		RelationDecrementReferenceCount(bufrel);
 	}
 
@@ -187,6 +189,8 @@ FlushLocalBuffer(Buffer buffer, bool release)
 	smgrflush(DEFAULT_SMGR, bufrel, bufHdr->tag.blockNum,
 			  (char *) MAKE_PTR(bufHdr->data));
 	LocalBufferFlushCount++;
+
+	/* drop relcache refcount incremented by RelationIdCacheGetRelation */
 	RelationDecrementReferenceCount(bufrel);
 
 	Assert(LocalRefCount[bufid] > 0);
@@ -260,6 +264,8 @@ LocalBufferSync(void)
 			smgrwrite(DEFAULT_SMGR, bufrel, buf->tag.blockNum,
 					  (char *) MAKE_PTR(buf->data));
 			LocalBufferFlushCount++;
+
+			/* drop relcache refcount from RelationIdCacheGetRelation */
 			RelationDecrementReferenceCount(bufrel);
 
 			buf->tag.relId.relId = InvalidOid;
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index 6b8765bb81ca605567ba4d815a2695d34a4624d4..f59e99d7fbe90fd5b0156749b01ef84c7c83a053 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.58 1999/07/19 07:07:23 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.59 1999/09/18 19:07:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -139,13 +139,16 @@ inv_create(int flags)
 
 	/* make the relation visible in this transaction */
 	CommandCounterIncrement();
-	r = heap_openr(objname);
 
-	if (!RelationIsValid(r))
-	{
-		elog(ERROR, "cannot create large object on %s under inversion",
-			 smgrout(DEFAULT_SMGR));
-	}
+	/*--------------------
+	 * We hold AccessShareLock on any large object we have open
+	 * by inv_create or inv_open; it is released by inv_close.
+	 * Note this will not conflict with ExclusiveLock or ShareLock
+	 * that we acquire when actually reading/writing; it just prevents
+	 * deletion of the large object while we have it open.
+	 *--------------------
+	 */
+	r = heap_openr(objname, AccessShareLock);
 
 	/*
 	 * Now create a btree index on the relation's olastbyte attribute to
@@ -205,10 +208,7 @@ inv_open(Oid lobjId, int flags)
 	char	   *indname;
 	Relation	indrel;
 
-	r = heap_open(lobjId);
-
-	if (!RelationIsValid(r))
-		return (LargeObjectDesc *) NULL;
+	r = heap_open(lobjId, AccessShareLock);
 
 	indname = pstrdup((r->rd_rel->relname).data);
 
@@ -262,8 +262,8 @@ inv_close(LargeObjectDesc *obj_desc)
 		obj_desc->iscan = NULL;
 	}
 
-	heap_close(obj_desc->heap_r);
 	index_close(obj_desc->index_r);
+	heap_close(obj_desc->heap_r, AccessShareLock);
 
 	pfree(obj_desc);
 }
@@ -279,7 +279,7 @@ inv_destroy(Oid lobjId)
 	Relation	r;
 
 	r = (Relation) RelationIdGetRelation(lobjId);
-	if (!RelationIsValid(r) || r->rd_rel->relkind == RELKIND_INDEX)
+	if (!RelationIsValid(r) || r->rd_rel->relkind != RELKIND_LOBJECT)
 		return -1;
 
 	heap_destroy_with_catalog(r->rd_rel->relname.data);
@@ -497,7 +497,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
 
 	if (!(obj_desc->flags & IFS_WRLOCK))
 	{
-		LockRelation(obj_desc->heap_r, ShareLock);
+		LockRelation(obj_desc->heap_r, ExclusiveLock);
 		obj_desc->flags |= (IFS_WRLOCK | IFS_RDLOCK);
 	}
 
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 839533952b5cf4306e9ad5dad366302c4ff38700..2aaaf69e83e9d67a4e9c98c9cea5e75d4fc91030 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.34 1999/09/04 18:42:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.35 1999/09/18 19:07:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,11 +20,12 @@
 
 
 #include "postgres.h"
+
 #include "access/transam.h"
 #include "catalog/catalog.h"
+#include "miscadmin.h"
 #include "utils/inval.h"
 
-extern Oid	MyDatabaseId;
 
 static LOCKMASK LockConflicts[] = {
 	(int) NULL,
@@ -106,37 +107,25 @@ InitLockTable()
 /*
  * RelationInitLockInfo
  *		Initializes the lock information in a relation descriptor.
+ *
+ *		relcache.c must call this during creation of any reldesc.
  */
 void
 RelationInitLockInfo(Relation relation)
 {
-	LockInfo	info;
 	char	   *relname;
-	MemoryContext oldcxt;
-	extern Oid	MyDatabaseId;	/* XXX use include */
-	extern GlobalMemory CacheCxt;
 
 	Assert(RelationIsValid(relation));
 	Assert(OidIsValid(RelationGetRelid(relation)));
 
-	info = (LockInfo) relation->lockInfo;
-
-	if (LockInfoIsValid(info))
-		return;
-
 	relname = (char *) RelationGetRelationName(relation);
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
-	info = (LockInfo) palloc(sizeof(LockInfoData));
-	MemoryContextSwitchTo(oldcxt);
+	relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
 
-	info->lockRelId.relId = RelationGetRelid(relation);
 	if (IsSharedSystemRelationName(relname))
-		info->lockRelId.dbId = InvalidOid;
+		relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
 	else
-		info->lockRelId.dbId = MyDatabaseId;
-
-	relation->lockInfo = (Pointer) info;
+		relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
 }
 
 /*
@@ -145,20 +134,14 @@ RelationInitLockInfo(Relation relation)
 void
 LockRelation(Relation relation, LOCKMODE lockmode)
 {
-	LockInfo	lockinfo;
 	LOCKTAG		tag;
 
 	if (LockingDisabled())
 		return;
 
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
-
-	lockinfo = (LockInfo) relation->lockInfo;
-
 	MemSet(&tag, 0, sizeof(tag));
-	tag.relId = lockinfo->lockRelId.relId;
-	tag.dbId = lockinfo->lockRelId.dbId;
+	tag.relId = relation->rd_lockInfo.lockRelId.relId;
+	tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
 	tag.objId.blkno = InvalidBlockNumber;
 
 	LockAcquire(LockTableId, &tag, lockmode);
@@ -180,28 +163,17 @@ LockRelation(Relation relation, LOCKMODE lockmode)
 void
 UnlockRelation(Relation relation, LOCKMODE lockmode)
 {
-	LockInfo	lockinfo;
 	LOCKTAG		tag;
 
 	if (LockingDisabled())
 		return;
 
-	lockinfo = (LockInfo) relation->lockInfo;
-
-	if (!LockInfoIsValid(lockinfo))
-	{
-		elog(ERROR,
-			 "Releasing a lock on %s with invalid lock information",
-			 RelationGetRelationName(relation));
-	}
-
 	MemSet(&tag, 0, sizeof(tag));
-	tag.relId = lockinfo->lockRelId.relId;
-	tag.dbId = lockinfo->lockRelId.dbId;
+	tag.relId = relation->rd_lockInfo.lockRelId.relId;
+	tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
 	tag.objId.blkno = InvalidBlockNumber;
 
 	LockRelease(LockTableId, &tag, lockmode);
-	return;
 }
 
 /*
@@ -210,24 +182,17 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
 void
 LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
 {
-	LockInfo	lockinfo;
 	LOCKTAG		tag;
 
 	if (LockingDisabled())
 		return;
 
-	if (!LockInfoIsValid(relation->lockInfo))
-		RelationInitLockInfo(relation);
-
-	lockinfo = (LockInfo) relation->lockInfo;
-
 	MemSet(&tag, 0, sizeof(tag));
-	tag.relId = lockinfo->lockRelId.relId;
-	tag.dbId = lockinfo->lockRelId.dbId;
+	tag.relId = relation->rd_lockInfo.lockRelId.relId;
+	tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
 	tag.objId.blkno = blkno;
 
 	LockAcquire(LockTableId, &tag, lockmode);
-	return;
 }
 
 /*
@@ -236,28 +201,17 @@ LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
 void
 UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
 {
-	LockInfo	lockinfo;
 	LOCKTAG		tag;
 
 	if (LockingDisabled())
 		return;
 
-	lockinfo = (LockInfo) relation->lockInfo;
-
-	if (!LockInfoIsValid(lockinfo))
-	{
-		elog(ERROR,
-			 "Releasing a lock on %s with invalid lock information",
-			 RelationGetRelationName(relation));
-	}
-
 	MemSet(&tag, 0, sizeof(tag));
-	tag.relId = lockinfo->lockRelId.relId;
-	tag.dbId = lockinfo->lockRelId.dbId;
+	tag.relId = relation->rd_lockInfo.lockRelId.relId;
+	tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
 	tag.objId.blkno = blkno;
 
 	LockRelease(LockTableId, &tag, lockmode);
-	return;
 }
 
 void
@@ -274,7 +228,6 @@ XactLockTableInsert(TransactionId xid)
 	tag.objId.xid = xid;
 
 	LockAcquire(LockTableId, &tag, ExclusiveLock);
-	return;
 }
 
 void
@@ -291,7 +244,6 @@ XactLockTableDelete(TransactionId xid)
 	tag.objId.xid = xid;
 
 	LockRelease(LockTableId, &tag, ExclusiveLock);
-	return;
 }
 
 void
@@ -316,6 +268,4 @@ XactLockTableWait(TransactionId xid)
 	 */
 	if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
 		TransactionIdAbort(xid);
-
-	return;
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 427cc749c84079879b50221c886063816084a9b5..3f5322c9f08d16b67b1d4e51b020bd7393ce9ad7 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.61 1999/07/17 20:17:46 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.62 1999/09/18 19:07:38 tgl Exp $
  *
  * NOTES
  *	  Outside modules can create a lock table and acquire/release
@@ -596,7 +596,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode)
 	if (!result)
 	{
 		elog(NOTICE, "LockAcquire: xid table corrupted");
-		return STATUS_ERROR;
+		return FALSE;
 	}
 
 	/*
@@ -1117,7 +1117,7 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode)
 			TPRINTF(TRACE_USERLOCKS, "LockRelease: no lock with this tag");
 		else
 #endif
-			elog(NOTICE, "LockReplace: xid table corrupted");
+			elog(NOTICE, "LockRelease: xid table corrupted");
 		return FALSE;
 	}
 	XID_PRINT("LockRelease: found", result);
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 8c1ac556149a590bdaf25a54c277505ec20babb3..29b4fb527c66eed7a1ba59d3af290eafc090dc02 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.64 1999/07/16 04:59:55 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.65 1999/09/18 19:07:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -165,38 +165,39 @@ ProcessUtility(Node *parsetree,
 		case T_DestroyStmt:
 			{
 				DestroyStmt *stmt = (DestroyStmt *) parsetree;
-				List	   *arg;
 				List	   *args = stmt->relNames;
-				Relation	rel;
+				List	   *arg;
 
 				PS_SET_STATUS(commandTag = "DROP");
 				CHECK_IF_ABORTED();
 
+				/* check as much as we can before we start dropping ... */
 				foreach(arg, args)
 				{
+					Relation	rel;
+
 					relname = strVal(lfirst(arg));
 					if (!allowSystemTableMods && IsSystemRelationName(relname))
 						elog(ERROR, "class \"%s\" is a system catalog",
 							 relname);
-					rel = heap_openr(relname);
-					if (RelationIsValid(rel))
-					{
-						if (stmt->sequence &&
-							rel->rd_rel->relkind != RELKIND_SEQUENCE)
-							elog(ERROR, "Use DROP TABLE to drop table '%s'",
-								 relname);
-						if (!(stmt->sequence) &&
-							rel->rd_rel->relkind == RELKIND_SEQUENCE)
-							elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
-								 relname);
-						heap_close(rel);
-					}
+					rel = heap_openr(relname, AccessExclusiveLock);
+					if (stmt->sequence &&
+						rel->rd_rel->relkind != RELKIND_SEQUENCE)
+						elog(ERROR, "Use DROP TABLE to drop table '%s'",
+							 relname);
+					if (!(stmt->sequence) &&
+						rel->rd_rel->relkind == RELKIND_SEQUENCE)
+						elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
+							 relname);
+					/* close rel, but keep lock until end of xact */
+					heap_close(rel, NoLock);
 #ifndef NO_SECURITY
 					if (!pg_ownercheck(userName, relname, RELNAME))
 						elog(ERROR, "you do not own class \"%s\"",
 							 relname);
 #endif
 				}
+				/* OK, terminate 'em all */
 				foreach(arg, args)
 				{
 					relname = strVal(lfirst(arg));
diff --git a/src/backend/utils/adt/not_in.c b/src/backend/utils/adt/not_in.c
index 2ef45f63e425059d369c1af2f5896c12fe7a030f..1a851cf7e5f7c4e52cf45d38722b2eb2d2313393 100644
--- a/src/backend/utils/adt/not_in.c
+++ b/src/backend/utils/adt/not_in.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.20 1999/07/17 20:17:58 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.21 1999/09/18 19:07:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,12 +58,7 @@ int4notin(int32 not_in_arg, char *relation_and_attr)
 
 	/* Open the relation and get a relation descriptor */
 
-	relation_to_scan = heap_openr(relation);
-	if (!RelationIsValid(relation_to_scan))
-	{
-		elog(ERROR, "int4notin: unknown relation %s",
-			 relation);
-	}
+	relation_to_scan = heap_openr(relation, AccessShareLock);
 
 	/* Find the column to search */
 
@@ -95,7 +90,9 @@ int4notin(int32 not_in_arg, char *relation_and_attr)
 	}
 
 	/* close the relation */
-	heap_close(relation_to_scan);
+	heap_endscan(scan_descriptor);
+	heap_close(relation_to_scan, AccessShareLock);
+
 	return retval;
 }
 
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 754eea3a96e933522b9ca007a38b243660cc2991..b3179e864c122526b1e6806f6a3f85ac33a7421f 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.42 1999/07/17 20:17:59 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.43 1999/09/18 19:07:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -78,7 +78,7 @@ regprocin(char *pro_name_or_oid)
 								   (RegProcedure) F_NAMEEQ,
 								   PointerGetDatum(pro_name_or_oid));
 
-			hdesc = heap_openr(ProcedureRelationName);
+			hdesc = heap_openr(ProcedureRelationName, AccessShareLock);
 			idesc = index_openr(ProcedureNameIndex);
 
 			sd = index_beginscan(idesc, false, 1, skey);
@@ -102,6 +102,7 @@ regprocin(char *pro_name_or_oid)
 			index_endscan(sd);
 			pfree(sd);
 			index_close(idesc);
+			heap_close(hdesc, AccessShareLock);
 
 			if (matches > 1)
 				elog(ERROR, "There is more than one procedure named %s.\n\tSupply the pg_proc oid inside single quotes.", pro_name_or_oid);
@@ -116,13 +117,7 @@ regprocin(char *pro_name_or_oid)
 		ScanKeyData key;
 		bool		isnull;
 
-		proc = heap_openr(ProcedureRelationName);
-		if (!RelationIsValid(proc))
-		{
-			elog(ERROR, "regprocin: could not open %s",
-				 ProcedureRelationName);
-			return 0;
-		}
+		proc = heap_openr(ProcedureRelationName, AccessShareLock);
 		ScanKeyEntryInitialize(&key,
 							   (bits16) 0,
 							   (AttrNumber) 1,
@@ -132,8 +127,8 @@ regprocin(char *pro_name_or_oid)
 		procscan = heap_beginscan(proc, 0, SnapshotNow, 1, &key);
 		if (!HeapScanIsValid(procscan))
 		{
-			heap_close(proc);
-			elog(ERROR, "regprocin: could not being scan of %s",
+			heap_close(proc, AccessShareLock);
+			elog(ERROR, "regprocin: could not begin scan of %s",
 				 ProcedureRelationName);
 			return 0;
 		}
@@ -151,7 +146,7 @@ regprocin(char *pro_name_or_oid)
 			result = (RegProcedure) 0;
 
 		heap_endscan(procscan);
-		heap_close(proc);
+		heap_close(proc, AccessShareLock);
 	}
 
 	return (int32) result;
@@ -193,12 +188,7 @@ regprocout(RegProcedure proid)
 		HeapScanDesc procscan;
 		ScanKeyData key;
 
-		proc = heap_openr(ProcedureRelationName);
-		if (!RelationIsValid(proc))
-		{
-			elog(ERROR, "regprocout: could not open %s", ProcedureRelationName);
-			return 0;
-		}
+		proc = heap_openr(ProcedureRelationName, AccessShareLock);
 		ScanKeyEntryInitialize(&key,
 							   (bits16) 0,
 							   (AttrNumber) ObjectIdAttributeNumber,
@@ -208,8 +198,8 @@ regprocout(RegProcedure proid)
 		procscan = heap_beginscan(proc, 0, SnapshotNow, 1, &key);
 		if (!HeapScanIsValid(procscan))
 		{
-			heap_close(proc);
-			elog(ERROR, "regprocout: could not being scan of %s",
+			heap_close(proc, AccessShareLock);
+			elog(ERROR, "regprocout: could not begin scan of %s",
 				 ProcedureRelationName);
 			return 0;
 		}
@@ -232,8 +222,7 @@ regprocout(RegProcedure proid)
 			result[1] = '\0';
 		}
 		heap_endscan(procscan);
-		heap_close(proc);
-		return result;
+		heap_close(proc, AccessShareLock);
 	}
 
 	return result;
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 1b2d58c075ed487de5fa54f1560f196adbb6baac..e14e5375553b3094f7ab4b3987d57ebf2db6bb0c 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.40 1999/09/09 02:35:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.41 1999/09/18 19:07:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -598,7 +598,7 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid typid, int32 typmod,
 	HeapTuple	typeTuple;
 	FmgrInfo	inputproc;
 
-	rel = heap_openr(StatisticRelationName);
+	rel = heap_openr(StatisticRelationName, AccessShareLock);
 
 	key[0].sk_argument = ObjectIdGetDatum(relid);
 	key[1].sk_argument = Int16GetDatum((int16) attnum);
@@ -609,7 +609,7 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid typid, int32 typmod,
 	{
 		/* no such stats entry */
 		heap_endscan(scan);
-		heap_close(rel);
+		heap_close(rel, AccessShareLock);
 		return false;
 	}
 
@@ -694,7 +694,7 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid typid, int32 typmod,
 	}
 
 	heap_endscan(scan);
-	heap_close(rel);
+	heap_close(rel, AccessShareLock);
 	return true;
 }
 
diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c
index 05bc16b92aff49c566fb863de9886cf8befc911d..46dbca9d6984e038b18e58e97bf4f229c174d594 100644
--- a/src/backend/utils/adt/sets.c
+++ b/src/backend/utils/adt/sets.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.25 1999/07/17 20:18:00 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.26 1999/09/18 19:07:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -100,8 +100,7 @@ SetDefine(char *querystr, char *typename)
 			replNull[i] = ' ';
 
 		/* change the pg_proc tuple */
-		procrel = heap_openr(ProcedureRelationName);
-		LockRelation(procrel, AccessExclusiveLock);
+		procrel = heap_openr(ProcedureRelationName, RowExclusiveLock);
 
 		tup = SearchSysCacheTuple(PROOID,
 								  ObjectIdGetDatum(setoid),
@@ -131,8 +130,7 @@ SetDefine(char *querystr, char *typename)
 			CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup);
 			CatalogCloseIndices(Num_pg_proc_indices, idescs);
 		}
-		UnlockRelation(procrel, AccessExclusiveLock);
-		heap_close(procrel);
+		heap_close(procrel, RowExclusiveLock);
 	}
 	return setoid;
 }
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index f6ef0fecac266eb116cb82eff2759c0a49045e6d..22d933bb37a3f4886e4875714ec453c3d7d38223 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.48 1999/07/17 20:18:01 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.49 1999/09/18 19:07:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -130,7 +130,8 @@ CatalogCacheInitializeCache(struct catcache * cache,
 	/* ----------------
 	 *	If no relation was passed we must open it to get access to
 	 *	its fields.  If one of the other caches has already opened
-	 *	it we use heap_open() instead of heap_openr()
+	 *	it we use heap_open() instead of heap_openr().
+	 *	XXX is that really worth the trouble of checking?
 	 * ----------------
 	 */
 	if (!RelationIsValid(relation))
@@ -155,9 +156,9 @@ CatalogCacheInitializeCache(struct catcache * cache,
 		 * ----------------
 		 */
 		if (cp)
-			relation = heap_open(cp->relationId);
+			relation = heap_open(cp->relationId, NoLock);
 		else
-			relation = heap_openr(cache->cc_relname);
+			relation = heap_openr(cache->cc_relname, NoLock);
 
 		didopen = 1;
 	}
@@ -217,7 +218,7 @@ CatalogCacheInitializeCache(struct catcache * cache,
 	 * ----------------
 	 */
 	if (didopen)
-		heap_close(relation);
+		heap_close(relation, NoLock);
 
 	/* ----------------
 	 *	initialize index information for the cache.  this
@@ -891,10 +892,10 @@ SearchSysCache(struct catcache * cache,
 		DLMoveToFront(elt);
 
 #ifdef CACHEDEBUG
-		relation = heap_open(cache->relationId);
+		relation = heap_open(cache->relationId, NoLock);
 		CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
 					RelationGetRelationName(relation), hash);
-		heap_close(relation);
+		heap_close(relation, NoLock);
 #endif	 /* CACHEDEBUG */
 
 		return ct->ct_tup;
@@ -925,7 +926,7 @@ SearchSysCache(struct catcache * cache,
 	 *	open the relation associated with the cache
 	 * ----------------
 	 */
-	relation = heap_open(cache->relationId);
+	relation = heap_open(cache->relationId, AccessShareLock);
 	CACHE2_elog(DEBUG, "SearchSysCache(%s)",
 				RelationGetRelationName(relation));
 
@@ -1082,7 +1083,7 @@ SearchSysCache(struct catcache * cache,
 	 *	and return the tuple we found (or NULL)
 	 * ----------------
 	 */
-	heap_close(relation);
+	heap_close(relation, AccessShareLock);
 
 	MemoryContextSwitchTo(oldcxt);
 	return ntp;
@@ -1146,8 +1147,6 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
 		(*function) (ccp->id,
 				 CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),
 					 &tuple->t_self);
-
-		heap_close(relation);
 	}
 
 	/* ----------------
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index db685e751ebf68ec2dc4d0b51b29602109a22cea..afba41db108094e12a771688014257c7586f7ba6 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.72 1999/09/06 19:33:16 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.73 1999/09/18 19:07:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -337,7 +337,7 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
 	 *	open pg_class and fetch a tuple
 	 * ----------------
 	 */
-	pg_class_desc = heap_openr(RelationRelationName);
+	pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
 	pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key);
 	pg_class_tuple = heap_getnext(pg_class_scan, 0);
 
@@ -361,7 +361,7 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
 
 	/* all done */
 	heap_endscan(pg_class_scan);
-	heap_close(pg_class_desc);
+	heap_close(pg_class_desc, AccessShareLock);
 
 	return return_tuple;
 }
@@ -372,9 +372,7 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
 	Relation	pg_class_desc;
 	HeapTuple	return_tuple;
 
-	pg_class_desc = heap_openr(RelationRelationName);
-	if (!IsInitProcessingMode())
-		LockRelation(pg_class_desc, AccessShareLock);
+	pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
 
 	switch (buildinfo.infotype)
 	{
@@ -389,18 +387,10 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
 
 		default:
 			elog(ERROR, "ScanPgRelation: bad buildinfo");
-
-			/*
-			 * XXX I hope this is right.  It seems better than returning
-			 * an uninitialized value
-			 */
-			return_tuple = NULL;
+			return_tuple = NULL; /* keep compiler quiet */
 	}
 
-	/* all done */
-	if (!IsInitProcessingMode())
-		UnlockRelation(pg_class_desc, AccessShareLock);
-	heap_close(pg_class_desc);
+	heap_close(pg_class_desc, AccessShareLock);
 
 	return return_tuple;
 }
@@ -508,7 +498,7 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 	 *	open pg_attribute and begin a scan
 	 * ----------------
 	 */
-	pg_attribute_desc = heap_openr(AttributeRelationName);
+	pg_attribute_desc = heap_openr(AttributeRelationName, AccessShareLock);
 	pg_attribute_scan = heap_beginscan(pg_attribute_desc, 0, SnapshotNow, 1, &key);
 
 	/* ----------------
@@ -544,7 +534,7 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 	 * ----------------
 	 */
 	heap_endscan(pg_attribute_scan);
-	heap_close(pg_attribute_desc);
+	heap_close(pg_attribute_desc, AccessShareLock);
 }
 
 static void
@@ -562,7 +552,7 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
 
 	constr->has_not_null = false;
 
-	attrel = heap_openr(AttributeRelationName);
+	attrel = heap_openr(AttributeRelationName, AccessShareLock);
 
 	for (i = 1; i <= relation->rd_rel->relnatts; i++)
 	{
@@ -597,7 +587,7 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
 		}
 	}
 
-	heap_close(attrel);
+	heap_close(attrel, AccessShareLock);
 
 	if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
 	{
@@ -677,7 +667,7 @@ RelationBuildRuleLock(Relation relation)
 	 *	open pg_attribute and begin a scan
 	 * ----------------
 	 */
-	pg_rewrite_desc = heap_openr(RewriteRelationName);
+	pg_rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock);
 	pg_rewrite_scan = heap_beginscan(pg_rewrite_desc, 0, SnapshotNow, 1, &key);
 	pg_rewrite_tupdesc = RelationGetDescr(pg_rewrite_desc);
 
@@ -732,7 +722,7 @@ RelationBuildRuleLock(Relation relation)
 	 * ----------------
 	 */
 	heap_endscan(pg_rewrite_scan);
-	heap_close(pg_rewrite_desc);
+	heap_close(pg_rewrite_desc, AccessShareLock);
 
 	/* ----------------
 	 *	form a RuleLock and insert into relation
@@ -765,9 +755,9 @@ RelationBuildRuleLock(Relation relation)
  *	uint16				   rd_refcnt;	 reference count
  *	Form_pg_am			   rd_am;		 AM tuple
  *	Form_pg_class		   rd_rel;		 RELATION tuple
- *	Oid					   rd_id;		 relations's object id
- *	Pointer				   lockInfo;	 ptr. to misc. info.
- *	TupleDesc			   rd_att;		 tuple desciptor
+ *	Oid					   rd_id;		 relation's object id
+ *	LockInfoData		   rd_lockInfo;	 lock manager's info
+ *	TupleDesc			   rd_att;		 tuple descriptor
  *
  *		Note: rd_ismem (rel is in-memory only) is currently unused
  *		by any part of the system.	someday this will indicate that
@@ -1048,14 +1038,18 @@ formrdesc(char *relationName,
 	 */
 	RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
 
+	/* ----------------
+	 *	initialize the relation lock manager information
+	 * ----------------
+	 */
+	RelationInitLockInfo(relation);		/* see lmgr.c */
+
 	/* ----------------
 	 *	add new reldesc to relcache
 	 * ----------------
 	 */
 	RelationCacheInsert(relation);
 
-	RelationInitLockInfo(relation);
-
 	/*
 	 * Determining this requires a scan on pg_class, but to do the scan
 	 * the rdesc for pg_class must already exist.  Therefore we must do
@@ -1074,9 +1068,13 @@ formrdesc(char *relationName,
 /* --------------------------------
  *		RelationIdCacheGetRelation
  *
- *		only try to get the reldesc by looking up the cache
- *		do not go to the disk.	this is used by BlockPrepareFile()
- *		and RelationIdGetRelation below.
+ *		Lookup a reldesc by OID.
+ *		Only try to get the reldesc by looking up the cache
+ *		do not go to the disk.
+ *
+ *		NB: relation ref count is incremented if successful.
+ *		Caller should eventually decrement count.  (Usually,
+ *		that happens by calling RelationClose().)
  * --------------------------------
  */
 Relation
@@ -1103,6 +1101,8 @@ RelationIdCacheGetRelation(Oid relationId)
 
 /* --------------------------------
  *		RelationNameCacheGetRelation
+ *
+ *		As above, but lookup by name.
  * --------------------------------
  */
 static Relation
@@ -1136,8 +1136,11 @@ RelationNameCacheGetRelation(char *relationName)
 /* --------------------------------
  *		RelationIdGetRelation
  *
- *		return a relation descriptor based on its id.
- *		return a cached value if possible
+ *		Lookup a reldesc by OID; make one if not already in cache.
+ *
+ *		NB: relation ref count is incremented, or set to 1 if new entry.
+ *		Caller should eventually decrement count.  (Usually,
+ *		that happens by calling RelationClose().)
  * --------------------------------
  */
 Relation
@@ -1176,8 +1179,7 @@ RelationIdGetRelation(Oid relationId)
 /* --------------------------------
  *		RelationNameGetRelation
  *
- *		return a relation descriptor based on its name.
- *		return a cached value if possible
+ *		As above, but lookup by name.
  * --------------------------------
  */
 Relation
@@ -1289,7 +1291,6 @@ RelationFlushRelation(Relation *relationPtr,
 	/* Free all the subsidiary data structures of the relcache entry */
 	FreeTupleDesc(relation->rd_att);
 	FreeTriggerDesc(relation);
-	pfree(RelationGetLockInfo(relation));
 	pfree(RelationGetForm(relation));
 
 	/* If we're really done with the relcache entry, blow it away.
@@ -1530,10 +1531,10 @@ RelationRegisterRelation(Relation relation)
 	if (oldcxt != (MemoryContext) CacheCxt)
 		elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
 
-	RelationCacheInsert(relation);
-
 	RelationInitLockInfo(relation);
 
+	RelationCacheInsert(relation);
+
 	/*
 	 * we've just created the relation. It is invisible to anyone else
 	 * before the transaction is committed. Setting rd_myxactonly allows
@@ -1692,7 +1693,7 @@ AttrDefaultFetch(Relation relation)
 						   (RegProcedure) F_OIDEQ,
 						   ObjectIdGetDatum(RelationGetRelid(relation)));
 
-	adrel = heap_openr(AttrDefaultRelationName);
+	adrel = heap_openr(AttrDefaultRelationName, AccessShareLock);
 	irel = index_openr(AttrDefaultIndex);
 	sd = index_beginscan(irel, false, 1, &skey);
 	tuple.t_data = NULL;
@@ -1754,7 +1755,7 @@ AttrDefaultFetch(Relation relation)
 	index_endscan(sd);
 	pfree(sd);
 	index_close(irel);
-	heap_close(adrel);
+	heap_close(adrel, AccessShareLock);
 }
 
 static void
@@ -1779,7 +1780,7 @@ RelCheckFetch(Relation relation)
 						   (RegProcedure) F_OIDEQ,
 						   ObjectIdGetDatum(RelationGetRelid(relation)));
 
-	rcrel = heap_openr(RelCheckRelationName);
+	rcrel = heap_openr(RelCheckRelationName, AccessShareLock);
 	irel = index_openr(RelCheckIndex);
 	sd = index_beginscan(irel, false, 1, &skey);
 	tuple.t_data = NULL;
@@ -1834,8 +1835,7 @@ RelCheckFetch(Relation relation)
 	index_endscan(sd);
 	pfree(sd);
 	index_close(irel);
-	heap_close(rcrel);
-
+	heap_close(rcrel, AccessShareLock);
 }
 
 /*
@@ -1929,9 +1929,6 @@ init_irels(void)
 		/* the file descriptor is not yet opened */
 		ird->rd_fd = -1;
 
-		/* lock info is not initialized */
-		ird->lockInfo = (char *) NULL;
-
 		/* next, read the access method tuple form */
 		if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
 		{
@@ -2038,8 +2035,9 @@ init_irels(void)
 
 		ird->rd_support = support;
 
-		RelationCacheInsert(ird);
 		RelationInitLockInfo(ird);
+
+		RelationCacheInsert(ird);
 	}
 }
 
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index c9c7770f8ccbb7a5e531967c51be16906d2cf093..204f13ffab9f34aa3a92a1a659d37f86cb76ce90 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.35 1999/09/04 22:00:30 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.36 1999/09/18 19:07:55 tgl Exp $
  *
  * NOTES
  *	  These routines allow the parser/planner/executor to perform
@@ -575,11 +575,19 @@ SearchSysCacheGetAttribute(int cacheId,
 	Datum		attributeValue;
 	void	   *returnValue;
 
-	tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
+	/*
+	 * Open the relation first, to ensure we are in sync with SI inval
+	 * events --- we don't want the tuple found in the cache to be
+	 * invalidated out from under us.
+	 */
 	cacheName = cacheinfo[cacheId].name;
+	relation = heap_openr(cacheName, AccessShareLock);
+
+	tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
 
 	if (!HeapTupleIsValid(tp))
 	{
+		heap_close(relation, AccessShareLock);
 #ifdef	CACHEDEBUG
 		elog(DEBUG,
 			 "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
@@ -588,8 +596,6 @@ SearchSysCacheGetAttribute(int cacheId,
 		return NULL;
 	}
 
-	relation = heap_openr(cacheName);
-
 	if (attributeNumber < 0 &&
 		attributeNumber > FirstLowInvalidHeapAttributeNumber)
 	{
@@ -604,6 +610,7 @@ SearchSysCacheGetAttribute(int cacheId,
 	}
 	else
 	{
+		heap_close(relation, AccessShareLock);
 		elog(ERROR,
 			 "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
 			 attributeNumber, cacheName, cacheId);
@@ -617,11 +624,11 @@ SearchSysCacheGetAttribute(int cacheId,
 
 	if (isNull)
 	{
-
 		/*
 		 * Used to be an elog(DEBUG, ...) here and a claim that it should
 		 * be a FATAL error, I don't think either is warranted -mer 6/9/92
 		 */
+		heap_close(relation, AccessShareLock);
 		return NULL;
 	}
 
@@ -639,6 +646,6 @@ SearchSysCacheGetAttribute(int cacheId,
 		returnValue = (void *) tmp;
 	}
 
-	heap_close(relation);
+	heap_close(relation, AccessShareLock);
 	return returnValue;
 }
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index d48d8b8840aefc08b77fe7b2678430831f44f044..dcf2814171b583600a8b974c9b43dfb63eeb1ab6 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.31 1999/07/17 20:18:04 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.32 1999/09/18 19:08:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,8 +56,13 @@ fmgr_dynamic(Oid procedureId, int *pronargs)
 
 	/*
 	 * The procedure isn't a builtin, so we'll have to do a catalog lookup
-	 * to find its pg_proc entry.
+	 * to find its pg_proc entry.  Moreover, since probin is varlena, we're
+	 * going to have to use heap_getattr, which means we need the reldesc,
+	 * which means we need to open the relation.  So we might as well do that
+	 * first and get the benefit of SI inval if needed.
 	 */
+	rel = heap_openr(ProcedureRelationName, AccessShareLock);
+
 	procedureTuple = SearchSysCacheTuple(PROOID,
 										 ObjectIdGetDatum(procedureId),
 										 0, 0, 0);
@@ -71,36 +76,24 @@ fmgr_dynamic(Oid procedureId, int *pronargs)
 	procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
 	proname = procedureStruct->proname.data;
 	pronargs_save = *pronargs = procedureStruct->pronargs;
-
-	/*
-	 * Extract the procedure info from the pg_proc tuple. Since probin is
-	 * varlena, do a amgetattr() on the procedure tuple.  To do that, we
-	 * need the rel for the procedure relation, so...
-	 */
-
-	/* open pg_procedure */
-
-	rel = heap_openr(ProcedureRelationName);
-	if (!RelationIsValid(rel))
-	{
-		elog(ERROR, "fmgr: Could not open relation %s",
-			 ProcedureRelationName);
-		return (func_ptr) NULL;
-	}
 	probinattr = heap_getattr(procedureTuple,
 							  Anum_pg_proc_probin,
 							  RelationGetDescr(rel), &isnull);
 	if (!PointerIsValid(probinattr) /* || isnull */ )
 	{
-		heap_close(rel);
+		heap_close(rel, AccessShareLock);
 		elog(ERROR, "fmgr: Could not extract probin for %u from %s",
 			 procedureId, ProcedureRelationName);
 		return (func_ptr) NULL;
 	}
 	probinstring = textout((struct varlena *) probinattr);
 
+	heap_close(rel, AccessShareLock);
+
 	user_fn = handle_load(probinstring, proname);
 
+	pfree(probinstring);
+
 	procedureId_save = procedureId;
 	user_fn_save = user_fn;
 
diff --git a/src/backend/utils/misc/database.c b/src/backend/utils/misc/database.c
index 39270f35c0c4292a9d0ef3ea064f62011a68677e..321ab943aeac394811e8d136d75ba550c696dece 100644
--- a/src/backend/utils/misc/database.c
+++ b/src/backend/utils/misc/database.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.28 1999/07/17 20:18:11 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.29 1999/09/18 19:08:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,10 +43,7 @@ GetDatabaseInfo(char *name, int4 *owner, char *path)
 	HeapScanDesc scan;
 	ScanKeyData scanKey;
 
-	dbrel = heap_openr(DatabaseRelationName);
-	if (!RelationIsValid(dbrel))
-		elog(FATAL, "GetDatabaseInfo: cannot open relation \"%-.*s\"",
-			 DatabaseRelationName);
+	dbrel = heap_openr(DatabaseRelationName, AccessShareLock);
 
 	ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
 						   F_NAMEEQ, NameGetDatum(name));
@@ -71,6 +68,7 @@ GetDatabaseInfo(char *name, int4 *owner, char *path)
 	{
 		elog(NOTICE, "GetDatabaseInfo: %s entry not found %s",
 			 DatabaseRelationName, name);
+		heap_close(dbrel, AccessShareLock);
 		return TRUE;
 	}
 
@@ -88,7 +86,7 @@ GetDatabaseInfo(char *name, int4 *owner, char *path)
 	memcpy(dbpath, VARDATA(dbtext), (VARSIZE(dbtext) - VARHDRSZ));
 	*(dbpath + (VARSIZE(dbtext) - VARHDRSZ)) = '\0';
 
-	heap_close(dbrel);
+	heap_close(dbrel, AccessShareLock);
 
 	owner = palloc(sizeof(Oid));
 	*owner = dbowner;
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 8c1461122fcbf7c239c57b59609b6f185a7af8cb..b6dccc33fa8d7c69f4c9f38be84bf382b264aaf3 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: heapam.h,v 1.45 1999/07/16 17:07:26 momjian Exp $
+ * $Id: heapam.h,v 1.46 1999/09/18 19:08:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "access/relscan.h"
 #include "access/tupmacs.h"
 #include "storage/block.h"
+#include "storage/lmgr.h"
 #include "utils/rel.h"
 #include "utils/tqual.h"
 
@@ -246,9 +247,9 @@ extern HeapAccessStatistics heap_access_stats;	/* in stats.c */
 
 /* heapam.c */
 
-extern Relation heap_open(Oid relationId);
-extern Relation heap_openr(char *relationName);
-extern void heap_close(Relation relation);
+extern Relation heap_open(Oid relationId, LOCKMODE lockmode);
+extern Relation heap_openr(char *relationName, LOCKMODE lockmode);
+extern void heap_close(Relation relation, LOCKMODE lockmode);
 extern HeapScanDesc heap_beginscan(Relation relation, int atend,
 			   Snapshot snapshot, unsigned nkeys, ScanKey key);
 extern void heap_rescan(HeapScanDesc scan, bool scanFromEnd, ScanKey key);
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index 98d8be3369d01802141091f9eb895d6807d35066..b98f0fb820f057834821273d52b50fe93579761c 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: buf_internals.h,v 1.31 1999/07/16 17:07:37 momjian Exp $
+ * $Id: buf_internals.h,v 1.32 1999/09/18 19:08:18 tgl Exp $
  *
  * NOTE
  *		If BUFFERPAGE0 is defined, then 0 will be used as a
@@ -64,8 +64,8 @@ struct buftag
 
 #define INIT_BUFFERTAG(a,xx_reln,xx_blockNum) \
 ( \
-	(a)->blockNum = xx_blockNum, \
-	(a)->relId = ((LockInfo)(xx_reln->lockInfo))->lockRelId \
+	(a)->blockNum = (xx_blockNum), \
+	(a)->relId = (xx_reln)->rd_lockInfo.lockRelId \
 )
 
 #define BAD_BUFFER_ID(bid) ((bid<1) || (bid>(NBuffers)))
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 8903af8ec6bd43396d62e1d87c264a5eac7a7eb1..302bedb6771d115a78d2a8a551d583b60ccc7786 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lmgr.h,v 1.22 1999/07/15 23:04:11 momjian Exp $
+ * $Id: lmgr.h,v 1.23 1999/09/18 19:08:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,11 @@
 #include "storage/lock.h"
 #include "utils/rel.h"
 
+/* These are the valid values of type LOCKMODE: */
+
+/* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */
+#define NoLock					0
+
 #define AccessShareLock			1		/* SELECT */
 #define RowShareLock			2		/* SELECT FOR UPDATE */
 #define RowExclusiveLock		3		/* INSERT, UPDATE, DELETE */
@@ -27,21 +32,6 @@
 extern LOCKMETHOD LockTableId;
 
 
-typedef struct LockRelId
-{
-	Oid			relId;			/* a relation identifier */
-	Oid			dbId;			/* a database identifier */
-} LockRelId;
-
-typedef struct LockInfoData
-{
-	LockRelId	lockRelId;
-} LockInfoData;
-
-typedef LockInfoData *LockInfo;
-
-#define LockInfoIsValid(lockinfo)	PointerIsValid(lockinfo)
-
 extern LOCKMETHOD InitLockTable(void);
 extern void RelationInitLockInfo(Relation relation);
 
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index c95f51e89d1e523af92d2c3a3ad2f83dc290c392..f2789b39e09d15717749598430fe8049f47d09aa 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rel.h,v 1.25 1999/07/16 17:07:40 momjian Exp $
+ * $Id: rel.h,v 1.26 1999/09/18 19:08:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,26 @@
 #include "rewrite/prs2lock.h"
 #include "storage/fd.h"
 
+
+/*
+ * LockRelId and LockInfo really belong to lmgr.h, but it's more convenient
+ * to declare them here so we can have a LockInfoData field in a Relation.
+ */
+
+typedef struct LockRelId
+{
+	Oid			relId;			/* a relation identifier */
+	Oid			dbId;			/* a database identifier */
+} LockRelId;
+
+typedef struct LockInfoData
+{
+	LockRelId	lockRelId;
+} LockInfoData;
+
+typedef LockInfoData *LockInfo;
+
+
 typedef struct Trigger
 {
 	char	   *tgname;
@@ -44,20 +64,21 @@ typedef struct TriggerDesc
 	Trigger    *triggers;
 } TriggerDesc;
 
+
 typedef struct RelationData
 {
 	File		rd_fd;			/* open file descriptor */
 	int			rd_nblocks;		/* number of blocks in rel */
 	uint16		rd_refcnt;		/* reference count */
-	bool		rd_myxactonly;	/* uses the local buffer mgr */
+	bool		rd_myxactonly;	/* rel uses the local buffer mgr */
 	bool		rd_isnailed;	/* rel is nailed in cache */
 	bool		rd_isnoname;	/* rel has no name */
 	bool		rd_nonameunlinked;		/* noname rel already unlinked */
 	Form_pg_am	rd_am;			/* AM tuple */
 	Form_pg_class rd_rel;		/* RELATION tuple */
-	Oid			rd_id;			/* relations's object id */
-	Pointer		lockInfo;		/* ptr. to misc. info. */
-	TupleDesc	rd_att;			/* tuple desciptor */
+	Oid			rd_id;			/* relation's object id */
+	LockInfoData rd_lockInfo;	/* lock manager's info for locking relation */
+	TupleDesc	rd_att;			/* tuple descriptor */
 	RuleLock   *rd_rules;		/* rewrite rules */
 	IndexStrategy rd_istrat;
 	RegProcedure *rd_support;
@@ -66,6 +87,7 @@ typedef struct RelationData
 
 typedef RelationData *Relation;
 
+
 /* ----------------
  *		RelationPtr is used in the executor to support index scans
  *		where we have to keep track of several index relations in an
@@ -74,7 +96,6 @@ typedef RelationData *Relation;
  */
 typedef Relation *RelationPtr;
 
-#define InvalidRelation ((Relation)NULL)
 
 /*
  * RelationIsValid
@@ -82,6 +103,8 @@ typedef Relation *RelationPtr;
  */
 #define RelationIsValid(relation) PointerIsValid(relation)
 
+#define InvalidRelation ((Relation) NULL)
+
 /*
  * RelationGetSystemPort
  *		Returns system port of a relation.
@@ -91,13 +114,6 @@ typedef Relation *RelationPtr;
  */
 #define RelationGetSystemPort(relation) ((relation)->rd_fd)
 
-/*
- * RelationGetLockInfo
- *		Returns the lock information structure in the reldesc
- *
- */
-#define RelationGetLockInfo(relation) ((relation)->lockInfo)
-
 /*
  * RelationHasReferenceCountZero
  *		True iff relation reference count is zero.
@@ -112,13 +128,13 @@ 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
@@ -135,7 +151,6 @@ typedef Relation *RelationPtr;
  */
 #define RelationGetForm(relation) ((relation)->rd_rel)
 
-
 /*
  * RelationGetRelid
  *
@@ -151,7 +166,6 @@ typedef Relation *RelationPtr;
  */
 #define RelationGetFile(relation) ((relation)->rd_fd)
 
-
 /*
  * RelationGetRelationName
  *
@@ -160,21 +174,19 @@ typedef Relation *RelationPtr;
 #define RelationGetRelationName(relation) (&(relation)->rd_rel->relname)
 
 /*
- * RelationGetRelationName
+ * RelationGetNumberOfAttributes
  *
- *	  Returns a the number of attributes.
+ *	  Returns the number of attributes.
  */
 #define RelationGetNumberOfAttributes(relation) ((relation)->rd_rel->relnatts)
 
 /*
  * RelationGetDescr
  *		Returns tuple descriptor for a relation.
- *
- * Note:
- *		Assumes relation descriptor is valid.
  */
 #define RelationGetDescr(relation) ((relation)->rd_att)
 
+
 extern IndexStrategy RelationGetIndexStrategy(Relation relation);
 
 extern void RelationSetIndexSupport(Relation relation, IndexStrategy strategy,