From 9999f5a10e722c052006886b678995695001958a Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 12 Apr 2002 20:38:31 +0000
Subject: [PATCH] Checking to decide whether relations are system relations now
 depends on the namespace not the name; pg_ is not a reserved prefix for table
 names anymore.  From Fernando Nasser.

---
 src/backend/catalog/aclchk.c              |   7 +-
 src/backend/catalog/catalog.c             | 123 +++++++++++++++++-----
 src/backend/catalog/heap.c                |  13 ++-
 src/backend/catalog/index.c               |  11 +-
 src/backend/catalog/namespace.c           |   5 +-
 src/backend/commands/analyze.c            |   6 +-
 src/backend/commands/command.c            |  26 ++---
 src/backend/commands/creatinh.c           |   5 +-
 src/backend/commands/indexcmds.c          |  29 +++--
 src/backend/commands/rename.c             |  10 +-
 src/backend/commands/trigger.c            |   6 +-
 src/backend/commands/vacuum.c             |   4 +-
 src/backend/executor/execUtils.c          |   4 +-
 src/backend/optimizer/util/plancat.c      |   5 +-
 src/backend/tcop/utility.c                |  20 +---
 src/backend/utils/cache/inval.c           |  13 ++-
 src/backend/utils/cache/relcache.c        |   6 +-
 src/include/catalog/catalog.h             |  17 ++-
 src/test/regress/expected/alter_table.out |   3 +
 src/test/regress/expected/errors.out      |   3 -
 src/test/regress/sql/alter_table.sql      |   3 +
 src/test/regress/sql/errors.sql           |   3 -
 22 files changed, 197 insertions(+), 125 deletions(-)

diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index e440489a34a..5f223aab9d9 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.64 2002/04/11 19:59:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.65 2002/04/12 20:38:17 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -726,7 +726,6 @@ pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode)
 	int32		result;
 	bool		usesuper,
 				usecatupd;
-	char	   *relname;
 	HeapTuple	tuple;
 	Datum		aclDatum;
 	bool		isNull;
@@ -761,9 +760,9 @@ pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode)
 	 * pg_shadow.usecatupd is set.	(This is to let superusers protect
 	 * themselves from themselves.)
 	 */
