From 9ace03183c56ca3474679bc56316e962d0af4b81 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 22 Oct 2000 23:32:48 +0000
Subject: [PATCH] Some small polishing of Mark Hollomon's cleanup of DROP
 command: might as well allow DROP multiple INDEX, RULE, TYPE as well.  Add
 missing CommandCounterIncrement to DROP loop, which could cause trouble
 otherwise with multiple DROP of items affecting same catalog entries.  Try to
 bring a little consistency to various error messages using 'does not exist',
 'nonexistent', etc --- I standardized on 'does not exist' since that's what
 the vast majority of the existing uses seem to be.

---
 doc/src/sgml/ref/drop_index.sgml          | 12 +--
 doc/src/sgml/ref/drop_rule.sgml           |  8 +-
 doc/src/sgml/ref/drop_sequence.sgml       |  6 +-
 doc/src/sgml/ref/drop_table.sgml          |  4 +-
 doc/src/sgml/ref/drop_type.sgml           |  6 +-
 doc/src/sgml/ref/drop_view.sgml           | 10 +--
 src/backend/catalog/heap.c                |  6 +-
 src/backend/catalog/pg_operator.c         | 12 +--
 src/backend/commands/indexcmds.c          | 16 ++--
 src/backend/commands/rename.c             |  4 +-
 src/backend/parser/gram.y                 | 74 ++++++-------------
 src/backend/tcop/utility.c                | 90 +++++++++++------------
 src/include/nodes/nodes.h                 |  4 +-
 src/test/regress/expected/errors.out      |  6 +-
 src/test/regress/expected/foreign_key.out |  4 +-
 src/test/regress/expected/inet.out        |  2 +-
 src/test/regress/expected/plpgsql.out     | 20 ++---
 src/test/regress/sql/plpgsql.sql          | 16 ++--
 18 files changed, 131 insertions(+), 169 deletions(-)

diff --git a/doc/src/sgml/ref/drop_index.sgml b/doc/src/sgml/ref/drop_index.sgml
index 22b7ce2c969..aaf5f1adfa7 100644
--- a/doc/src/sgml/ref/drop_index.sgml
+++ b/doc/src/sgml/ref/drop_index.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_index.sgml,v 1.7 1999/07/22 15:09:10 thomas Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_index.sgml,v 1.8 2000/10/22 23:32:38 tgl Exp $
 Postgres documentation
 -->
 
@@ -15,7 +15,7 @@ Postgres documentation
    DROP INDEX
   </refname>
   <refpurpose>
-   Removes an index from a database
+   Removes existing indexes from a database
   </refpurpose>
  </refnamediv>
  <refsynopsisdiv>
@@ -23,7 +23,7 @@ Postgres documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP INDEX <replaceable class="PARAMETER">index_name</replaceable>
+DROP INDEX <replaceable class="PARAMETER">index_name</replaceable> [, ...]
   </synopsis>
 
   <refsect2 id="R2-SQL-DROPINDEX-1">
@@ -39,7 +39,7 @@ DROP INDEX <replaceable class="PARAMETER">index_name</replaceable>
       <term><replaceable class="PARAMETER">index_name</replaceable></term>
       <listitem>
        <para>
-	The name of the index to remove.
+	The name of an index to remove.
        </para>
       </listitem>
      </varlistentry>
@@ -62,13 +62,13 @@ DROP
        </computeroutput></term>
       <listitem>
        <para>
-	The message returned if the index is successfully dropped.
+	The message returned if the command completes successfully.
        </para>
       </listitem>
      </varlistentry>
      <varlistentry>
       <term><computeroutput>
-ERROR: index "<replaceable class="PARAMETER">index_name</replaceable>" nonexistent
+ERROR: index "<replaceable class="PARAMETER">index_name</replaceable>" does not exist
        </computeroutput></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/drop_rule.sgml b/doc/src/sgml/ref/drop_rule.sgml
index 597f7462af3..9942ae6e06a 100644
--- a/doc/src/sgml/ref/drop_rule.sgml
+++ b/doc/src/sgml/ref/drop_rule.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_rule.sgml,v 1.7 2000/10/05 19:48:18 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_rule.sgml,v 1.8 2000/10/22 23:32:38 tgl Exp $
 Postgres documentation
 -->
 
