From 7d05310828aae801fd1483e638771a4034cbecd7 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 2 Nov 2001 16:30:29 +0000
Subject: [PATCH] Fix problem reported by Alex Korn: if a relation has been
 dropped and recreated since the start of our transaction, our first reference
 to it errored out because we'd try to reuse our old relcache entry for it. Do
 this by accepting SI inval messages just before relcache search in
 heap_openr, so that dead relcache entries will be flushed before we search. 
 Also, break heap_open/openr into two pairs of routines, relation_open(r) and
 heap_open(r).  The relation_open routines make no tests on relkind and so can
 be used to open anything that has a pg_class entry.  The heap_open routines
 are wrappers that add a relkind test to preserve their established behavior. 
 Use the relation_open routines in several places that had various kluge
 solutions for opening rels that might be either heap or index rels.

Also, remove the old 'heap stats' code that's been superseded by Jan's
stats collector, and clean up some inconsistencies in error reporting
between the different types of ALTER TABLE.
---
 src/backend/access/heap/Makefile     |   4 +-
 src/backend/access/heap/heapam.c     | 160 +++++++------
 src/backend/access/heap/stats.c      | 333 ---------------------------
 src/backend/access/index/indexam.c   |  40 ++--
 src/backend/catalog/index.c          |  15 +-
 src/backend/commands/command.c       |  51 ++--
 src/backend/commands/comment.c       |  18 +-
 src/backend/commands/rename.c        |  17 +-
 src/backend/parser/parse_func.c      |  10 +-
 src/backend/utils/init/postinit.c    |   8 +-
 src/include/access/genam.h           |   4 +-
 src/include/access/heapam.h          |  78 +------
 src/test/regress/expected/errors.out |   4 +-
 src/test/regress/expected/temp.out   |   2 +-
 14 files changed, 150 insertions(+), 594 deletions(-)
 delete mode 100644 src/backend/access/heap/stats.c

diff --git a/src/backend/access/heap/Makefile b/src/backend/access/heap/Makefile
index 95575f8e325..352ced33929 100644
--- a/src/backend/access/heap/Makefile
+++ b/src/backend/access/heap/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for access/heap
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/access/heap/Makefile,v 1.11 2000/08/31 16:09:33 petere Exp $
+#    $Header: /cvsroot/pgsql/src/backend/access/heap/Makefile,v 1.12 2001/11/02 16:30:29 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,7 +12,7 @@ subdir = src/backend/access/heap
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = heapam.o hio.o stats.o tuptoaster.o
+OBJS = heapam.o hio.o tuptoaster.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index f73ca50285b..bf7798a07dc 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,14 +8,16 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.126 2001/10/25 05:49:21 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.127 2001/11/02 16:30:29 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
- *		heap_open		- open a heap relation by relationId
+ *		relation_open	- open any relation by relation OID
+ *		relation_openr	- open any relation by name
+ *		relation_close	- close any relation
+ *		heap_open		- open a heap relation by relation OID
  *		heap_openr		- open a heap relation by name
- *		heap_open[r]_nofail - same, but return NULL on failure instead of elog
- *		heap_close		- close a heap relation
+ *		heap_close		- (now just a macro for relation_close)
  *		heap_beginscan	- begin relation scan
  *		heap_rescan		- restart a relation scan
  *		heap_endscan	- end relation scan
@@ -440,15 +442,21 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
  */
 
 /* ----------------
- *		heap_open - open a heap relation by relationId
+ *		relation_open - open any relation by relation OID
  *
  *		If lockmode is not "NoLock", the specified kind of lock is
- *		obtained on the relation.
+ *		obtained on the relation.  (Generally, NoLock should only be
+ *		used if the caller knows it has some appropriate lock on the
+ *		relation already.)
+ *
  *		An error is raised if the relation does not exist.
+ *
+ *		NB: a "relation" is anything with a pg_class entry.  The caller is
+ *		expected to check whether the relkind is something it can handle.
  * ----------------
  */
 Relation
-heap_open(Oid relationId, LOCKMODE lockmode)
+relation_open(Oid relationId, LOCKMODE lockmode)
 {
 	Relation	r;
 
@@ -466,10 +474,6 @@ heap_open(Oid relationId, LOCKMODE lockmode)
 	if (!RelationIsValid(r))
 		elog(ERROR, "Relation %u does not exist", relationId);
 
-	/* Under no circumstances will we return an index as a relation. */
-	if (r->rd_rel->relkind == RELKIND_INDEX)
-		elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
-
 	if (lockmode != NoLock)
 		LockRelation(r, lockmode);
 
@@ -477,15 +481,13 @@ heap_open(Oid relationId, LOCKMODE lockmode)
 }
 
 /* ----------------
- *		heap_openr - open a heap relation by name
+ *		relation_openr - open any relation by name
  *
- *		If lockmode is not "NoLock", the specified kind of lock is
- *		obtained on the relation.
- *		An error is raised if the relation does not exist.
+ *		As above, but lookup by name instead of OID.
  * ----------------
  */
 Relation