-	relname = NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname);
 	if ((mode & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
-		!allowSystemTableMods && IsSystemRelationName(relname) &&
+		!allowSystemTableMods &&
+		IsSystemClass((Form_pg_class) GETSTRUCT(tuple)) &&
 		!usecatupd)
 	{
 #ifdef ACLDEBUG
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 2a6ddf11ff3..6e198772754 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -1,6 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * catalog.c
+ *		routines concerned with catalog naming conventions
  *
  *
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
@@ -8,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.44 2001/11/16 23:30:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.45 2002/04/12 20:38:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,9 +19,9 @@
 #include "access/transam.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
-#include "catalog/pg_type.h"
+#include "catalog/pg_namespace.h"
 #include "miscadmin.h"
-#include "utils/lsyscache.h"
+
 
 /*
  * relpath			- construct path to a relation's file
@@ -74,54 +75,121 @@ GetDatabasePath(Oid tblNode)
 
 
 /*
- * IsSystemRelationName
- *		True iff name is the name of a system catalog relation.
+ * IsSystemRelation
+ *		True iff the relation is a system catalog relation.
  *
- *		NB: TOAST relations are considered system relations by this test.
+ *		NB: TOAST relations are considered system relations by this test
+ *		for compatibility with the old IsSystemRelationName function.
  *		This is appropriate in many places but not all.  Where it's not,
- *		also check IsToastRelationName.
+ *		also check IsToastRelation.
  *
- *		We now make a new requirement where system catalog relns must begin
- *		with pg_ while user relns are forbidden to do so.  Make the test
- *		trivial and instantaneous.
+ *		We now just test if the relation is in the system catalog namespace;
+ *		so it's no longer necessary to forbid user relations from having
+ *		names starting with pg_.  Now only schema names have the pg_
+ *		distinction/requirement.
+ */
+bool
+IsSystemRelation(Relation relation)
+{
+	return	IsSystemNamespace(RelationGetNamespace(relation)) ||
+			IsToastNamespace(RelationGetNamespace(relation));
+}
+
+/*
+ * IsSystemClass
+ *		Like the above, but takes a Form_pg_class as argument.
+ *		Used when we do not want to open the relation and have to
+ *		search pg_class directly.
+ */
+bool
+IsSystemClass(Form_pg_class reltuple)
+{
+	Oid		relnamespace = reltuple->relnamespace;
+
+	return	IsSystemNamespace(relnamespace) ||
+			IsToastNamespace(relnamespace);
+}
+
+/*
+ * IsToastRelation
+ *		True iff relation is a TOAST support relation (or index).
+ */
+bool
+IsToastRelation(Relation relation)
+{
+	return IsToastNamespace(RelationGetNamespace(relation));
+}
+
+/*
+ * IsToastClass
+ *		Like the above, but takes a Form_pg_class as argument.
+ *		Used when we do not want to open the relation and have to
+ *		search pg_class directly.
+ */
+bool
+IsToastClass(Form_pg_class reltuple)
+{
+	Oid		relnamespace = reltuple->relnamespace;
+
+	return	IsToastNamespace(relnamespace);
+}
+
+/*
+ * IsSystemNamespace
+ *		True iff namespace is pg_catalog.
  *
- *		XXX this is way bogus. -- pma
+ * NOTE: the reason this isn't a macro is to avoid having to include
+ * catalog/pg_namespace.h in a lot of places.
  */
 bool
-IsSystemRelationName(const char *relname)
+IsSystemNamespace(Oid namespaceId)
 {
-	/* ugly coding for speed */
-	return (relname[0] == 'p' &&
-			relname[1] == 'g' &&
-			relname[2] == '_');
+	return namespaceId == PG_CATALOG_NAMESPACE;
+}
+
+/*
+ * IsToastNamespace
+ *		True iff namespace is pg_toast.
+ *
+ * NOTE: the reason this isn't a macro is to avoid having to include
+ * catalog/pg_namespace.h in a lot of places.
+ */
+bool
+IsToastNamespace(Oid namespaceId)
+{
+	return namespaceId == PG_TOAST_NAMESPACE;
 }
 
+
 /*
- * IsToastRelationName
- *		True iff name is the name of a TOAST support relation (or index).
+ * IsReservedName
+ *		True iff name starts with the pg_ prefix.
+ *
+ *		For some classes of objects, the prefix pg_ is reserved
+ *		for system objects only.
  */
 bool
-IsToastRelationName(const char *relname)
+IsReservedName(const char *name)
 {
-	return strncmp(relname, "pg_toast_", 9) == 0;
+	/* ugly coding for speed */
+	return (name[0] == 'p' &&
+			name[1] == 'g' &&
+			name[2] == '_');
 }
 
 /*
  * IsSharedSystemRelationName
  *		True iff name is the name of a shared system catalog relation.
+ *
+ *		Note: This function assumes that this is a system relation
+ *		in the first place.  If that is not known, check the namespace
+ *		(with IsSystemNamespace) before calling this function.
  */
 bool
 IsSharedSystemRelationName(const char *relname)
 {
 	int			i;
 
-	/*
-	 * Quick out: if it's not a system relation, it can't be a shared
-	 * system relation.
-	 */
-	if (!IsSystemRelationName(relname))
-		return FALSE;
-
 	i = 0;
 	while (SharedSystemRelationNames[i] != NULL)
 	{
@@ -132,6 +200,7 @@ IsSharedSystemRelationName(const char *relname)
 	return FALSE;
 }
 
+
 /*
  *		newoid			- returns a unique identifier across all catalogs.
  *
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 1d225cc082b..eb7487ae62d 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.195 2002/04/11 19:59:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.196 2002/04/12 20:38:18 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -38,7 +38,6 @@
 #include "catalog/indexing.h"
 #include "catalog/pg_attrdef.h"
 #include "catalog/pg_inherits.h"
-#include "catalog/pg_namespace.h"
 #include "catalog/pg_relcheck.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
@@ -224,10 +223,10 @@ heap_create(const char *relname,
 	 * sanity checks
 	 */
 	if (!allow_system_table_mods &&
-		IsSystemRelationName(relname) &&
+		(IsSystemNamespace(relnamespace) || IsToastNamespace(relnamespace)) &&
 		IsNormalProcessingMode())
-		elog(ERROR, "invalid relation name \"%s\"; "
-			 "the 'pg_' name prefix is reserved for system catalogs",
+		elog(ERROR, "invalid relation \"%s\"; "
+			 "system catalog modifications are currently disallowed",
 			 relname);
 
 	/*
@@ -237,7 +236,7 @@ heap_create(const char *relname,
 	 * have to take special care for those rels that should be nailed
 	 * in cache and/or are shared across databases.
 	 */
-	if (relnamespace == PG_CATALOG_NAMESPACE)
+	if (IsSystemNamespace(relnamespace))
 	{
 		if (strcmp(TypeRelationName, relname) == 0)
 		{
@@ -1193,7 +1192,7 @@ heap_drop_with_catalog(Oid rid,
 	 * prevent deletion of system relations
 	 */
 	if (!allow_system_table_mods &&
-		IsSystemRelationName(RelationGetRelationName(rel)))
+		IsSystemRelation(rel))
 		elog(ERROR, "System relation \"%s\" may not be dropped",
 			 RelationGetRelationName(rel));
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index f8a1e5d4b20..d563d654183 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.175 2002/03/31 06:26:29 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.176 2002/04/12 20:38:19 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -33,7 +33,6 @@
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_index.h"
-#include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
@@ -320,7 +319,7 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
 	indexRelation->rd_rel->relowner = GetUserId();
 	indexRelation->rd_rel->relam = amoid;
 	indexRelation->rd_rel->relisshared =
-		(RelationGetNamespace(indexRelation) == PG_CATALOG_NAMESPACE) &&
+		IsSystemNamespace(RelationGetNamespace(indexRelation)) &&
 		IsSharedSystemRelationName(RelationGetRelationName(indexRelation));
 	indexRelation->rd_rel->relkind = RELKIND_INDEX;
 	indexRelation->rd_rel->relhasoids = false;
@@ -582,7 +581,7 @@ index_create(Oid heapRelationId,
 		elog(ERROR, "must index at least one column");
 
 	if (!allow_system_table_mods &&
-		IsSystemRelationName(RelationGetRelationName(heapRelation)) &&
+		IsSystemRelation(heapRelation) &&
 		IsNormalProcessingMode())
 		elog(ERROR, "User-defined indexes on system catalogs are not supported");
 
@@ -1221,7 +1220,7 @@ setNewRelfilenode(Relation relation)
 	Buffer		buffer;
 	RelationData workrel;
 
-	Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);
+	Assert(!IsSystemRelation(relation) || relation->rd_rel->relkind == RELKIND_INDEX);
 
 	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 	/* Fetch and lock the classTuple associated with this relation */
@@ -1912,7 +1911,7 @@ reindex_relation(Oid relid, bool force)
 	 * ignore the indexes of the target system relation while processing
 	 * reindex.
 	 */
-	if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
+	if (!IsIgnoringSystemIndexes() && IsSystemRelation(rel))
 		deactivate_needed = true;
 #ifndef ENABLE_REINDEX_NAILED_RELATIONS
 
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 6880dbe19e3..84bd95e4662 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.7 2002/04/09 20:35:47 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.8 2002/04/12 20:38:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 
 #include "access/heapam.h"
 #include "access/xact.h"
+#include "catalog/catalog.h"
 #include "catalog/catname.h"
 #include "catalog/heap.h"
 #include "catalog/namespace.h"
@@ -391,7 +392,7 @@ FuncnameGetCandidates(List *names, int nargs)
 		{
 			/* Consider only procs that are in the search path */
 			if (pathContainsSystemNamespace ||
-				procform->pronamespace != PG_CATALOG_NAMESPACE)
+				!IsSystemNamespace(procform->pronamespace))
 			{
 				List	   *nsp;
 
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ea778de3360..e36f21273d5 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.30 2002/04/02 01:03:05 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.31 2002/04/12 20:38:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,9 +18,9 @@
 
 #include "access/heapam.h"
 #include "access/tuptoaster.h"
+#include "catalog/catalog.h"
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
-#include "catalog/pg_namespace.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
@@ -218,7 +218,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 	/*
 	 * We can ANALYZE any table except pg_statistic. See update_attstats
 	 */
-	if (RelationGetNamespace(onerel) == PG_CATALOG_NAMESPACE &&
+	if (IsSystemNamespace(RelationGetNamespace(onerel)) &&
 		strcmp(RelationGetRelationName(onerel), StatisticRelationName) == 0)
 	{
 		relation_close(onerel, AccessShareLock);
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index c74d24cf7a5..c13b2aa67d4 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.173 2002/04/11 23:20:04 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.174 2002/04/12 20:38:20 tgl Exp $
  *
  * NOTES
  *	  The PerformAddAttribute() code, like most of the relation
@@ -346,7 +346,7 @@ AlterTableAddColumn(Oid myrelid,
 	 * normally, only the owner of a class can change its schema.
 	 */
 	if (!allowSystemTableMods
-		&& IsSystemRelationName(RelationGetRelationName(rel)))
+		&& IsSystemRelation(rel))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
 			 RelationGetRelationName(rel));
 	if (!pg_class_ownercheck(myrelid, GetUserId()))
@@ -548,7 +548,7 @@ AlterTableAlterColumnDropNotNull(Oid myrelid,
 			 RelationGetRelationName(rel));
 
 	if (!allowSystemTableMods
-		&& IsSystemRelationName(RelationGetRelationName(rel)))
+		&& IsSystemRelation(rel))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
 			 RelationGetRelationName(rel));
 
@@ -699,7 +699,7 @@ AlterTableAlterColumnSetNotNull(Oid myrelid,
 			 RelationGetRelationName(rel));
 
 	if (!allowSystemTableMods
-		&& IsSystemRelationName(RelationGetRelationName(rel)))
+		&& IsSystemRelation(rel))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
 			 RelationGetRelationName(rel));
 
@@ -829,7 +829,7 @@ AlterTableAlterColumnDefault(Oid myrelid,
 			 RelationGetRelationName(rel));
 
 	if (!allowSystemTableMods
-		&& IsSystemRelationName(RelationGetRelationName(rel)))
+		&& IsSystemRelation(rel))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
 			 RelationGetRelationName(rel));
 
@@ -970,8 +970,8 @@ drop_default(Oid relid, int16 attnum)
  */
 void
 AlterTableAlterColumnFlags(Oid myrelid,
-								bool inh, const char *colName,
-								Node *flagValue, const char *flagType)
+						   bool inh, const char *colName,
+						   Node *flagValue, const char *flagType)
 {
 	Relation	rel;
 	int			newtarget = 1;
@@ -989,9 +989,7 @@ AlterTableAlterColumnFlags(Oid myrelid,
 	/*
 	 * we allow statistics case for system tables
 	 */
-	if (*flagType != 'S' &&
-		!allowSystemTableMods
-		&& IsSystemRelationName(RelationGetRelationName(rel)))
+	if (*flagType != 'S' && !allowSystemTableMods && IsSystemRelation(rel))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
 			 RelationGetRelationName(rel));
 
@@ -1150,7 +1148,7 @@ AlterTableAddConstraint(Oid myrelid,
 			 RelationGetRelationName(rel));
 
 	if (!allowSystemTableMods
-		&& IsSystemRelationName(RelationGetRelationName(rel)))
+		&& IsSystemRelation(rel))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
 			 RelationGetRelationName(rel));
 