@@ -15,7 +15,7 @@ Postgres documentation
    DROP RULE
   </refname>
   <refpurpose>
-   Removes an existing rule from the database
+   Removes existing rules from the database
   </refpurpose>
  </refnamediv>
  <refsynopsisdiv>
@@ -23,7 +23,7 @@ Postgres documentation
    <date>1998-09-22</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP RULE <replaceable class="PARAMETER">name</replaceable>
+DROP RULE <replaceable class="PARAMETER">name</replaceable> [, ...]
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPRULE-1">
@@ -68,7 +68,7 @@ DROP
      </varlistentry>
      <varlistentry>
       <term><computeroutput>
-ERROR:  RewriteGetRuleEventRel: rule "<replaceable class="parameter">name</replaceable>" not found
+ERROR:  Rule or view "<replaceable class="parameter">name</replaceable>" not found
        </computeroutput></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/drop_sequence.sgml b/doc/src/sgml/ref/drop_sequence.sgml
index 16db5a47c95..e2de3fa3c77 100644
--- a/doc/src/sgml/ref/drop_sequence.sgml
+++ b/doc/src/sgml/ref/drop_sequence.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_sequence.sgml,v 1.7 2000/05/18 14:24:33 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_sequence.sgml,v 1.8 2000/10/22 23:32:38 tgl Exp $
 Postgres documentation
 -->
 
@@ -15,7 +15,7 @@ Postgres documentation
    DROP SEQUENCE
   </refname>
   <refpurpose>
-   Removes an existing sequence
+   Removes existing sequences from a database
   </refpurpose>
  </refnamediv>
  <refsynopsisdiv>
@@ -69,7 +69,7 @@ DROP
      </varlistentry>
      <varlistentry>
       <term><computeroutput>
-NOTICE: Relation "<replaceable class="parameter">name</replaceable>" does not exist.
+ERROR: sequence "<replaceable class="parameter">name</replaceable>" does not exist
        </computeroutput></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/drop_table.sgml b/doc/src/sgml/ref/drop_table.sgml
index 5f5a7aa821b..f855b57de76 100644
--- a/doc/src/sgml/ref/drop_table.sgml
+++ b/doc/src/sgml/ref/drop_table.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_table.sgml,v 1.8 2000/10/18 16:16:03 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_table.sgml,v 1.9 2000/10/22 23:32:38 tgl Exp $
 Postgres documentation
 -->
 
@@ -68,7 +68,7 @@ DROP
      </varlistentry>
      <varlistentry>
       <term><computeroutput>
-ERROR: table "<replaceable class="parameter">name</replaceable>" is nonexistent
+ERROR: table "<replaceable class="parameter">name</replaceable>" does not exist
        </computeroutput></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/drop_type.sgml b/doc/src/sgml/ref/drop_type.sgml
index 789d8b37989..abd7582a807 100644
--- a/doc/src/sgml/ref/drop_type.sgml
+++ b/doc/src/sgml/ref/drop_type.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_type.sgml,v 1.7 2000/07/22 04:30:27 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_type.sgml,v 1.8 2000/10/22 23:32:38 tgl Exp $
 Postgres documentation
 -->
 
@@ -15,7 +15,7 @@ Postgres documentation
    DROP TYPE
   </refname>
   <refpurpose>
-   Removes a user-defined type from the system catalogs
+   Removes user-defined types from the system catalogs
   </refpurpose>
  </refnamediv>
  <refsynopsisdiv>
@@ -23,7 +23,7 @@ Postgres documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP TYPE <replaceable class="PARAMETER">typename</replaceable>
+DROP TYPE <replaceable class="PARAMETER">typename</replaceable> [, ...]
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPTYPE-1">
diff --git a/doc/src/sgml/ref/drop_view.sgml b/doc/src/sgml/ref/drop_view.sgml
index 636d18151d5..721dcddaca3 100644
--- a/doc/src/sgml/ref/drop_view.sgml
+++ b/doc/src/sgml/ref/drop_view.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_view.sgml,v 1.7 2000/10/18 16:16:03 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_view.sgml,v 1.8 2000/10/22 23:32:38 tgl Exp $
 Postgres documentation
 -->
 
@@ -15,7 +15,7 @@ Postgres documentation
    DROP VIEW
   </refname>
   <refpurpose>