-heap_openr(const char *relationName, LOCKMODE lockmode)
+relation_openr(const char *relationName, LOCKMODE lockmode)
 {
 	Relation	r;
 
@@ -497,116 +499,111 @@ heap_openr(const char *relationName, LOCKMODE lockmode)
 	IncrHeapAccessStat(local_openr);
 	IncrHeapAccessStat(global_openr);
 
+	/*
+	 * Check for shared-cache-inval messages before trying to open the
+	 * relation.  This is needed to cover the case where the name identifies
+	 * a rel that has been dropped and recreated since the start of our
+	 * transaction: if we don't flush the old relcache entry then we'll
+	 * latch onto that entry and suffer an error when we do LockRelation.
+	 * Note that relation_open does not need to do this, since a relation's
+	 * OID never changes.
+	 *
+	 * We skip this if asked for NoLock, on the assumption that the caller
+	 * has already ensured some appropriate lock is held.
+	 */
+	if (lockmode != NoLock)
+		AcceptInvalidationMessages();
+
 	/* The relcache does all the real work... */
 	r = RelationNameGetRelation(relationName);
 
 	if (!RelationIsValid(r))
-		elog(ERROR, "Relation '%s' does not exist", relationName);
-
-	/* Under no circumstances will we return an index as a relation. */
-	if (r->rd_rel->relkind == RELKIND_INDEX)
-		elog(ERROR, "%s is an index relation", RelationGetRelationName(r));
+		elog(ERROR, "Relation \"%s\" does not exist", relationName);
 
 	if (lockmode != NoLock)
 		LockRelation(r, lockmode);
 
-	pgstat_initstats(&r->pgstat_info, r);
-
-	pgstat_initstats(&r->pgstat_info, r);
-
 	return r;
 }
 
 /* ----------------
- *		heap_open_nofail - open a heap relation by relationId,
- *				do not raise error on failure
+ *		relation_close - close any relation
+ *
+ *		If lockmode is not "NoLock", we first release the specified lock.
  *
- *		The caller must check for a NULL return value indicating
- *		that no such relation exists.
- *		No lock is obtained on the relation, either.
+ *		Note that it is often sensible to hold a lock beyond relation_close;
+ *		in that case, the lock is released automatically at xact end.
  * ----------------
  */
-Relation
-heap_open_nofail(Oid relationId)
+void
+relation_close(Relation relation, LOCKMODE lockmode)
 {
-	Relation	r;
+	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
 
 	/*
 	 * increment access statistics
 	 */
-	IncrHeapAccessStat(local_open);
-	IncrHeapAccessStat(global_open);
-
-	/* The relcache does all the real work... */
-	r = RelationIdGetRelation(relationId);
+	IncrHeapAccessStat(local_close);
+	IncrHeapAccessStat(global_close);
 
-	/* 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", RelationGetRelationName(r));
+	if (lockmode != NoLock)
+		UnlockRelation(relation, lockmode);
 
-	return r;
+	/* The relcache does the real work... */
+	RelationClose(relation);
 }
 
+
 /* ----------------
- *		heap_openr_nofail - open a heap relation by name,
- *				do not raise error on failure
+ *		heap_open - open a heap relation by relation OID
  *
- *		The caller must check for a NULL return value indicating
- *		that no such relation exists.
- *		No lock is obtained on the relation, either.
+ *		This is essentially relation_open plus check that the relation
+ *		is not an index or special relation.  (The caller should also check
+ *		that it's not a view before assuming it has storage.)
  * ----------------
  */
 Relation
-heap_openr_nofail(const char *relationName)
+heap_open(Oid relationId, LOCKMODE lockmode)
 {
 	Relation	r;
 
-	/*
-	 * increment access statistics
-	 */
-	IncrHeapAccessStat(local_openr);
-	IncrHeapAccessStat(global_openr);
+	r = relation_open(relationId, lockmode);
 
-	/* 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", RelationGetRelationName(r));
-
-	if (RelationIsValid(r))
-		pgstat_initstats(&r->pgstat_info, r);
+	if (r->rd_rel->relkind == RELKIND_INDEX)
+		elog(ERROR, "%s is an index relation",
+			 RelationGetRelationName(r));
+	else if (r->rd_rel->relkind == RELKIND_SPECIAL)
+		elog(ERROR, "%s is a special relation",
+			 RelationGetRelationName(r));
 
-	if (RelationIsValid(r))
-		pgstat_initstats(&r->pgstat_info, r);
+	pgstat_initstats(&r->pgstat_info, r);
 
 	return r;
 }
 
 /* ----------------
- *		heap_close - close a heap relation
+ *		heap_openr - open a heap relation by name
  *
- *		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.
+ *		As above, but lookup by name instead of OID.
  * ----------------
  */
-void
-heap_close(Relation relation, LOCKMODE lockmode)
+Relation
+heap_openr(const char *relationName, LOCKMODE lockmode)
 {
-	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+	Relation	r;
 
-	/*
-	 * increment access statistics
-	 */
-	IncrHeapAccessStat(local_close);
-	IncrHeapAccessStat(global_close);
+	r = relation_openr(relationName, lockmode);
 
-	if (lockmode != NoLock)
-		UnlockRelation(relation, lockmode);
+	if (r->rd_rel->relkind == RELKIND_INDEX)
+		elog(ERROR, "%s is an index relation",
+			 RelationGetRelationName(r));
+	else if (r->rd_rel->relkind == RELKIND_SPECIAL)
+		elog(ERROR, "%s is a special relation",
+			 RelationGetRelationName(r));
 
-	/* The relcache does the real work... */
-	RelationClose(relation);
+	pgstat_initstats(&r->pgstat_info, r);
+
+	return r;
 }
 
 
@@ -2332,8 +2329,7 @@ newsame:;
 	}
 
 	/* undo */