@@ -1476,7 +1474,7 @@ AlterTableDropConstraint(Oid myrelid,
 			 RelationGetRelationName(rel));
 
 	if (!allowSystemTableMods
-		&& IsSystemRelationName(RelationGetRelationName(rel)))
+		&& IsSystemRelation(rel))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
 			 RelationGetRelationName(rel));
 
@@ -1952,6 +1950,10 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 				 owner_name, authId);
 	}
 
+	if (!allowSystemTableMods && IsReservedName(schemaName))
+		elog(ERROR, "CREATE SCHEMA: Illegal schema name: \"%s\" -- pg_ is reserved for system schemas",
+			 schemaName);
+
 	/* Create the schema's namespace */
 	NamespaceCreate(schemaName, owner_userid);
 
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
index 4a76e0c11ec..6a0cf811473 100644
--- a/src/backend/commands/creatinh.c
+++ b/src/backend/commands/creatinh.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.95 2002/03/31 06:26:30 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.96 2002/04/12 20:38:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,7 +22,6 @@
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_inherits.h"
-#include "catalog/pg_namespace.h"
 #include "catalog/pg_type.h"
 #include "commands/creatinh.h"
 #include "miscadmin.h"
@@ -275,7 +274,7 @@ TruncateRelation(const RangeVar *relation)
 		elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
 			 RelationGetRelationName(rel));
 
