From 11333426f103bedef311d1dd88b62176276b8544 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 18 Jul 2002 16:47:26 +0000
Subject: [PATCH] Implement DROP SCHEMA.  It lacks support for dropping
 conversions and operator classes, both of which are schema-local and so
 should really be droppable.

---
 doc/src/sgml/ref/allfiles.sgml    |   3 +-
 doc/src/sgml/ref/drop_schema.sgml | 184 ++++++++++++++++++++++++++++++
 doc/src/sgml/reference.sgml       |   3 +-
 src/backend/catalog/dependency.c  |  31 ++++-
 src/backend/catalog/heap.c        |  21 +++-
 src/backend/catalog/index.c       |   5 +-
 src/backend/catalog/pg_operator.c |  13 ++-
 src/backend/catalog/pg_proc.c     |   8 +-
 src/backend/catalog/pg_type.c     | 133 +++++++++++----------
 src/backend/commands/schemacmds.c |  75 +++++++++++-
 src/backend/parser/gram.y         |  24 +---
 src/backend/tcop/postgres.c       |   9 +-
 src/backend/tcop/utility.c        |  21 ++--
 src/bin/initdb/initdb.sh          |   5 +-
 src/include/commands/schemacmds.h |   5 +-
 src/include/nodes/parsenodes.h    |   5 +-
 16 files changed, 438 insertions(+), 107 deletions(-)
 create mode 100644 doc/src/sgml/ref/drop_schema.sgml

diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index c039f661b0c..c9ece5af561 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.39 2002/04/25 21:47:07 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.40 2002/07/18 16:47:22 tgl Exp $
 PostgreSQL documentation
 Complete list of usable sgml source files in this directory.
 -->
@@ -79,6 +79,7 @@ Complete list of usable sgml source files in this directory.
 <!entity dropLanguage       system "drop_language.sgml">
 <!entity dropOperator       system "drop_operator.sgml">
 <!entity dropRule           system "drop_rule.sgml">
+<!entity dropSchema         system "drop_schema.sgml">
 <!entity dropSequence       system "drop_sequence.sgml">
 <!entity dropTable          system "drop_table.sgml">
 <!entity dropTrigger        system "drop_trigger.sgml">