-	if (XLByteLT(PageGetLSN(page), lsn))		/* changes are not applied
-												 * ?! */
+	if (XLByteLT(PageGetLSN(page), lsn))		/* changes not applied?! */
 		elog(STOP, "heap_update_undo: bad new tuple page LSN");
 
 	elog(STOP, "heap_update_undo: unimplemented");
diff --git a/src/backend/access/heap/stats.c b/src/backend/access/heap/stats.c
deleted file mode 100644
index 6f5dfbea141..00000000000
--- a/src/backend/access/heap/stats.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * stats.c
- *	  heap access method debugging statistic collection routines
- *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.25 2001/10/25 05:49:21 momjian Exp $
- *
- * NOTES
- *	  initam should be moved someplace else.
- *
- *-------------------------------------------------------------------------
- */
-
-#include <time.h>
-
-#include "postgres.h"
-
-#include "access/heapam.h"
-
-
-static void InitHeapAccessStatistics(void);
-
-/* ----------------
- *		InitHeapAccessStatistics
- * ----------------
- */
-HeapAccessStatistics heap_access_stats = (HeapAccessStatistics) NULL;
-
-static void
-InitHeapAccessStatistics()
-{
-	MemoryContext oldContext;
-	HeapAccessStatistics stats;
-
-	/*
-	 * make sure we don't initialize things twice
-	 */
-	if (heap_access_stats != NULL)
-		return;
-
-	/*
-	 * allocate statistics structure from the top memory context
-	 */
-	oldContext = MemoryContextSwitchTo(TopMemoryContext);
-
-	stats = (HeapAccessStatistics)
-		palloc(sizeof(HeapAccessStatisticsData));
-
-	/*
-	 * initialize fields to default values
-	 */
-	stats->global_open = 0;
-	stats->global_openr = 0;
-	stats->global_close = 0;
-	stats->global_beginscan = 0;
-	stats->global_rescan = 0;
-	stats->global_endscan = 0;
-	stats->global_getnext = 0;
-	stats->global_fetch = 0;
-	stats->global_insert = 0;
-	stats->global_delete = 0;
-	stats->global_replace = 0;
-	stats->global_mark4update = 0;
-	stats->global_markpos = 0;
-	stats->global_restrpos = 0;
-	stats->global_BufferGetRelation = 0;
-	stats->global_RelationIdGetRelation = 0;
-	stats->global_RelationIdGetRelation_Buf = 0;
-	stats->global_getreldesc = 0;
-	stats->global_heapgettup = 0;
-	stats->global_RelationPutHeapTuple = 0;
-	stats->global_RelationPutLongHeapTuple = 0;
-
-	stats->local_open = 0;
-	stats->local_openr = 0;
-	stats->local_close = 0;
-	stats->local_beginscan = 0;
-	stats->local_rescan = 0;
-	stats->local_endscan = 0;
-	stats->local_getnext = 0;
-	stats->local_fetch = 0;
-	stats->local_insert = 0;
-	stats->local_delete = 0;
-	stats->local_replace = 0;
-	stats->local_mark4update = 0;
-	stats->local_markpos = 0;
-	stats->local_restrpos = 0;
-	stats->local_BufferGetRelation = 0;
-	stats->local_RelationIdGetRelation = 0;
-	stats->local_RelationIdGetRelation_Buf = 0;
-	stats->local_getreldesc = 0;
-	stats->local_heapgettup = 0;
-	stats->local_RelationPutHeapTuple = 0;
-	stats->local_RelationPutLongHeapTuple = 0;
-	stats->local_RelationNameGetRelation = 0;
-	stats->global_RelationNameGetRelation = 0;
-
-	/*
-	 * record init times
-	 */
-	time(&stats->init_global_timestamp);
-	time(&stats->local_reset_timestamp);
-	time(&stats->last_request_timestamp);
-
-	/*
-	 * return to old memory context
-	 */
-	MemoryContextSwitchTo(oldContext);
-
-	heap_access_stats = stats;
-}
-
-#ifdef NOT_USED
-/* ----------------
- *		ResetHeapAccessStatistics
- * ----------------
- */
-void
-ResetHeapAccessStatistics()
-{
-	HeapAccessStatistics stats;
-
-	/*
-	 * do nothing if stats aren't initialized
-	 */
-	if (heap_access_stats == NULL)
-		return;
-
-	stats = heap_access_stats;
-
-	/*
-	 * reset local counts
-	 */
-	stats->local_open = 0;
-	stats->local_openr = 0;
-	stats->local_close = 0;
-	stats->local_beginscan = 0;
-	stats->local_rescan = 0;
-	stats->local_endscan = 0;
-	stats->local_getnext = 0;
-	stats->local_fetch = 0;
-	stats->local_insert = 0;
-	stats->local_delete = 0;
-	stats->local_replace = 0;
-	stats->local_mark4update = 0;
-	stats->local_markpos = 0;
-	stats->local_restrpos = 0;
-	stats->local_BufferGetRelation = 0;
-	stats->local_RelationIdGetRelation = 0;
-	stats->local_RelationIdGetRelation_Buf = 0;
-	stats->local_getreldesc = 0;
-	stats->local_heapgettup = 0;
-	stats->local_RelationPutHeapTuple = 0;
-	stats->local_RelationPutLongHeapTuple = 0;
-
-	/*
-	 * reset local timestamps
-	 */
-	time(&stats->local_reset_timestamp);
-	time(&stats->last_request_timestamp);
-}
-#endif
-
-#ifdef NOT_USED
-/* ----------------
- *		GetHeapAccessStatistics
- * ----------------
- */
-HeapAccessStatistics
-GetHeapAccessStatistics()
-{
-	HeapAccessStatistics stats;
-
-	/*
-	 * return nothing if stats aren't initialized
-	 */
-	if (heap_access_stats == NULL)
-		return NULL;
-
-	/*
-	 * record the current request time
-	 */
-	time(&heap_access_stats->last_request_timestamp);
-
-	/*
-	 * allocate a copy of the stats and return it to the caller.
-	 */
-	stats = (HeapAccessStatistics)
-		palloc(sizeof(HeapAccessStatisticsData));
-
-	memmove(stats,
-			heap_access_stats,
-			sizeof(HeapAccessStatisticsData));
-
-	return stats;
-}
-#endif
-
-#ifdef NOT_USED
-/* ----------------
- *		PrintHeapAccessStatistics
- * ----------------
- */
-void
-PrintHeapAccessStatistics(HeapAccessStatistics stats)
-{
-	/*
-	 * return nothing if stats aren't valid
-	 */
-	if (stats == NULL)
-		return;
-
-	printf("======== heap am statistics ========\n");
-	printf("init_global_timestamp:      %s",
-		   ctime(&(stats->init_global_timestamp)));
-
-	printf("local_reset_timestamp:      %s",
-		   ctime(&(stats->local_reset_timestamp)));
-
-	printf("last_request_timestamp:     %s",
-		   ctime(&(stats->last_request_timestamp)));
-
-	printf("local/global_open:                        %6d/%6d\n",
-		   stats->local_open, stats->global_open);
-
-	printf("local/global_openr:                       %6d/%6d\n",
-		   stats->local_openr, stats->global_openr);
-
-	printf("local/global_close:                       %6d/%6d\n",
-		   stats->local_close, stats->global_close);
-
-	printf("local/global_beginscan:                   %6d/%6d\n",
-		   stats->local_beginscan, stats->global_beginscan);
-
-	printf("local/global_rescan:                      %6d/%6d\n",
-		   stats->local_rescan, stats->global_rescan);
-
-	printf("local/global_endscan:                     %6d/%6d\n",
-		   stats->local_endscan, stats->global_endscan);
-
-	printf("local/global_getnext:                     %6d/%6d\n",
-		   stats->local_getnext, stats->global_getnext);
-
-	printf("local/global_fetch:                       %6d/%6d\n",
-		   stats->local_fetch, stats->global_fetch);
-
-	printf("local/global_insert:                      %6d/%6d\n",
-		   stats->local_insert, stats->global_insert);
-
-	printf("local/global_delete:                      %6d/%6d\n",
-		   stats->local_delete, stats->global_delete);
-
-	printf("local/global_replace:                     %6d/%6d\n",
-		   stats->local_replace, stats->global_replace);
-
-	printf("local/global_mark4update:                     %6d/%6d\n",
-		   stats->local_mark4update, stats->global_mark4update);
-
-	printf("local/global_markpos:                     %6d/%6d\n",
-		   stats->local_markpos, stats->global_markpos);
-
-	printf("local/global_restrpos:                    %6d/%6d\n",
-		   stats->local_restrpos, stats->global_restrpos);
-
-	printf("================\n");
-
-	printf("local/global_BufferGetRelation:             %6d/%6d\n",
-		   stats->local_BufferGetRelation,
-		   stats->global_BufferGetRelation);
-
-	printf("local/global_RelationIdGetRelation:         %6d/%6d\n",
-		   stats->local_RelationIdGetRelation,
-		   stats->global_RelationIdGetRelation);
-
-	printf("local/global_RelationIdGetRelation_Buf:     %6d/%6d\n",
-		   stats->local_RelationIdGetRelation_Buf,
-		   stats->global_RelationIdGetRelation_Buf);
-
-	printf("local/global_getreldesc:                    %6d/%6d\n",
-		   stats->local_getreldesc, stats->global_getreldesc);
-
-	printf("local/global_heapgettup:                    %6d/%6d\n",
-		   stats->local_heapgettup, stats->global_heapgettup);
-
-	printf("local/global_RelationPutHeapTuple:          %6d/%6d\n",
-		   stats->local_RelationPutHeapTuple,
-		   stats->global_RelationPutHeapTuple);
-
-	printf("local/global_RelationPutLongHeapTuple:      %6d/%6d\n",
-		   stats->local_RelationPutLongHeapTuple,
-		   stats->global_RelationPutLongHeapTuple);
-
-	printf("===================================\n");
-
-	printf("\n");
-}
-#endif
-
-#ifdef NOT_USED
-/* ----------------
- *		PrintAndFreeHeapAccessStatistics
- * ----------------
- */
-void
-PrintAndFreeHeapAccessStatistics(HeapAccessStatistics stats)
-{
-	PrintHeapAccessStatistics(stats);
-	if (stats != NULL)
-		pfree(stats);
-}
-#endif
-
-/* ----------------------------------------------------------------
- *					access method initialization
- * ----------------------------------------------------------------
- */
-/* ----------------
- *		initam should someday be moved someplace else.
- * ----------------
- */
-void
-initam(void)
-{
-	/*
-	 * initialize heap statistics.
-	 */
-	InitHeapAccessStatistics();
-}
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 8e1d5b87332..523349ebdb5 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,12 +8,12 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.54 2001/10/25 05:49:21 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.55 2001/11/02 16:30:29 tgl Exp $
  *
  * INTERFACE ROUTINES