-	if (!allowSystemTableMods && IsSystemRelationName(RelationGetRelationName(rel)))
+	if (!allowSystemTableMods && IsSystemRelation(rel))
 		elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
 			 RelationGetRelationName(rel));
 
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 0a8ddc1807c..297d5e72663 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.69 2002/04/11 19:59:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.70 2002/04/12 20:38:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -104,13 +104,13 @@ DefineIndex(RangeVar *heapRelation,
 
 	relationId = RelationGetRelid(rel);
 
-	heap_close(rel, NoLock);
-
 	if (!IsBootstrapProcessingMode() &&
-		IsSystemRelationName(heapRelation->relname) &&
+		IsSystemRelation(rel) &&
 		!IndexesAreActive(relationId, false))
 		elog(ERROR, "Existing indexes are inactive. REINDEX first");
 
+	heap_close(rel, NoLock);
+
 	/*
 	 * look up the access method, verify it can handle the requested
 	 * features
@@ -560,6 +560,16 @@ ReindexIndex(RangeVar *indexRelation, bool force /* currently unused */ )
 			 indexRelation->relname,
 			 ((Form_pg_class) GETSTRUCT(tuple))->relkind);
 
+	if (IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
+	{
+		if (!allowSystemTableMods)
+			elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -O -P options",
+				 indexRelation->relname);
+		if (!IsIgnoringSystemIndexes())
+			elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -P -O options",
+				 indexRelation->relname);
+	}
+
 	ReleaseSysCache(tuple);
 
 	if (IsIgnoringSystemIndexes())