-   Removes an existing view from a database
+   Removes existing views from a database
   </refpurpose>
  </refnamediv>
  <refsynopsisdiv>
@@ -70,7 +70,7 @@ DROP
      </varlistentry>
      <varlistentry>
       <term><computeroutput>
-ERROR: view <replaceable class="parameter">name</replaceable> is nonexistent
+ERROR: view <replaceable class="parameter">name</replaceable> does not exist
        </computeroutput></term>
       <listitem>
        <para>
@@ -104,10 +104,6 @@ ERROR: view <replaceable class="parameter">name</replaceable> is nonexistent
    <title>
     Notes
    </title>
-   <para>
-    The <productname>Postgres</productname>
-    <command>DROP TABLE</command> statement also drops views.
-   </para>
    <para>
     Refer to <command>CREATE VIEW</command>
     for information on how to create views.
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index fbdd1ae0cf9..f2df9c3c07c 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.149 2000/10/16 14:52:02 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.150 2000/10/22 23:32:38 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1091,7 +1091,7 @@ DeleteRelationTuple(Relation rel)
 	if (!HeapTupleIsValid(tup))
 	{
 		heap_close(pg_class_desc, RowExclusiveLock);
-		elog(ERROR, "Relation '%s' does not exist",
+		elog(ERROR, "Relation \"%s\" does not exist",
 			 RelationGetRelationName(rel));
 	}
 
@@ -1342,7 +1342,7 @@ DeleteTypeTuple(Relation rel)
 	{
 		heap_endscan(pg_type_scan);
 		heap_close(pg_type_desc, RowExclusiveLock);
-		elog(ERROR, "DeleteTypeTuple: %s type nonexistent",
+		elog(ERROR, "DeleteTypeTuple: type \"%s\" does not exist",
 			 RelationGetRelationName(rel));
 	}
 
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index a0c6dd70a38..388bad8a583 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.51 2000/08/21 17:22:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.52 2000/10/22 23:32:38 tgl Exp $
  *
  * NOTES
  *	  these routines moved here from commands/define.c and somewhat cleaned up.
@@ -181,7 +181,7 @@ OperatorGet(char *operatorName,
 		leftObjectId = TypeGet(leftTypeName, &leftDefined);
 
 		if (!OidIsValid(leftObjectId) || !leftDefined)
-			elog(ERROR, "OperatorGet: left type '%s' nonexistent",
+			elog(ERROR, "OperatorGet: left type \"%s\" does not exist",
 				 leftTypeName);
 	}
 
@@ -190,7 +190,7 @@ OperatorGet(char *operatorName,
 		rightObjectId = TypeGet(rightTypeName, &rightDefined);
 
 		if (!OidIsValid(rightObjectId) || !rightDefined)
-			elog(ERROR, "OperatorGet: right type '%s' nonexistent",
+			elog(ERROR, "OperatorGet: right type \"%s\" does not exist",
 				 rightTypeName);
 	}
 
@@ -527,7 +527,7 @@ OperatorDef(char *operatorName,
 		leftTypeId = TypeGet(leftTypeName, &leftDefined);
 
 		if (!OidIsValid(leftTypeId) || !leftDefined)
-			elog(ERROR, "OperatorDef: left type '%s' nonexistent",
+			elog(ERROR, "OperatorDef: left type \"%s\" does not exist",
 				 leftTypeName);
 	}
 
@@ -536,7 +536,7 @@ OperatorDef(char *operatorName,
 		rightTypeId = TypeGet(rightTypeName, &rightDefined);
 
 		if (!OidIsValid(rightTypeId) || !rightDefined)
-			elog(ERROR, "OperatorDef: right type '%s' nonexistent",
+			elog(ERROR, "OperatorDef: right type \"%s\" does not exist",
 				 rightTypeName);
 	}
 
@@ -739,7 +739,7 @@ OperatorDef(char *operatorName,
 											  otherRightTypeName);
 				if (!OidIsValid(other_oid))
 					elog(ERROR,
-						 "OperatorDef: can't create operator shell '%s'",
+						 "OperatorDef: can't create operator shell \"%s\"",
 						 name[j]);
 				values[i++] = ObjectIdGetDatum(other_oid);
 			}
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 64cdf840f06..f9d1a92c758 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.38 2000/09/06 14:15:16 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.39 2000/10/22 23:32:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -610,7 +610,7 @@ RemoveIndex(char *name)
 								0, 0, 0);
 
 	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "index \"%s\" nonexistent", name);
+		elog(ERROR, "index \"%s\" does not exist", name);
 
 	if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
 	{
@@ -640,7 +640,7 @@ ReindexIndex(const char *name, bool force /* currently unused */ )
 								0, 0, 0);
 
 	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "index \"%s\" nonexistent", name);
+		elog(ERROR, "index \"%s\" does not exist", name);
 
 	if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
 	{
@@ -650,7 +650,7 @@ ReindexIndex(const char *name, bool force /* currently unused */ )
 	}
 
 	if (!reindex_index(tuple->t_data->t_oid, force))
-		elog(NOTICE, "index '%s' wasn't reindexed", name);
+		elog(NOTICE, "index \"%s\" wasn't reindexed", name);
 }
 
 /*
@@ -671,7 +671,7 @@ ReindexTable(const char *name, bool force)
 								0, 0, 0);
 
 	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "table \"%s\" nonexistent", name);
+		elog(ERROR, "table \"%s\" does not exist", name);
 
 	if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_RELATION)
 	{
@@ -681,7 +681,7 @@ ReindexTable(const char *name, bool force)
 	}
 
 	if (!reindex_relation(tuple->t_data->t_oid, force))
-		elog(NOTICE, "table '%s' wasn't reindexed", name);
+		elog(NOTICE, "table \"%s\" wasn't reindexed", name);
 }
 
 /*
@@ -719,7 +719,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
 	scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scankey);
 	dbtuple = heap_getnext(scan, 0);
 	if (!HeapTupleIsValid(dbtuple))
-		elog(ERROR, "Database \"%s\" doesn't exist", dbname);
+		elog(ERROR, "Database \"%s\" does not exist", dbname);
 	db_id = dbtuple->t_data->t_oid;
 	db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
 	heap_endscan(scan);
@@ -789,7 +789,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
 	{
 		StartTransactionCommand();
 		if (reindex_relation(relids[i], force))
-			elog(NOTICE, "relation %d was reindexed", relids[i]);
+			elog(NOTICE, "relation %u was reindexed", relids[i]);
 		CommitTransactionCommand();
 	}
 	StartTransactionCommand();
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
index ad7f25bbfd8..0f41cac1dc7 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.50 2000/10/20 02:53:10 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.51 2000/10/22 23:32:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -137,7 +137,7 @@ renameatt(char *relname,
 										PointerGetDatum(oldattname),
 										0, 0);
 	if (!HeapTupleIsValid(oldatttup))
-		elog(ERROR, "renameatt: attribute \"%s\" nonexistent", oldattname);
+		elog(ERROR, "renameatt: attribute \"%s\" does not exist", oldattname);
 
 	if (((Form_pg_attribute) GETSTRUCT(oldatttup))->attnum < 0)
 		elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index fbda2758035..11f55a2f97e 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.196 2000/10/18 16:16:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.197 2000/10/22 23:32:48 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -125,7 +125,7 @@ static void doNegateFloat(Value *v);
 		DropUserStmt, DropdbStmt, ExplainStmt, ExtendStmt, FetchStmt,
 		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
 		NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
-		RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt, RemoveStmt,
+		RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt,
 		RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty,
 		RuleStmt, SelectStmt, SetSessionStmt, TransactionStmt, TruncateStmt,
 		UnlistenStmt, UpdateStmt, VacuumStmt, VariableResetStmt,
@@ -202,7 +202,7 @@ static void doNegateFloat(Value *v);
 				opt_with_copy, index_opt_unique, opt_verbose, opt_analyze
 %type <boolean> opt_cursor
 
-%type <ival>	copy_dirn, def_type, direction, reindex_type, remove_type,
+%type <ival>	copy_dirn, def_type, direction, reindex_type, drop_type,
 		opt_column, event, comment_type, comment_cl,
 		comment_ag, comment_fn, comment_op, comment_tg
 
@@ -447,7 +447,6 @@ stmt :	AlterSchemaStmt
 		| RemoveAggrStmt
 		| RemoveOperStmt
 		| RemoveFuncStmt
-		| RemoveStmt
 		| RenameStmt
 		| RevokeStmt
 		| OptimizableStmt
@@ -1935,33 +1934,28 @@ def_arg:  func_return  					{  $$ = (Node *)$1; }
 /*****************************************************************************
  *
  *		QUERY:
- *				drop <relname1> [, <relname2> .. <relnameN> ]
+ *
+ *		DROP itemtype itemname [, itemname ...]
  *
  *****************************************************************************/
 
-DropStmt:  DROP TABLE relation_name_list
-				{
-					DropStmt *n = makeNode(DropStmt);
-					n->names = $3;
-					n->removeType = DROP_TABLE;
-					$$ = (Node *)n;
-				}
-		| DROP SEQUENCE relation_name_list
-				{
-					DropStmt *n = makeNode(DropStmt);
-					n->names = $3;
-					n->removeType = DROP_SEQUENCE;
-					$$ = (Node *)n;
-				}
-		| DROP VIEW relation_name_list
+DropStmt:  DROP drop_type name_list
 				{
 					DropStmt *n = makeNode(DropStmt);
+					n->removeType = $2;
 					n->names = $3;
-					n->removeType = DROP_VIEW;
 					$$ = (Node *)n;
 				}
 		;
 
+drop_type: TABLE								{ $$ = DROP_TABLE; }
+		| SEQUENCE								{ $$ = DROP_SEQUENCE; }
+		| VIEW									{ $$ = DROP_VIEW; }
+		| INDEX									{ $$ = DROP_INDEX; }
+		| RULE									{ $$ = DROP_RULE; }
+		| TYPE_P								{ $$ = DROP_TYPE_P; }
+		;
+
 /*****************************************************************************
  *
  *		QUERY:
@@ -2550,34 +2544,21 @@ func_return:  Typename
  *
  *		QUERY:
  *
- *		remove function <funcname>
- *				(REMOVE FUNCTION "funcname" (arg1, arg2, ...))
- *		remove aggregate <aggname>
- *				(REMOVE AGGREGATE "aggname" "aggtype")
- *		remove operator <opname>
- *				(REMOVE OPERATOR "opname" (leftoperand_typ rightoperand_typ))
- *		remove type <typename>
- *				(REMOVE TYPE "typename")
- *		remove rule <rulename>
- *				(REMOVE RULE "rulename")
+ *		DROP FUNCTION funcname (arg1, arg2, ...)
+ *		DROP AGGREGATE aggname aggtype
+ *		DROP OPERATOR opname (leftoperand_typ rightoperand_typ)
  *
  *****************************************************************************/
 
-RemoveStmt:  DROP remove_type name
+RemoveFuncStmt:  DROP FUNCTION func_name func_args
 				{
-					DropStmt *n = makeNode(DropStmt);
-					n->removeType = $2;
-					n->names =  makeList1(makeString($3));
+					RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
+					n->funcname = $3;
+					n->args = $4;
 					$$ = (Node *)n;
 				}
 		;
 
-remove_type:  TYPE_P							{  $$ = DROP_TYPE_P; }
-		| INDEX									{  $$ = DROP_INDEX; }
-		| RULE									{  $$ = DROP_RULE; }
-		;
-
-
 RemoveAggrStmt:  DROP AGGREGATE name aggr_argtype
 				{
 						RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
@@ -2591,17 +2572,6 @@ aggr_argtype:  Typename							{ $$ = $1; }
 		| '*'									{ $$ = NULL; }
 		;
 
-
-RemoveFuncStmt:  DROP FUNCTION func_name func_args
-				{
-					RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
-					n->funcname = $3;
-					n->args = $4;
-					$$ = (Node *)n;
-				}
-		;
-
-
 RemoveOperStmt:  DROP OPERATOR all_Op '(' oper_argtypes ')'
 				{
 					RemoveOperStmt *n = makeNode(RemoveOperStmt);
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index d63a5c6b7e2..3c4c40c84cc 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.97 2000/10/18 16:16:06 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.98 2000/10/22 23:32:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,21 +47,22 @@
 
 
 /*
- *
+ * Error-checking support for DROP commands
  */
 
 struct kindstrings {
 	char kind;
+	char *indef_article;
 	char *name;
 	char *command;
 };
 
 static struct kindstrings kindstringarray[] = {
-	{ RELKIND_RELATION, "table", "TABLE" },
-	{ RELKIND_SEQUENCE, "sequence", "SEQUENCE" },
-	{ RELKIND_VIEW, "view", "VIEW" },
-	{ RELKIND_INDEX, "index", "INDEX" },
-	{ '\0', "", "" }
+	{ RELKIND_RELATION, "a", "table", "TABLE" },
+	{ RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE" },
+	{ RELKIND_VIEW, "a", "view", "VIEW" },
+	{ RELKIND_INDEX, "an", "index", "INDEX" },
+	{ '\0', "a", "???", "???" }
 };
 
 
@@ -81,36 +82,44 @@ DropErrorMsg(char* relname, char wrongkind, char rightkind)
 			break;
 	Assert(wentry->kind != '\0');
 	
-	elog(ERROR, "%s is not a %s. Use 'DROP %s' to remove a %s",
-			relname, rentry->name, wentry->command, wentry->name);
+	elog(ERROR, "\"%s\" is not %s %s. Use DROP %s to remove %s %s",
+		 relname, rentry->indef_article, rentry->name,
+		 wentry->command, wentry->indef_article, wentry->name);
 }
 
 static void
-CheckClassKind(char *name, char rightkind)
+CheckDropPermissions(char *name, char rightkind)
 {
-	HeapTuple	tuple;
 	struct kindstrings *rentry;
+	HeapTuple	tuple;
 	Form_pg_class classform;
 
+	for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
+		if (rentry->kind == rightkind)
+			break;
+	Assert(rentry->kind != '\0');
+
 	tuple = SearchSysCacheTuple(RELNAME,
 								PointerGetDatum(name),
 								0, 0, 0);
-
 	if (!HeapTupleIsValid(tuple))
-	{
-		for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
-			if (rentry->kind == rightkind)
-				break;
-		Assert(rentry->kind != '\0');
-		elog(ERROR, "%s \"%s\" is nonexistent", rentry->name, name);
-	}
+		elog(ERROR, "%s \"%s\" does not exist", rentry->name, name);
 
 	classform = (Form_pg_class) GETSTRUCT(tuple);
 
 	if (classform->relkind != rightkind)
 		DropErrorMsg(name, classform->relkind, rightkind);
+
+	if (!pg_ownercheck(GetUserId(), name, RELNAME))
+		elog(ERROR, "you do not own %s \"%s\"",
+			 rentry->name, name);
+
+	if (!allowSystemTableMods && IsSystemRelationName(name))
+		elog(ERROR, "%s \"%s\" is a system %s",
+			 rentry->name, name, rentry->name);
 }
 
+
 /* ----------------
  *		general utility function invoker
  * ----------------
@@ -204,7 +213,6 @@ ProcessUtility(Node *parsetree,
 			/*
 			 * Let AlterTableCreateToastTable decide if this
 			 * one needs a secondary relation too.
-			 *
 			 */
 			CommandCounterIncrement();
 			AlterTableCreateToastTable(((CreateStmt *)parsetree)->relname,
@@ -217,51 +225,32 @@ ProcessUtility(Node *parsetree,
 				List	   *args = stmt->names;
 				List	   *arg;
 
-				foreach(arg, args) {
+				set_ps_display(commandTag = "DROP");
 
+				foreach(arg, args)
+				{
 					relname = strVal(lfirst(arg));
-					if (!allowSystemTableMods && IsSystemRelationName(relname))
-						elog(ERROR, "class \"%s\" is a system catalog",
-							 relname);
-
-					set_ps_display(commandTag = "DROP");
 
 					switch(stmt->removeType)
 					{
 						case DROP_TABLE:
-							CheckClassKind(relname, RELKIND_RELATION);
-							if (!pg_ownercheck(GetUserId(), relname, RELNAME))
-								elog(ERROR, "you do not own table \"%s\"",
-									 relname);
+							CheckDropPermissions(relname, RELKIND_RELATION);
 							RemoveRelation(relname);
-
 							break;
 
 						case DROP_SEQUENCE:
-							CheckClassKind(relname, RELKIND_SEQUENCE);
-							if (!pg_ownercheck(GetUserId(), relname, RELNAME))
-								elog(ERROR, "you do not own sequence \"%s\"",
-									 relname);
+							CheckDropPermissions(relname, RELKIND_SEQUENCE);
 							RemoveRelation(relname);
-
 							break;
 
 						case DROP_VIEW:
-							CheckClassKind(relname, RELKIND_VIEW);
-							if (!pg_ownercheck(GetUserId(), relname, RELNAME))
-								elog(ERROR, "you do not own view \"%s\"",
-									 relname);
+							CheckDropPermissions(relname, RELKIND_VIEW);
 							RemoveView(relname);
-
 							break;
 
 						case DROP_INDEX:
-							CheckClassKind(relname, RELKIND_INDEX);
-							if (!pg_ownercheck(GetUserId(), relname, RELNAME))
-								elog(ERROR, "%s: %s", relname, 
-										aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+							CheckDropPermissions(relname, RELKIND_INDEX);
 							RemoveIndex(relname);
-
 							break;
 
 						case DROP_RULE:
@@ -279,11 +268,18 @@ ProcessUtility(Node *parsetree,
 							break;
 
 						case DROP_TYPE_P:
+							/* RemoveType does its own permissions checks */
 							RemoveType(relname);
 							break;
 					}
-				}
 
+					/*
+					 * Make sure subsequent loop iterations will see results
+					 * of this one; needed if removing multiple rules for
+					 * same table, for example.
+					 */
+					CommandCounterIncrement();
+				}
 			}
 			break;
 
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index fe798492c78..43bb8b733ee 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.78 2000/10/05 19:11:36 tgl Exp $
+ * $Id: nodes.h,v 1.79 2000/10/22 23:32:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -169,7 +169,7 @@ typedef enum NodeTag
 	T_RemoveAggrStmt,
 	T_RemoveFuncStmt,
 	T_RemoveOperStmt,
-	T_RemoveStmt,
+	T_RemoveStmt_XXX,			/* not used anymore; this tag# is available */
 	T_RenameStmt,
 	T_RuleStmt,
 	T_NotifyStmt,
diff --git a/src/test/regress/expected/errors.out b/src/test/regress/expected/errors.out
index 81b905bbae5..c59ba0817c3 100644
--- a/src/test/regress/expected/errors.out
+++ b/src/test/regress/expected/errors.out
@@ -52,7 +52,7 @@ drop table;
 ERROR:  parser: parse error at or near ";"
 -- no such relation 
 drop table nonesuch;
-ERROR:  table "nonesuch" is nonexistent
+ERROR:  table "nonesuch" does not exist
 --
 -- RENAME
  
@@ -81,7 +81,7 @@ alter table nonesuchrel rename column nonesuchatt to newnonesuchatt;
 ERROR:  Relation 'nonesuchrel' does not exist
 -- no such attribute 
 alter table emp rename column nonesuchatt to newnonesuchatt;
-ERROR:  renameatt: attribute "nonesuchatt" nonexistent
+ERROR:  renameatt: attribute "nonesuchatt" does not exist
 -- conflict 
 alter table emp rename column salary to manager;
 ERROR:  renameatt: attribute "manager" exists
@@ -122,7 +122,7 @@ drop index 314159;
 ERROR:  parser: parse error at or near "314159"
 -- no such index 
 drop index nonesuch;
-ERROR:  index "nonesuch" is nonexistent
+ERROR:  index "nonesuch" does not exist
 --
 -- REMOVE AGGREGATE
  
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index 42ac65a3fe4..41263247556 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -699,7 +699,7 @@ CREATE TABLE FKTABLE_FAIL2 ( ftest1 int, CONSTRAINT fkfail1 FOREIGN KEY (ftest1)
 NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 ERROR:  UNIQUE constraint matching given keys for referenced table "pktable" not found
 DROP TABLE FKTABLE_FAIL1;
-ERROR:  table "fktable_fail1" is nonexistent
+ERROR:  table "fktable_fail1" does not exist
 DROP TABLE FKTABLE_FAIL2;
-ERROR:  table "fktable_fail2" is nonexistent
+ERROR:  table "fktable_fail2" does not exist
 DROP TABLE PKTABLE;
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index 4a91fcc96fd..527914a6757 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -3,7 +3,7 @@
 --
 -- prepare the table...
 DROP TABLE INET_TBL;
-ERROR:  table "inet_tbl" is nonexistent
+ERROR:  table "inet_tbl" does not exist
 CREATE TABLE INET_TBL (c cidr, i inet);
 INSERT INTO INET_TBL (c, i) VALUES ('192.168.1', '192.168.1.226/24');
 INSERT INTO INET_TBL (c, i) VALUES ('192.168.1.2/24', '192.168.1.226');
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index a735a2ef0bc..ac6ba3253da 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -587,7 +587,7 @@ begin
     if mytype = ''PS'' then
         select into rec * from PSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.backlink != blname then
 	    update PSlot set backlink = blname where slotname = myname;
@@ -597,7 +597,7 @@ begin
     if mytype = ''WS'' then
         select into rec * from WSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.backlink != blname then
 	    update WSlot set backlink = blname where slotname = myname;
@@ -607,7 +607,7 @@ begin
     if mytype = ''PL'' then
         select into rec * from PLine where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.backlink != blname then
 	    update PLine set backlink = blname where slotname = myname;
@@ -743,7 +743,7 @@ begin
     if mytype = ''PS'' then
         select into rec * from PSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update PSlot set slotlink = blname where slotname = myname;
@@ -753,7 +753,7 @@ begin
     if mytype = ''WS'' then
         select into rec * from WSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update WSlot set slotlink = blname where slotname = myname;
@@ -763,7 +763,7 @@ begin
     if mytype = ''IF'' then
         select into rec * from IFace where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update IFace set slotlink = blname where slotname = myname;
@@ -773,7 +773,7 @@ begin
     if mytype = ''HS'' then
         select into rec * from HSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update HSlot set slotlink = blname where slotname = myname;
@@ -783,7 +783,7 @@ begin
     if mytype = ''PH'' then
         select into rec * from PHone where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update PHone set slotlink = blname where slotname = myname;
@@ -1498,11 +1498,11 @@ select * from PField_v1 where pfname = 'PF0_2' order by slotname;
 insert into PField values ('PF1_1', 'should fail due to unique index');
 ERROR:  Cannot insert a duplicate key into unique index pfield_name
 update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
-ERROR:  WS.not.there         does not exists
+ERROR:  WS.not.there         does not exist
 update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
 ERROR:  illegal backlink beginning with XX
 update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
-ERROR:  PS.not.there         does not exists
+ERROR:  PS.not.there         does not exist
 update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
 ERROR:  illegal slotlink beginning with XX
 insert into HSlot values ('HS', 'base.hub1', 1, '');
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index aaa874c81c1..5bfda232981 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -698,7 +698,7 @@ begin
     if mytype = ''PS'' then
         select into rec * from PSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.backlink != blname then
 	    update PSlot set backlink = blname where slotname = myname;
@@ -708,7 +708,7 @@ begin
     if mytype = ''WS'' then
         select into rec * from WSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.backlink != blname then
 	    update WSlot set backlink = blname where slotname = myname;
@@ -718,7 +718,7 @@ begin
     if mytype = ''PL'' then
         select into rec * from PLine where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.backlink != blname then
 	    update PLine set backlink = blname where slotname = myname;
@@ -866,7 +866,7 @@ begin
     if mytype = ''PS'' then
         select into rec * from PSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update PSlot set slotlink = blname where slotname = myname;
@@ -876,7 +876,7 @@ begin
     if mytype = ''WS'' then
         select into rec * from WSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update WSlot set slotlink = blname where slotname = myname;
@@ -886,7 +886,7 @@ begin
     if mytype = ''IF'' then
         select into rec * from IFace where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update IFace set slotlink = blname where slotname = myname;
@@ -896,7 +896,7 @@ begin
     if mytype = ''HS'' then
         select into rec * from HSlot where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update HSlot set slotlink = blname where slotname = myname;
@@ -906,7 +906,7 @@ begin
     if mytype = ''PH'' then
         select into rec * from PHone where slotname = myname;
 	if not found then
-	    raise exception ''% does not exists'', myname;
+	    raise exception ''% does not exist'', myname;
 	end if;
 	if rec.slotlink != blname then
 	    update PHone set slotlink = blname where slotname = myname;
-- 
GitLab