- *		index_open		- open an index relation by relationId
- *		index_openr		- open a index relation by name
- *		index_close		- close a index relation
+ *		index_open		- open an index relation by relation OID
+ *		index_openr		- open an index relation by name
+ *		index_close		- close an index relation
  *		index_beginscan - start a scan of an index
  *		index_rescan	- restart a scan of an index
  *		index_endscan	- end a scan
@@ -106,15 +106,17 @@
  *				   index_ interface functions
  * ----------------------------------------------------------------
  */
+
 /* ----------------
- *		index_open - open an index relation by relationId
- *
- *		presently the relcache routines do all the work we need
- *		to open/close index relations.	However, callers of index_open
- *		expect it to succeed, so we need to check for a failure return.
+ *		index_open - open an index relation by relation OID
  *
  *		Note: we acquire no lock on the index.	An AccessShareLock is
  *		acquired by index_beginscan (and released by index_endscan).
+ *		Generally, the caller should already hold some type of lock on
+ *		the parent relation to ensure that the index doesn't disappear.
+ *
+ *		This is a convenience routine adapted for indexscan use.
+ *		Some callers may prefer to use relation_open directly.
  * ----------------
  */
 Relation
@@ -122,13 +124,11 @@ index_open(Oid relationId)
 {
 	Relation	r;
 
-	r = RelationIdGetRelation(relationId);
-
-	if (!RelationIsValid(r))
-		elog(ERROR, "Index %u does not exist", relationId);
+	r = relation_open(relationId, NoLock);
 
 	if (r->rd_rel->relkind != RELKIND_INDEX)
-		elog(ERROR, "%s is not an index relation", RelationGetRelationName(r));
+		elog(ERROR, "%s is not an index relation",
+			 RelationGetRelationName(r));
 
 	pgstat_initstats(&r->pgstat_info, r);
 
@@ -136,23 +136,21 @@ index_open(Oid relationId)
 }
 
 /* ----------------
- *		index_openr - open a index relation by name
+ *		index_openr - open an index relation by name
  *
  *		As above, but lookup by name instead of OID.
  * ----------------
  */
 Relation