@@ -611,10 +621,6 @@ ReindexTable(RangeVar *relation, bool force)
 /*
  * ReindexDatabase
  *		Recreate indexes of a database.
- *
- * Exceptions:
- *		"ERROR" if table nonexistent.
- *		...
  */
 void
 ReindexDatabase(const char *dbname, bool force, bool all)
@@ -638,6 +644,11 @@ ReindexDatabase(const char *dbname, bool force, bool all)
 	if (!(superuser() || is_dbadmin(MyDatabaseId)))
 		elog(ERROR, "REINDEX DATABASE: Permission denied.");
 
+	if (!allowSystemTableMods)
+		elog(ERROR, "must be called under standalone postgres with -O -P options");
+	if (!IsIgnoringSystemIndexes())
+		elog(ERROR, "must be called under standalone postgres with -P -O options");
+
 	/*
 	 * We cannot run inside a user transaction block; if we were inside a
 	 * transaction, then our commit- and start-transaction-command calls
@@ -668,7 +679,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
 	{
 		if (!all)
 		{
-			if (!IsSystemRelationName(NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname)))
+			if (!IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
 				continue;
 		}
 		if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
index 5760cbe3004..21db59b7f6b 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.69 2002/04/05 11:58:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.70 2002/04/12 20:38:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,7 +92,7 @@ renameatt(Oid relid,
 	 * normally, only the owner of a class can change its schema.
 	 */
 	if (!allowSystemTableMods 
-		&& IsSystemRelationName(RelationGetRelationName(targetrelation)))
+		&& IsSystemRelation(targetrelation))
 		elog(ERROR, "renameatt: class \"%s\" is a system catalog",
 			 RelationGetRelationName(targetrelation));
 	if (!pg_class_ownercheck(relid, GetUserId()))