diff --git a/doc/src/sgml/ref/drop_schema.sgml b/doc/src/sgml/ref/drop_schema.sgml
new file mode 100644
index 00000000000..8c69893ae2f
--- /dev/null
+++ b/doc/src/sgml/ref/drop_schema.sgml
@@ -0,0 +1,184 @@
+<!--
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_schema.sgml,v 1.1 2002/07/18 16:47:22 tgl Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-DROPSCHEMA">
+ <refmeta>
+  <refentrytitle id="SQL-DROPSCHEMA-TITLE">DROP SCHEMA</refentrytitle>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+  <refname>
+   DROP SCHEMA
+  </refname>
+  <refpurpose>
+   remove a schema
+  </refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+  <refsynopsisdivinfo>
+   <date>2002-07-18</date>
+  </refsynopsisdivinfo>
+  <synopsis>
+DROP SCHEMA <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ]
+
+  </synopsis>
+  
+  <refsect2 id="R2-SQL-DROPSCHEMA-1">
+   <refsect2info>
+    <date>2002-07-18</date>
+   </refsect2info>
+   <title>
+    Inputs
+   </title>
+   <para>
+    <variablelist>
+     <varlistentry>
+      <term><replaceable class="PARAMETER">name</replaceable></term>
+      <listitem>
+       <para>
+	The name of a schema.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects (tables, functions, etc) that are contained
+	in the schema.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the schema if it contains any objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+  </refsect2>
+
+  <refsect2 id="R2-SQL-DROPSCHEMA-2">
+   <refsect2info>
+    <date>2002-07-18</date>
+   </refsect2info>
+   <title>
+    Outputs
+   </title>
+   <para>
+
+    <variablelist>
+     <varlistentry>
+      <term><computeroutput>
+DROP SCHEMA
+       </computeroutput></term>
+      <listitem>
+       <para>
+	The message returned if the schema is successfully dropped.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><computeroutput>
+ERROR: Schema "<replaceable class="parameter">name</replaceable>" does not exist
+       </computeroutput></term>
+      <listitem>
+       <para>
+	This message occurs if the specified schema does not exist.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+
+   </para>
+  </refsect2>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-SQL-DROPSCHEMA-1">
+  <refsect1info>
+   <date>2002-07-18</date>
+  </refsect1info>
+  <title>
+   Description
+  </title>
+  <para>
+   <command>DROP SCHEMA</command> removes schemas from the data base.
+  </para>
+
+  <para>
+   A schema can only be dropped by its owner or a superuser.  Note that
+   the owner can drop the schema (and thereby all contained objects)
+   even if he does not own some of the objects within the schema.
+  </para>
+
+  <refsect2 id="R2-SQL-DROPSCHEMA-3">
+   <refsect2info>
+    <date>2002-07-18</date>
+   </refsect2info>
+   <title>
+    Notes
+   </title>
+   <para>
+    Refer to the <command>CREATE SCHEMA</command> statement for
+    information on how to create a schema.
+   </para>
+  </refsect2>
+ </refsect1>
+
+ <refsect1 id="R1-SQL-DROPSCHEMA-2">
+  <title>
+   Usage
+  </title>
+  <para>
+   To remove schema <literal>mystuff</literal> from the database,
+   along with everything it contains:
+
+   <programlisting>
+DROP SCHEMA mystuff CASCADE;
+   </programlisting>
+  </para>
+ </refsect1>
+ 
+ <refsect1 id="R1-SQL-DROPSCHEMA-3">
+  <title>
+   Compatibility
+  </title>
+  
+  <refsect2 id="R2-SQL-DROPSCHEMA-4">
+   <refsect2info>
+    <date>2002-07-18</date>
+   </refsect2info>
+   <title>
+    SQL92
+   </title>
+   <para>
+    <command>DROP SCHEMA</command> is fully compatible with
+    <acronym>SQL92</acronym>, except that the standard only allows
+    one schema to be dropped per command.
+   </para>
+  </refsect2>
+ </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:nil
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:"../reference.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:"/usr/lib/sgml/catalog"
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index d1d40f3a72b..8249039826c 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -1,5 +1,5 @@
 <!-- reference.sgml
-$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.28 2002/04/25 21:47:06 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.29 2002/07/18 16:47:22 tgl Exp $
 
 PostgreSQL Reference Manual
 -->
@@ -88,6 +88,7 @@ PostgreSQL Reference Manual
    &dropLanguage;
    &dropOperator;
    &dropRule;
+   &dropSchema;
    &dropSequence;
    &dropTable;
    &dropTrigger;
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 527cca3a85b..d2dc8b3795a 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.3 2002/07/16 05:53:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.4 2002/07/18 16:47:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,12 +25,14 @@
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_depend.h"
 #include "catalog/pg_language.h"
+#include "catalog/pg_namespace.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
 #include "commands/comment.h"
 #include "commands/defrem.h"
 #include "commands/proclang.h"
+#include "commands/schemacmds.h"
 #include "commands/trigger.h"
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
@@ -54,6 +56,7 @@ typedef enum ObjectClasses
 	OCLASS_OPERATOR,			/* pg_operator */
 	OCLASS_REWRITE,				/* pg_rewrite */
 	OCLASS_TRIGGER,				/* pg_trigger */
+	OCLASS_SCHEMA,				/* pg_namespace */
 	MAX_OCLASS					/* MUST BE LAST */
 } ObjectClasses;
 
@@ -597,6 +600,10 @@ doDeletion(const ObjectAddress *object)
 			RemoveTriggerById(object->objectId);
 			break;
 
+		case OCLASS_SCHEMA:
+			RemoveSchemaById(object->objectId);
+			break;
+
 		default:
 			elog(ERROR, "doDeletion: Unsupported object class %u",
 				 object->classId);