-index_openr(char *relationName)
+index_openr(const char *relationName)
 {
 	Relation	r;
 
-	r = RelationNameGetRelation(relationName);
-
-	if (!RelationIsValid(r))
-		elog(ERROR, "Index '%s' does not exist", relationName);
+	r = relation_openr(relationName, NoLock);
 
 	if (r->rd_rel->relkind != RELKIND_INDEX)
-		elog(ERROR, "%s is not an index relation", RelationGetRelationName(r));
+		elog(ERROR, "%s is not an index relation",
+			 RelationGetRelationName(r));
 
 	pgstat_initstats(&r->pgstat_info, r);
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 4e338b0eb21..b5c25516cd1 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.167 2001/10/25 20:37:30 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.168 2001/11/02 16:30:29 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1417,15 +1417,9 @@ UpdateStats(Oid relid, double reltuples)
 	 */
 
 	/*
-	 * Can't use heap_open here since we don't know if it's an index...
+	 * Grabbing lock here is probably redundant ...
 	 */
-	whichRel = RelationIdGetRelation(relid);
-
-	if (!RelationIsValid(whichRel))
-		elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
-
-	/* Grab lock to be held till end of xact (probably redundant...) */
-	LockRelation(whichRel, ShareLock);
+	whichRel = relation_open(relid, ShareLock);
 
 	/*
 	 * Find the RELATION relation tuple for the given relation.
@@ -1553,8 +1547,7 @@ UpdateStats(Oid relid, double reltuples)
 		heap_endscan(pg_class_scan);
 
 	heap_close(pg_class, RowExclusiveLock);
-	/* Cheating a little bit since we didn't open it with heap_open... */
-	heap_close(whichRel, NoLock);
+	relation_close(whichRel, NoLock);
 }
 
 
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index b9cfee96e4f..93c52e1b334 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.148 2001/10/31 04:49:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.149 2001/11/02 16:30:29 tgl Exp $
  *
  * NOTES
  *	  The PerformAddAttribute() code, like most of the relation