@@ -276,14 +276,10 @@ renamerel(Oid relid, const char *newrelname)
 
 	/* Validity checks */
 	if (!allowSystemTableMods &&
-		IsSystemRelationName(RelationGetRelationName(targetrelation)))
+		IsSystemRelation(targetrelation))
 		elog(ERROR, "renamerel: system relation \"%s\" may not be renamed",
 			 RelationGetRelationName(targetrelation));
 
-	if (!allowSystemTableMods && IsSystemRelationName(newrelname))
-		elog(ERROR, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
-			 newrelname);
-
 	relkind = targetrelation->rd_rel->relkind;
 	relhastriggers = (targetrelation->rd_rel->reltriggers > 0);
 
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 72f13d3db49..891b9f3cfba 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.112 2002/04/09 20:35:48 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.113 2002/04/12 20:38:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -80,7 +80,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 		elog(ERROR, "CreateTrigger: relation \"%s\" is not a table",
 			 stmt->relation->relname);
 
-	if (!allowSystemTableMods && IsSystemRelationName(stmt->relation->relname))
+	if (!allowSystemTableMods && IsSystemRelation(rel))
 		elog(ERROR, "CreateTrigger: can't create trigger for system relation %s",
 			stmt->relation->relname);
 
@@ -326,7 +326,7 @@ DropTrigger(Oid relid, const char *trigname)
 		elog(ERROR, "DropTrigger: relation \"%s\" is not a table",
 			 RelationGetRelationName(rel));
 