@@ -981,6 +988,7 @@ init_object_classes(void)
 	object_classes[OCLASS_OPERATOR] = get_system_catalog_relid(OperatorRelationName);
 	object_classes[OCLASS_REWRITE] = get_system_catalog_relid(RewriteRelationName);
 	object_classes[OCLASS_TRIGGER] = get_system_catalog_relid(TriggerRelationName);
+	object_classes[OCLASS_SCHEMA] = get_system_catalog_relid(NamespaceRelationName);
 	object_classes_initialized = true;
 }
 
@@ -1045,6 +1053,11 @@ getObjectClass(const ObjectAddress *object)
 		Assert(object->objectSubId == 0);
 		return OCLASS_TRIGGER;
 	}
+	if (object->classId == object_classes[OCLASS_SCHEMA])
+	{
+		Assert(object->objectSubId == 0);
+		return OCLASS_SCHEMA;
+	}
 
 	elog(ERROR, "getObjectClass: Unknown object class %u",
 		 object->classId);
@@ -1265,6 +1278,22 @@ getObjectDescription(const ObjectAddress *object)
 			break;
 		}
 
+		case OCLASS_SCHEMA:
+		{
+			HeapTuple		schemaTup;
+
+			schemaTup = SearchSysCache(NAMESPACEOID,
+									   ObjectIdGetDatum(object->objectId),
+									   0, 0, 0);
+			if (!HeapTupleIsValid(schemaTup))
+				elog(ERROR, "getObjectDescription: Schema %u does not exist",
+					 object->objectId);
+			appendStringInfo(&buffer, "schema %s",
+							 NameStr(((Form_pg_namespace) GETSTRUCT(schemaTup))->nspname));
+			ReleaseSysCache(schemaTup);
+			break;
+		}
+
 		default:
 			appendStringInfo(&buffer, "unknown object %u %u %d",
 							 object->classId,
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 51933d32ede..076e1e0462b 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.209 2002/07/16 22:12:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.210 2002/07/18 16:47:22 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -742,6 +742,25 @@ heap_create_with_catalog(const char *relname,
 	AddNewAttributeTuples(new_rel_oid, new_rel_desc->rd_att,
 						  relhasoids, relkind);
 
+	/*
+	 * make a dependency link to force the relation to be deleted if
+	 * its namespace is.  Skip this in bootstrap mode, since we don't
+	 * make dependencies while bootstrapping.
+	 */
+	if (!IsBootstrapProcessingMode())
+	{
+		ObjectAddress	myself,
+						referenced;
+
+		myself.classId = RelOid_pg_class;
+		myself.objectId = new_rel_oid;
+		myself.objectSubId = 0;
+		referenced.classId = get_system_catalog_relid(NamespaceRelationName);
+		referenced.objectId = relnamespace;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
+
 	/*
 	 * store constraints and defaults passed in the tupdesc, if any.
 	 *
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index c827edfb3e5..92d4d361a5b 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.184 2002/07/16 05:53:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.185 2002/07/18 16:47:23 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -670,6 +670,9 @@ index_create(Oid heapRelationId,
 	 * linked to the table.  If it's not a CONSTRAINT, make the dependency
 	 * directly on the table.
 	 *
+	 * We don't need a dependency on the namespace, because there'll be
+	 * an indirect dependency via our parent table.
+	 *
 	 * During bootstrap we can't register any dependencies, and we don't
 	 * try to make a constraint either.
 	 */
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 09c3f6be76f..a2a591f1e62 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.71 2002/07/16 22:12:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.72 2002/07/18 16:47:23 tgl Exp $
  *
  * NOTES
  *	  these routines moved here from commands/define.c and somewhat cleaned up.
@@ -907,7 +907,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
  * Create dependencies for a new operator (either a freshly inserted
  * complete operator, a new shell operator, or a just-updated shell).
  *
- * NB: the OidIsValid tests in this routine are *all* necessary, in case
+ * NB: the OidIsValid tests in this routine are necessary, in case
  * the given operator is a shell.
  */
 static void
@@ -924,6 +924,15 @@ makeOperatorDependencies(HeapTuple tuple, Oid pg_operator_relid)
 	/* In case we are updating a shell, delete any existing entries */
 	deleteDependencyRecordsFor(myself.classId, myself.objectId);
 
+	/* Dependency on namespace */
+	if (OidIsValid(oper->oprnamespace))
+	{
+		referenced.classId = get_system_catalog_relid(NamespaceRelationName);
+		referenced.objectId = oper->oprnamespace;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
+
 	/* Dependency on left type */
 	if (OidIsValid(oper->oprleft))
 	{
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 18746d9e219..f8693fa7fec 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.77 2002/07/16 22:12:19 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.78 2002/07/18 16:47:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -268,6 +268,12 @@ ProcedureCreate(const char *procedureName,
 	myself.objectId = retval;
 	myself.objectSubId = 0;
 
+	/* dependency on namespace */
+	referenced.classId = get_system_catalog_relid(NamespaceRelationName);
+	referenced.objectId = procNamespace;
+	referenced.objectSubId = 0;
+	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
 	/* dependency on implementation language */
 	referenced.classId = get_system_catalog_relid(LanguageRelationName);
 	referenced.objectId = languageObjectId;
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 88f113beb01..5cd5d291d7e 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.73 2002/07/12 18:43:15 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.74 2002/07/18 16:47:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
@@ -167,8 +168,6 @@ TypeCreate(const char *typeName,
 	NameData	name;
 	TupleDesc	tupDesc;
 	int			i;
-	ObjectAddress	myself,
-					referenced;
 
 	/*
 	 * validate size specifications: either positive (fixed-length) or -1
@@ -302,74 +301,90 @@ TypeCreate(const char *typeName,
 	}
 
 	/*
-	 * Create dependencies
+	 * Create dependencies.  We can/must skip this in bootstrap mode.
 	 */
-	myself.classId = RelOid_pg_type;
-	myself.objectId = typeObjectId;
-	myself.objectSubId = 0;
-
-	/* Normal dependencies on the I/O functions */
-	referenced.classId = RelOid_pg_proc;
-	referenced.objectId = inputProcedure;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-
-	referenced.classId = RelOid_pg_proc;
-	referenced.objectId = outputProcedure;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-
-	if (receiveProcedure != inputProcedure)
+	if (!IsBootstrapProcessingMode())
 	{
+		ObjectAddress	myself,
+						referenced;
+
+		myself.classId = RelOid_pg_type;
+		myself.objectId = typeObjectId;
+		myself.objectSubId = 0;
+
+		/* dependency on namespace */
+		/* skip for relation rowtype, since we have indirect dependency */
+		if (!OidIsValid(relationOid))
+		{
+			referenced.classId = get_system_catalog_relid(NamespaceRelationName);
+			referenced.objectId = typeNamespace;
+			referenced.objectSubId = 0;
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		}
+
+		/* Normal dependencies on the I/O functions */
 		referenced.classId = RelOid_pg_proc;
-		referenced.objectId = receiveProcedure;
+		referenced.objectId = inputProcedure;
 		referenced.objectSubId = 0;
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-	}
 
-	if (sendProcedure != outputProcedure)
-	{
 		referenced.classId = RelOid_pg_proc;
-		referenced.objectId = sendProcedure;
+		referenced.objectId = outputProcedure;
 		referenced.objectSubId = 0;
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-	}
 
-	/*
-	 * If the type is a rowtype for a relation, mark it as internally
-	 * dependent on the relation.  This allows it to be auto-dropped
-	 * when the relation is, and not otherwise.
-	 */
-	if (OidIsValid(relationOid))
-	{
-		referenced.classId = RelOid_pg_class;
-		referenced.objectId = relationOid;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
-	}
+		if (receiveProcedure != inputProcedure)
+		{
+			referenced.classId = RelOid_pg_proc;
+			referenced.objectId = receiveProcedure;
+			referenced.objectSubId = 0;
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		}
+
+		if (sendProcedure != outputProcedure)
+		{
+			referenced.classId = RelOid_pg_proc;
+			referenced.objectId = sendProcedure;
+			referenced.objectSubId = 0;
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		}
 
-	/*
-	 * If the type is an array type, mark it auto-dependent on the
-	 * base type.  (This is a compromise between the typical case where the
-	 * array type is automatically generated and the case where it is manually
-	 * created: we'd prefer INTERNAL for the former case and NORMAL for the
-	 * latter.)
-	 */
-	if (OidIsValid(elementType))
-	{
-		referenced.classId = RelOid_pg_type;
-		referenced.objectId = elementType;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
-	}
+		/*
+		 * If the type is a rowtype for a relation, mark it as internally
+		 * dependent on the relation.  This allows it to be auto-dropped
+		 * when the relation is, and not otherwise.
+		 */
+		if (OidIsValid(relationOid))
+		{
+			referenced.classId = RelOid_pg_class;
+			referenced.objectId = relationOid;
+			referenced.objectSubId = 0;
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+		}
 
-	/* Normal dependency from a domain to its base type. */
-	if (OidIsValid(baseType))
-	{
-		referenced.classId = RelOid_pg_type;
-		referenced.objectId = baseType;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		/*
+		 * If the type is an array type, mark it auto-dependent on the base
+		 * type.  (This is a compromise between the typical case where the
+		 * array type is automatically generated and the case where it is
+		 * manually created: we'd prefer INTERNAL for the former case and
+		 * NORMAL for the latter.)
+		 */
+		if (OidIsValid(elementType))
+		{
+			referenced.classId = RelOid_pg_type;
+			referenced.objectId = elementType;
+			referenced.objectSubId = 0;
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+		}
+
+		/* Normal dependency from a domain to its base type. */
+		if (OidIsValid(baseType))
+		{
+			referenced.classId = RelOid_pg_type;
+			referenced.objectId = baseType;
+			referenced.objectSubId = 0;
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		}
 	}
 
 	/*
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index a790a28bccd..621006758c5 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -1,20 +1,23 @@
 /*-------------------------------------------------------------------------
  *
  * schemacmds.c
- *	  schema creation command support code
+ *	  schema creation/manipulation commands
  *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.4 2002/06/11 13:40:50 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.5 2002/07/18 16:47:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "access/heapam.h"
 #include "catalog/catalog.h"
+#include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_namespace.h"
 #include "commands/schemacmds.h"
@@ -23,6 +26,7 @@
 #include "tcop/utility.h"
 #include "utils/acl.h"
 #include "utils/lsyscache.h"
+#include "utils/syscache.h"
 
 
 /*
@@ -139,3 +143,70 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 	/* Reset current user */
 	SetUserId(saved_userid);
 }
+
+
+/*
+ *	RemoveSchema
+ *		Removes a schema.
+ */
+void
+RemoveSchema(List *names, DropBehavior behavior)
+{
+	char	   *namespaceName;
+	Oid			namespaceId;
+	ObjectAddress object;
+
+	if (length(names) != 1)
+		elog(ERROR, "Schema name may not be qualified");
+	namespaceName = strVal(lfirst(names));
+
+	namespaceId = GetSysCacheOid(NAMESPACENAME,
+								 CStringGetDatum(namespaceName),
+								 0, 0, 0);
+	if (!OidIsValid(namespaceId))
+		elog(ERROR, "Schema \"%s\" does not exist", namespaceName);
+
+	/* Permission check */
+	if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, namespaceName);
+
+	/*
+	 * Do the deletion.  Objects contained in the schema are removed
+	 * by means of their dependency links to the schema.
+	 *
+	 * XXX currently, index opclasses don't have creation/deletion
+	 * commands, so they will not get removed when the containing
+	 * schema is removed.  This is annoying but not fatal.
+	 */
+	object.classId = get_system_catalog_relid(NamespaceRelationName);
+	object.objectId = namespaceId;
+	object.objectSubId = 0;
+
+	performDeletion(&object, behavior);
+}
+
+
+/*
+ * Guts of schema deletion.
+ */
+void
+RemoveSchemaById(Oid schemaOid)
+{
+	Relation	relation;
+	HeapTuple	tup;
+
+	relation = heap_openr(NamespaceRelationName, RowExclusiveLock);
+
+	tup = SearchSysCache(NAMESPACEOID,
+						 ObjectIdGetDatum(schemaOid),
+						 0, 0, 0);
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "RemoveSchemaById: schema %u not found",
+			 schemaOid);
+
+	simple_heap_delete(relation, &tup->t_self);
+
+	ReleaseSysCache(tup);
+
+	heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 17a3b61e762..d7af8d956af 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.344 2002/07/18 04:43:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.345 2002/07/18 16:47:24 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -132,7 +132,7 @@ static void doNegateFloat(Value *v);
 }
 
 %type <node>	stmt, schema_stmt,
-		AlterDatabaseSetStmt, AlterGroupStmt, AlterSchemaStmt,
+		AlterDatabaseSetStmt, AlterGroupStmt,
 		AlterTableStmt, AlterUserStmt, AlterUserSetStmt,
 		AnalyzeStmt, ClosePortalStmt, ClusterStmt, CommentStmt,
 		ConstraintsSetStmt, CopyStmt, CreateAsStmt,
@@ -140,7 +140,7 @@ static void doNegateFloat(Value *v);
 		CreateSchemaStmt, CreateSeqStmt, CreateStmt,
 		CreateAssertStmt, CreateTrigStmt, CreateUserStmt,
 		CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
-		DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt,
+		DropGroupStmt, DropPLangStmt, DropStmt,
 		DropAssertStmt, DropTrigStmt, DropRuleStmt,
 		DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
 		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt,
@@ -468,7 +468,6 @@ stmtmulti:	stmtmulti ';' stmt
 stmt :
 			AlterDatabaseSetStmt
 			| AlterGroupStmt
-			| AlterSchemaStmt
 			| AlterTableStmt
 			| AlterUserStmt
 			| AlterUserSetStmt
@@ -488,7 +487,6 @@ stmt :
 			| ClusterStmt
 			| DefineStmt
 			| DropStmt
-			| DropSchemaStmt
 			| TruncateStmt
 			| CommentStmt
 			| DropGroupStmt
@@ -746,7 +744,6 @@ DropGroupStmt:
  *
  * Manipulate a schema
  *
- *
  *****************************************************************************/
 
 CreateSchemaStmt:
@@ -773,20 +770,6 @@ CreateSchemaStmt:
 				}
 		;
 
-AlterSchemaStmt:
-			ALTER SCHEMA ColId
-				{
-					elog(ERROR, "ALTER SCHEMA not yet supported");
-				}
-		;
-
-DropSchemaStmt:
-			DROP SCHEMA ColId opt_drop_behavior
-				{
-					elog(ERROR, "DROP SCHEMA not yet supported");
-				}
-		;
-
 OptSchemaName:
 			ColId									{ $$ = $1; }
 			| /* EMPTY */							{ $$ = NULL; }
@@ -2306,6 +2289,7 @@ drop_type:	TABLE									{ $$ = DROP_TABLE; }
 			| TYPE_P								{ $$ = DROP_TYPE; }
 			| DOMAIN_P								{ $$ = DROP_DOMAIN; }
 			| CONVERSION_P							{ $$ = DROP_CONVERSION; }
+			| SCHEMA								{ $$ = DROP_SCHEMA; }
 		;
 
 any_name_list:
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 154e478687b..862faf34cae 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.270 2002/07/13 01:02:14 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.271 2002/07/18 16:47:25 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -1693,7 +1693,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.270 $ $Date: 2002/07/13 01:02:14 $\n");
+		puts("$Revision: 1.271 $ $Date: 2002/07/18 16:47:25 $\n");
 	}
 
 	/*
@@ -2220,7 +2220,10 @@ CreateCommandTag(Node *parsetree)
 					tag = "DROP DOMAIN";
 					break;
 				case DROP_CONVERSION:
-					tag = "DROP CONVERSON";
+					tag = "DROP CONVERSION";
+					break;
+				case DROP_SCHEMA:
+					tag = "DROP SCHEMA";
 					break;
 				default:
 					tag = "???";
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 86373943667..8ba7466ee28 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.162 2002/07/12 18:43:17 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.163 2002/07/18 16:47:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -252,11 +252,7 @@ ProcessUtility(Node *parsetree,
 			 * relation and attribute manipulation
 			 */
 		case T_CreateSchemaStmt:
-			{
-				CreateSchemaStmt  *stmt = (CreateSchemaStmt *) parsetree;
-
-				CreateSchemaCommand(stmt);
-			}
+			CreateSchemaCommand((CreateSchemaStmt *) parsetree);
 			break;
 
 		case T_CreateStmt:
@@ -322,17 +318,20 @@ ProcessUtility(Node *parsetree,
 							break;
 
 						case DROP_CONVERSION:
-							/* RemoveDomain does its own permissions checks */
+							/* does its own permissions checks */
 							DropConversionCommand(names);
 							break;
+
+						case DROP_SCHEMA:
+							/* RemoveSchema does its own permissions checks */
+							RemoveSchema(names, stmt->behavior);
+							break;
 					}
 
 					/*
-					 * Make sure subsequent loop iterations will see
-					 * results of this one; needed if removing multiple
-					 * rules for same table, for example.
+					 * We used to need to do CommandCounterIncrement()
+					 * here, but now it's done inside performDeletion().
 					 */
-					CommandCounterIncrement();
 				}
 			}
 			break;
diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh
index a88eed353b1..9902a24fc4f 100644
--- a/src/bin/initdb/initdb.sh
+++ b/src/bin/initdb/initdb.sh
@@ -27,7 +27,7 @@
 # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.159 2002/07/18 02:02:30 ishii Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.160 2002/07/18 16:47:25 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -717,6 +717,9 @@ INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_language;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_operator;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_rewrite;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_trigger;
+-- restriction here to avoid pinning the public namespace
+INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_namespace \
+    WHERE nspname LIKE 'pg%';
 EOF
 if [ "$?" -ne 0 ]; then
     exit_nicely
diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h
index 6adf9a4517e..63205500c27 100644
--- a/src/include/commands/schemacmds.h
+++ b/src/include/commands/schemacmds.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: schemacmds.h,v 1.1 2002/04/15 05:22:04 tgl Exp $
+ * $Id: schemacmds.h,v 1.2 2002/07/18 16:47:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,4 +19,7 @@
 
 extern void CreateSchemaCommand(CreateSchemaStmt *parsetree);
 
+extern void RemoveSchema(List *names, DropBehavior behavior);
+extern void RemoveSchemaById(Oid schemaOid);
+
 #endif  /* SCHEMACMDS_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e6b27d03af4..26e2e0ab299 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.190 2002/07/18 04:43:51 momjian Exp $
+ * $Id: parsenodes.h,v 1.191 2002/07/18 16:47:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1136,7 +1136,7 @@ typedef struct CreateDomainStmt
 } CreateDomainStmt;
 
 /* ----------------------
- *		Drop Table|Sequence|View|Index|Type|Domain Statement
+ *		Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement
  * ----------------------
  */
 
@@ -1147,6 +1147,7 @@ typedef struct CreateDomainStmt
 #define DROP_TYPE     5
 #define DROP_DOMAIN	  6
 #define DROP_CONVERSION	  7
+#define DROP_SCHEMA	  8
 
 typedef struct DropStmt
 {
-- 
GitLab