@@ -55,7 +55,6 @@
 
 static void drop_default(Oid relid, int16 attnum);
 static bool needs_toast_table(Relation rel);
-static bool is_relation(char *name);
 
 
 /* --------------------------------
@@ -554,9 +553,11 @@ AlterTableAlterColumnDefault(const char *relationName,
 #endif
 
 	rel = heap_openr(relationName, AccessExclusiveLock);
+
 	if (rel->rd_rel->relkind != RELKIND_RELATION)
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
 			 relationName);
+
 	myrelid = RelationGetRelid(rel);
 	heap_close(rel, NoLock);
 
@@ -721,9 +722,11 @@ AlterTableAlterColumnStatistics(const char *relationName,
 #endif
 
 	rel = heap_openr(relationName, AccessExclusiveLock);
+
 	if (rel->rd_rel->relkind != RELKIND_RELATION)
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
 			 relationName);
+
 	myrelid = RelationGetRelid(rel);
 	heap_close(rel, NoLock);	/* close rel, but keep lock! */
 
@@ -1192,12 +1195,16 @@ AlterTableAddConstraint(char *relationName,
 		elog(ERROR, "ALTER TABLE: permission denied");
 #endif
 
-	/* Disallow ADD CONSTRAINT on views, indexes, sequences, etc */
-	if (!is_relation(relationName))
-		elog(ERROR, "ALTER TABLE ADD CONSTRAINT: %s is not a table",
+	/*
+	 * Grab an exclusive lock on the target table, which we will NOT
+	 * release until end of transaction.
+	 */
+	rel = heap_openr(relationName, AccessExclusiveLock);
+
+	if (rel->rd_rel->relkind != RELKIND_RELATION)
+		elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
 			 relationName);
 
-	rel = heap_openr(relationName, AccessExclusiveLock);
 	myrelid = RelationGetRelid(rel);
 
 	if (inh)
@@ -1686,7 +1693,7 @@ AlterTableDropConstraint(const char *relationName,
 
 	/* Disallow DROP CONSTRAINT on views, indexes, sequences, etc */
 	if (rel->rd_rel->relkind != RELKIND_RELATION)
-		elog(ERROR, "ALTER TABLE / DROP CONSTRAINT: %s is not a table",
+		elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
 			 relationName);
 
 	/*
@@ -2053,7 +2060,6 @@ void
 LockTableCommand(LockStmt *lockstmt)
 {
 	List	   *p;
-	Relation	rel;
 
 	/*
 	 * Iterate over the list and open, lock, and close the relations one
@@ -2064,12 +2070,7 @@ LockTableCommand(LockStmt *lockstmt)
 	{
 		char	   *relname = strVal(lfirst(p));
 		int			aclresult;
-
-		rel = heap_openr(relname, NoLock);
-
-		if (rel->rd_rel->relkind != RELKIND_RELATION)
-			elog(ERROR, "LOCK TABLE: %s is not a table",
-				 relname);
+		Relation	rel;
 
 		if (lockstmt->mode == AccessShareLock)
 			aclresult = pg_aclcheck(relname, GetUserId(),
@@ -2081,21 +2082,13 @@ LockTableCommand(LockStmt *lockstmt)
 		if (aclresult != ACLCHECK_OK)
 			elog(ERROR, "LOCK TABLE: permission denied");
 
-		LockRelation(rel, lockstmt->mode);
-
-		heap_close(rel, NoLock);	/* close rel, keep lock */
-	}
-}
-
-
-static bool
-is_relation(char *name)
-{
-	Relation	rel = heap_openr(name, NoLock);
+		rel = relation_openr(relname, lockstmt->mode);
 
-	bool		retval = (rel->rd_rel->relkind == RELKIND_RELATION);
-
-	heap_close(rel, NoLock);
+		/* Currently, we only allow plain tables to be locked */
+		if (rel->rd_rel->relkind != RELKIND_RELATION)
+			elog(ERROR, "LOCK TABLE: %s is not a table",
+				 relname);
 
-	return retval;
+		relation_close(rel, NoLock);	/* close rel, keep lock */
+	}
 }
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 647cb55b7e7..baeff0c172d 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -7,7 +7,7 @@
  * Copyright (c) 1999-2001, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.34 2001/10/25 05:49:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.35 2001/11/02 16:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -336,16 +336,8 @@ CommentRelation(int reltype, char *relname, char *comment)
 	 * ensures no one else drops the relation before we commit.  (If they
 	 * did, they'd fail to remove the entry we are about to make in
 	 * pg_description.)
-	 *
-	 * heap_openr will complain if it's an index, so we must do this:
 	 */
-	if (reltype != INDEX)
-		relation = heap_openr(relname, AccessShareLock);
-	else
-	{
-		relation = index_openr(relname);
-		LockRelation(relation, AccessShareLock);
-	}
+	relation = relation_openr(relname, AccessShareLock);
 
 	/* Next, verify that the relation type matches the intent */
 