-	if (!allowSystemTableMods && IsSystemRelationName(RelationGetRelationName(rel)))
+	if (!allowSystemTableMods && IsSystemRelation(rel))
 		elog(ERROR, "DropTrigger: can't drop trigger for system relation %s",
 			 RelationGetRelationName(rel));
 
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index ed3effab651..20a366d02ab 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.222 2002/04/02 05:11:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.223 2002/04/12 20:38:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -806,7 +806,7 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
 	bool		reindex = false;
 
 	if (IsIgnoringSystemIndexes() &&
-		IsSystemRelationName(RelationGetRelationName(onerel)))
+		IsSystemRelation(onerel))
 		reindex = true;
 
 	vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 5b071948779..9b03401e444 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.79 2002/02/19 20:11:13 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.80 2002/04/12 20:38:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -467,7 +467,7 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
 	if (!RelationGetForm(resultRelation)->relhasindex)
 		return;
 	if (IsIgnoringSystemIndexes() &&
-		IsSystemRelationName(RelationGetRelationName(resultRelation)))
+		IsSystemRelation(resultRelation))
 		return;
 
 	/*
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 447b3e61f2b..6ae9e1b7e90 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.70 2002/02/19 20:11:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.71 2002/04/12 20:38:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,8 +58,7 @@ get_relation_info(Oid relationObjectId,
 			 relationObjectId);
 	relation = (Form_pg_class) GETSTRUCT(relationTuple);
 
-	if (IsIgnoringSystemIndexes() &&
-		IsSystemRelationName(NameStr(relation->relname)))
+	if (IsIgnoringSystemIndexes() && IsSystemClass(relation))
 		*hasindex = false;
 	else
 		*hasindex = relation->relhasindex;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 7e2be17edea..77dfe4a2365 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.147 2002/04/12 09:17:10 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.148 2002/04/12 20:38:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -127,7 +127,7 @@ CheckDropPermissions(RangeVar *rel, char rightkind)
 		elog(ERROR, "you do not own %s \"%s\"",
 			 rentry->name, rel->relname);
 
-	if (!allowSystemTableMods && IsSystemRelationName(rel->relname))
+	if (!allowSystemTableMods && IsSystemClass(classform))
 		elog(ERROR, "%s \"%s\" is a system %s",
 			 rentry->name, rel->relname, rentry->name);
 
@@ -153,7 +153,8 @@ CheckOwnership(RangeVar *rel, bool noCatalogs)
 
 	if (noCatalogs)
 	{
-		if (!allowSystemTableMods && IsSystemRelationName(rel->relname))
+		if (!allowSystemTableMods &&
+			IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
 			elog(ERROR, "relation \"%s\" is a system catalog",
 				 rel->relname);
 	}
@@ -791,15 +792,6 @@ ProcessUtility(Node *parsetree,
 				{
 					case INDEX:
 						relname = (char *) stmt->relation->relname;
-						if (IsSystemRelationName(relname))
-						{
-							if (!allowSystemTableMods)
-								elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -O -P options",
-									 relname);
-							if (!IsIgnoringSystemIndexes())
-								elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -P -O options",
-									 relname);
-						}
 						CheckOwnership(stmt->relation, false);
 						ReindexIndex(stmt->relation, stmt->force);
 						break;
@@ -809,10 +801,6 @@ ProcessUtility(Node *parsetree,
 						break;
 					case DATABASE:
 						relname = (char *) stmt->name;
-						if (!allowSystemTableMods)
-							elog(ERROR, "must be called under standalone postgres with -O -P options");
-						if (!IsIgnoringSystemIndexes())
-							elog(ERROR, "must be called under standalone postgres with -P -O options");
 						ReindexDatabase(relname, stmt->force, false);
 						break;
 				}
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index 6d397a7ba98..483c06bd6ac 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -74,7 +74,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.49 2002/03/03 17:47:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.50 2002/04/12 20:38:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -456,12 +456,15 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
 	 * We only need to worry about invalidation for tuples that are in
 	 * system relations; user-relation tuples are never in catcaches and
 	 * can't affect the relcache either.
-	 *
-	 * TOAST tuples can likewise be ignored here.
 	 */
-	if (!IsSystemRelationName(NameStr(RelationGetForm(relation)->relname)))
+	if (!IsSystemRelation(relation))
 		return;
-	if (IsToastRelationName(NameStr(RelationGetForm(relation)->relname)))
+	/* 
+	 * TOAST tuples can likewise be ignored here.
+	 * Note that TOAST tables are considered system relations
+	 * so they are not filtered by the above test.
+	 */
+	if (IsToastRelation(relation))
 		return;
 
 	/*
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index fcdffa9132e..9a8e76f4926 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.159 2002/03/31 06:26:31 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.160 2002/04/12 20:38:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -183,7 +183,7 @@ do { \
 		elog(ERROR, "out of memory for relation descriptor cache"); \
 	/* used to give notice if found -- now just keep quiet */ \
 	nodentry->reldesc = RELATION; \
-	if (RelationGetNamespace(RELATION) == PG_CATALOG_NAMESPACE) \
+	if (IsSystemNamespace(RelationGetNamespace(RELATION))) \
 	{ \
 		char *relname = RelationGetRelationName(RELATION); \
 		RelNameCacheEnt *namehentry; \
@@ -244,7 +244,7 @@ do { \
 										   HASH_REMOVE, NULL); \
 	if (nodentry == NULL) \
 		elog(WARNING, "trying to delete a reldesc that does not exist."); \
-	if (RelationGetNamespace(RELATION) == PG_CATALOG_NAMESPACE) \
+	if (IsSystemNamespace(RelationGetNamespace(RELATION))) \
 	{ \
 		char *relname = RelationGetRelationName(RELATION); \
 		RelNameCacheEnt *namehentry; \
diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h
index 62cc5736f7f..255bb265c4c 100644
--- a/src/include/catalog/catalog.h
+++ b/src/include/catalog/catalog.h
@@ -7,22 +7,29 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catalog.h,v 1.22 2002/03/22 21:34:44 tgl Exp $
+ * $Id: catalog.h,v 1.23 2002/04/12 20:38:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef CATALOG_H
 #define CATALOG_H
 
-#include "access/tupdesc.h"
+#include "utils/rel.h"
 
-#include "storage/relfilenode.h"
 
 extern char *relpath(RelFileNode rnode);
 extern char *GetDatabasePath(Oid tblNode);
 
-extern bool IsSystemRelationName(const char *relname);
-extern bool IsToastRelationName(const char *relname);
+extern bool IsSystemRelation(Relation relation);
+extern bool IsToastRelation(Relation relation);
+
+extern bool IsSystemClass(Form_pg_class reltuple);
+extern bool IsToastClass(Form_pg_class reltuple);
+
+extern bool IsSystemNamespace(Oid namespaceId);
+extern bool IsToastNamespace(Oid namespaceId);
+
+extern bool IsReservedName(const char *name);
 extern bool IsSharedSystemRelationName(const char *relname);
 
 extern Oid	newoid(void);
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index cbf0680a42f..95821b513d2 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -296,6 +296,9 @@ SELECT * FROM foo_seq_new;
 (1 row)
 
 DROP SEQUENCE foo_seq_new;
+-- toast-like relation name
+alter table stud_emp rename to pg_toast_stud_emp;
+alter table pg_toast_stud_emp rename to stud_emp;
 -- FOREIGN KEY CONSTRAINT adding TEST
 CREATE TABLE tmp2 (a int primary key);
 NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 'tmp2_pkey' for table 'tmp2'
diff --git a/src/test/regress/expected/errors.out b/src/test/regress/expected/errors.out
index 56c8939c6f0..cdd4218d99e 100644
--- a/src/test/regress/expected/errors.out
+++ b/src/test/regress/expected/errors.out
@@ -66,9 +66,6 @@ ERROR:  Relation "nonesuch" does not exist
 -- no such relation 
 alter table nonesuch rename to stud_emp;
 ERROR:  Relation "nonesuch" does not exist
--- system relation 
-alter table stud_emp rename to pg_stud_emp;
-ERROR:  renamerel: Illegal class name: "pg_stud_emp" -- pg_ is reserved for system catalogs
 -- conflict 
 alter table stud_emp rename to aggtest;
 ERROR:  renamerel: relation "aggtest" exists
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 477f4696b56..2931e8ea188 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -178,6 +178,9 @@ CREATE SEQUENCE foo_seq;
 ALTER TABLE foo_seq RENAME TO foo_seq_new;
 SELECT * FROM foo_seq_new;
 DROP SEQUENCE foo_seq_new;
+-- toast-like relation name
+alter table stud_emp rename to pg_toast_stud_emp;
+alter table pg_toast_stud_emp rename to stud_emp;
 
 -- FOREIGN KEY CONSTRAINT adding TEST
 
diff --git a/src/test/regress/sql/errors.sql b/src/test/regress/sql/errors.sql
index 949f6405998..5ab09d2a123 100644
--- a/src/test/regress/sql/errors.sql
+++ b/src/test/regress/sql/errors.sql
@@ -77,9 +77,6 @@ alter table nonesuch rename to newnonesuch;
 -- no such relation 
 alter table nonesuch rename to stud_emp;
 
--- system relation 
-alter table stud_emp rename to pg_stud_emp;
-
 -- conflict 
 alter table stud_emp rename to aggtest;
 
-- 
GitLab