@@ -374,11 +366,7 @@ CommentRelation(int reltype, char *relname, char *comment)
 	CreateComments(RelationGetRelid(relation), RelOid_pg_class, 0, comment);
 
 	/* Done, but hold lock until commit */
-
-	if (reltype != INDEX)
-		heap_close(relation, NoLock);
-	else
-		index_close(relation);
+	relation_close(relation, NoLock);
 }
 
 /*------------------------------------------------------------------
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
index c65cfcc5519..42abe24f138 100644
--- a/src/backend/commands/rename.c
+++ b/src/backend/commands/rename.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.59 2001/10/25 05:49:25 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.60 2001/11/02 16:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -258,19 +258,10 @@ renamerel(const char *oldrelname, const char *newrelname)
 		return;					/* all done... */
 
 	/*
-	 * Instead of using heap_openr(), do it the hard way, so that we can
-	 * rename indexes as well as regular relations.
-	 */
-	targetrelation = RelationNameGetRelation(oldrelname);
-
-	if (!RelationIsValid(targetrelation))
-		elog(ERROR, "Relation \"%s\" does not exist", oldrelname);
-
-	/*
-	 * Grab an exclusive lock on the target table, which we will NOT
+	 * Grab an exclusive lock on the target table or index, which we will NOT
 	 * release until end of transaction.
 	 */
-	LockRelation(targetrelation, AccessExclusiveLock);
+	targetrelation = relation_openr(oldrelname, AccessExclusiveLock);
 
 	reloid = RelationGetRelid(targetrelation);
 	relkind = targetrelation->rd_rel->relkind;
@@ -278,7 +269,7 @@ renamerel(const char *oldrelname, const char *newrelname)
 	/*
 	 * Close rel, but keep exclusive lock!
 	 */
-	heap_close(targetrelation, NoLock);
+	relation_close(targetrelation, NoLock);
 
 	/*
 	 * Flush the relcache entry (easier than trying to change it at
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index f6d94e5c552..1f2887031e4 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.112 2001/10/25 05:49:39 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.113 2001/11/02 16:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -131,7 +131,6 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 	List	   *i = NIL;
 	Node	   *first_arg = NULL;
 	char	   *refname;
-	Relation	rd;
 	int			nargs = length(fargs);
 	int			argn;
 	Func	   *funcnode;
@@ -200,13 +199,10 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 			if (attisset)
 			{
 				toid = exprType(first_arg);
-				rd = heap_openr_nofail(typeidTypeName(toid));
-				if (RelationIsValid(rd))
-					heap_close(rd, NoLock);
-				else
+				argrelid = typeidTypeRelid(toid);
+				if (argrelid == InvalidOid)
 					elog(ERROR, "Type '%s' is not a relation type",
 						 typeidTypeName(toid));
-				argrelid = typeidTypeRelid(toid);
 
 				/*
 				 * A projection must match an attribute name of the rel.
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 3dc6deb0cb4..3a48b133bfe 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.96 2001/10/28 06:25:54 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.97 2001/11/02 16:30:29 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -292,12 +292,6 @@ InitPostgres(const char *dbname, const char *username)
 	 */
 	RelationCacheInitialize();
 
-	/*
-	 * Initialize the access methods. Does not touch files (?) - thomas
-	 * 1997-11-01
-	 */
-	initam();
-
 	/*
 	 * Initialize all the system catalog caches.
 	 *
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 88c1c06699b..dbef1a6cdad 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: genam.h,v 1.29 2001/10/28 06:25:59 momjian Exp $
+ * $Id: genam.h,v 1.30 2001/11/02 16:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@ typedef bool (*IndexBulkDeleteCallback) (ItemPointer itemptr, void *state);
  * ----------------
  */
 extern Relation index_open(Oid relationId);
-extern Relation index_openr(char *relationName);
+extern Relation index_openr(const char *relationName);
 extern void index_close(Relation relation);
 extern InsertIndexResult index_insert(Relation relation,
 			 Datum *datum, char *nulls,
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 61fa3afea56..b0124ed31cd 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -7,15 +7,13 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: heapam.h,v 1.70 2001/10/28 06:25:59 momjian Exp $
+ * $Id: heapam.h,v 1.71 2001/11/02 16:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef HEAPAM_H
 #define HEAPAM_H
 
-#include <time.h>
-
 #include "access/htup.h"
 #include "access/relscan.h"
 #include "access/tupmacs.h"
@@ -26,67 +24,11 @@
 #include "utils/tqual.h"
 
 /* ----------------------------------------------------------------
- *				heap access method statistics
+ *				leftover cruft from old statistics code
  * ----------------------------------------------------------------
  */
 
-typedef struct HeapAccessStatisticsData
-{
-	time_t		init_global_timestamp;	/* time global statistics started */
-	time_t		local_reset_timestamp;	/* last time local reset was done */
-	time_t		last_request_timestamp; /* last time stats were requested */
-
-	int			global_open;
-	int			global_openr;
-	int			global_close;
-	int			global_beginscan;
-	int			global_rescan;
-	int			global_endscan;
-	int			global_getnext;
-	int			global_fetch;
-	int			global_insert;
-	int			global_delete;
-	int			global_replace;
-	int			global_mark4update;
-	int			global_markpos;
-	int			global_restrpos;
-	int			global_BufferGetRelation;
-	int			global_RelationIdGetRelation;
-	int			global_RelationIdGetRelation_Buf;
-	int			global_RelationNameGetRelation;
-	int			global_getreldesc;
-	int			global_heapgettup;
-	int			global_RelationPutHeapTuple;
-	int			global_RelationPutLongHeapTuple;
-
-	int			local_open;
-	int			local_openr;
-	int			local_close;
-	int			local_beginscan;
-	int			local_rescan;
-	int			local_endscan;
-	int			local_getnext;
-	int			local_fetch;
-	int			local_insert;
-	int			local_delete;
-	int			local_replace;
-	int			local_mark4update;
-	int			local_markpos;
-	int			local_restrpos;
-	int			local_BufferGetRelation;
-	int			local_RelationIdGetRelation;
-	int			local_RelationIdGetRelation_Buf;
-	int			local_RelationNameGetRelation;
-	int			local_getreldesc;
-	int			local_heapgettup;
-	int			local_RelationPutHeapTuple;
-	int			local_RelationPutLongHeapTuple;
-} HeapAccessStatisticsData;
-
-typedef HeapAccessStatisticsData *HeapAccessStatistics;
-
-#define IncrHeapAccessStat(x) \
-	(heap_access_stats == NULL ? 0 : (heap_access_stats->x)++)
+#define IncrHeapAccessStat(x)	((void) 0)
 
 /* ----------------
  *		fastgetattr
@@ -180,7 +122,6 @@ extern Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
 
 extern Datum heap_getsysattr(HeapTuple tup, int attnum, bool *isnull);
 
-extern HeapAccessStatistics heap_access_stats;	/* in stats.c */
 
 /* ----------------
  *		function prototypes for heap access method
@@ -192,11 +133,14 @@ extern HeapAccessStatistics heap_access_stats;	/* in stats.c */
 
 /* heapam.c */
 
+extern Relation relation_open(Oid relationId, LOCKMODE lockmode);
+extern Relation relation_openr(const char *relationName, LOCKMODE lockmode);
+extern void relation_close(Relation relation, LOCKMODE lockmode);
+
 extern Relation heap_open(Oid relationId, LOCKMODE lockmode);
 extern Relation heap_openr(const char *relationName, LOCKMODE lockmode);
-extern Relation heap_open_nofail(Oid relationId);
-extern Relation heap_openr_nofail(const char *relationName);
-extern void heap_close(Relation relation, LOCKMODE lockmode);
+#define heap_close(r,l)  relation_close(r,l)
+
 extern HeapScanDesc heap_beginscan(Relation relation, int atend,
 			   Snapshot snapshot, unsigned nkeys, ScanKey key);
 extern void heap_rescan(HeapScanDesc scan, bool scanFromEnd, ScanKey key);
@@ -242,8 +186,4 @@ extern HeapTuple heap_modifytuple(HeapTuple tuple,
 extern void heap_freetuple(HeapTuple tuple);
 extern HeapTuple heap_addheader(int natts, Size structlen, void *structure);
 
-/* in common/heap/stats.c */
-extern void PrintHeapAccessStatistics(HeapAccessStatistics stats);
-extern void initam(void);
-
 #endif	 /* HEAPAM_H */
diff --git a/src/test/regress/expected/errors.out b/src/test/regress/expected/errors.out
index f652fb1eb05..8a4344fe1ec 100644
--- a/src/test/regress/expected/errors.out
+++ b/src/test/regress/expected/errors.out
@@ -43,7 +43,7 @@ delete from;
 ERROR:  parser: parse error at or near ";"
 -- no such relation 
 delete from nonesuch;
-ERROR:  Relation 'nonesuch' does not exist
+ERROR:  Relation "nonesuch" does not exist
 --
 -- DESTROY
  
@@ -78,7 +78,7 @@ ERROR:  renamerel: relation "stud_emp" exists
 -- attribute renaming 
 -- no such relation 
 alter table nonesuchrel rename column nonesuchatt to newnonesuchatt;
-ERROR:  Relation 'nonesuchrel' does not exist
+ERROR:  Relation "nonesuchrel" does not exist
 -- no such attribute 
 alter table emp rename column nonesuchatt to newnonesuchatt;
 ERROR:  renameatt: attribute "nonesuchatt" does not exist
diff --git a/src/test/regress/expected/temp.out b/src/test/regress/expected/temp.out
index 7d085de85bc..a3a583ec624 100644
--- a/src/test/regress/expected/temp.out
+++ b/src/test/regress/expected/temp.out
@@ -34,4 +34,4 @@ CREATE TEMP TABLE temptest(col int);
 -- test temp table deletion
 \c regression
 SELECT * FROM temptest;
-ERROR:  Relation 'temptest' does not exist
+ERROR:  Relation "temptest" does not exist
-- 
GitLab