 src/backend/catalog/objectaddress.c          |   38 +++-
 src/backend/commands/Makefile                |    2 +-
 src/backend/commands/collationcmds.c         |   61 -----
 src/backend/commands/conversioncmds.c        |   61 -----
 src/backend/commands/dropcmds.c              |  313 ++++++++++++++++++++++++++
 src/backend/commands/extension.c             |   63 -----
 src/backend/commands/schemacmds.c            |   63 -----
 src/backend/commands/tablecmds.c             |  248 --------------------
 src/backend/commands/tsearchcmds.c           |  254 ---------------------
 src/backend/commands/typecmds.c              |   92 --------
 src/backend/nodes/copyfuncs.c                |    1 +
 src/backend/nodes/equalfuncs.c               |    1 +
 src/backend/parser/gram.y                    |    2 +
 src/backend/tcop/utility.c                   |   57 +-----
 src/include/commands/collationcmds.h         |    1 -
 src/include/commands/conversioncmds.h        |    1 -
 src/include/commands/defrem.h                |    6 +-
 src/include/commands/extension.h             |    1 -
 src/include/commands/schemacmds.h            |    1 -
 src/include/commands/tablecmds.h             |    2 -
 src/include/commands/typecmds.h              |    1 -
 src/include/nodes/parsenodes.h               |    1 +
 src/test/regress/expected/alter_table.out    |    2 +-
 src/test/regress/expected/drop_if_exists.out |   16 +-
 src/test/regress/expected/errors.out         |    4 +-
 src/test/regress/expected/foreign_data.out   |    2 +-
 src/test/regress/expected/foreign_key.out    |    8 +-
 src/test/regress/expected/inet.out           |    2 +-
 src/test/regress/expected/prepared_xacts.out |    2 +-
 src/test/regress/expected/privileges.out     |    2 +-
 src/test/regress/expected/sequence.out       |    2 +-
 31 files changed, 375 insertions(+), 935 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 8de5bec..861eb45 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -400,17 +400,46 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 							   bool missing_ok)
 {
 	Relation	relation;
+	RangeVar   *range;
 	ObjectAddress	address;
 
+	if (lockmode != NoLock)
+		AcceptInvalidationMessages();
+
+	range = makeRangeVarFromNameList(objname);
+
 	address.classId = RelationRelationId;
-	address.objectId = InvalidOid;
+	address.objectId = RangeVarGetRelid(range, missing_ok);
 	address.objectSubId = 0;
 
-	relation = relation_openrv_extended(makeRangeVarFromNameList(objname),
-										lockmode, missing_ok);
-	if (!relation)
+	if (!OidIsValid(address.objectId))
 		return address;
 
+	/*
+	 * In DROP INDEX, attempt to acquire lock on the parent table before
+	 * locking the index.  index_drop() will need this anyway, and since
+	 * regular queries lock tables before their indexes, we risk deadlock
+	 * if we do it the other way around.  No error if we don't find a
+	 * pg_index entry, though --- that most likely means it isn't an
+	 * index, and we'll fail below.
+	 */
+	if (objtype == OBJECT_INDEX)
+	{
+		HeapTuple   tuple;
+
+		tuple = SearchSysCache1(INDEXRELID,
+								ObjectIdGetDatum(address.objectId));
+		if (HeapTupleIsValid(tuple))
+	    {
+			Form_pg_index index = (Form_pg_index) GETSTRUCT(tuple);
+
+			LockRelationOid(index->indrelid, AccessExclusiveLock);
+			ReleaseSysCache(tuple);
+		}
+	}
+
+	relation = relation_open(address.objectId, lockmode);
+
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
@@ -454,7 +483,6 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 	}
 
 	/* Done */
-	address.objectId = RelationGetRelid(relation);
 	*relp = relation;
 
 	return address;
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index 81fd658..4af7aad 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -14,7 +14,7 @@ include $(top_builddir)/src/Makefile.global
 
 OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o  \
 	collationcmds.o constraint.o conversioncmds.o copy.o \
-	dbcommands.o define.o discard.o explain.o extension.o \
+	dbcommands.o define.o discard.o dropcmds.o explain.o extension.o \
 	foreigncmds.o functioncmds.o \
 	indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
 	portalcmds.o prepare.o proclang.o \
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 7f8a108..6872e58 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -145,67 +145,6 @@ DefineCollation(List *names, List *parameters)
 }
 
 /*
- * DROP COLLATION
- */
-void
-DropCollationsCommand(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	/*
-	 * First we identify all the collations, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the collations depends on another. (Not that
-	 * that is very likely, but we may as well do this consistently.)
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *name = (List *) lfirst(cell);
-		Oid			collationOid;
-		HeapTuple	tuple;
-		Form_pg_collation coll;
-		ObjectAddress object;
-
-		collationOid = get_collation_oid(name, drop->missing_ok);
-
-		if (!OidIsValid(collationOid))
-		{
-			ereport(NOTICE,
-					(errmsg("collation \"%s\" does not exist, skipping",
-							NameListToString(name))));
-			continue;
-		}
-
-		tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationOid));
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "cache lookup failed for collation %u",
-				 collationOid);
-		coll = (Form_pg_collation) GETSTRUCT(tuple);
-
-		/* Permission check: must own collation or its namespace */
-		if (!pg_collation_ownercheck(collationOid, GetUserId()) &&
-			!pg_namespace_ownercheck(coll->collnamespace, GetUserId()))
-			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION,
-						   NameStr(coll->collname));
-
-		object.classId = CollationRelationId;
-		object.objectId = collationOid;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-
-		ReleaseSysCache(tuple);
-	}
-
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-/*
  * Rename collation
  */
 void
diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c
index 2c1c6da..8dafec9 100644
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -120,67 +120,6 @@ CreateConversionCommand(CreateConversionStmt *stmt)
 }
 
 /*
- * DROP CONVERSION
- */
-void
-DropConversionsCommand(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	/*
-	 * First we identify all the conversions, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the conversions depends on another. (Not that
-	 * that is very likely, but we may as well do this consistently.)
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *name = (List *) lfirst(cell);
-		Oid			conversionOid;
-		HeapTuple	tuple;
-		Form_pg_conversion con;
-		ObjectAddress object;
-
-		conversionOid = get_conversion_oid(name, drop->missing_ok);
-
-		if (!OidIsValid(conversionOid))
-		{
-			ereport(NOTICE,
-					(errmsg("conversion \"%s\" does not exist, skipping",
-							NameListToString(name))));
-			continue;
-		}
-
-		tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conversionOid));
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "cache lookup failed for conversion %u",
-				 conversionOid);
-		con = (Form_pg_conversion) GETSTRUCT(tuple);
-
-		/* Permission check: must own conversion or its namespace */
-		if (!pg_conversion_ownercheck(conversionOid, GetUserId()) &&
-			!pg_namespace_ownercheck(con->connamespace, GetUserId()))
-			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
-						   NameStr(con->conname));
-
-		object.classId = ConversionRelationId;
-		object.objectId = conversionOid;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-
-		ReleaseSysCache(tuple);
-	}
-
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-/*
  * Rename conversion
  */
 void
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
new file mode 100644
index 0000000..dc3e317
--- /dev/null
+++ b/src/backend/commands/dropcmds.c
@@ -0,0 +1,313 @@
+/*
+ * dropcmd.c
+ *    routine to support DROP statement commonly
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/namespace.h"
+#include "catalog/objectaddress.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_collation.h"
+#include "catalog/pg_conversion.h"
+#include "catalog/pg_extension.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_ts_config.h"
+#include "catalog/pg_ts_dict.h"
+#include "catalog/pg_ts_parser.h"
+#include "catalog/pg_ts_template.h"
+#include "catalog/pg_type.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+#include "utils/inval.h"
+#include "utils/syscache.h"
+
+static void
+notice_object_non_existent(ObjectType type, List *objname, List *objargs)
+{
+	switch (type)
+	{
+		case OBJECT_TABLE:
+			ereport(NOTICE,
+					(errmsg("table \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_INDEX:
+			ereport(NOTICE,
+					(errmsg("index \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_SEQUENCE:
+			ereport(NOTICE,
+					(errmsg("sequence \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_VIEW:
+			ereport(NOTICE,
+					(errmsg("view \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_FOREIGN_TABLE:
+			ereport(NOTICE,
+					(errmsg("foreign table \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_TYPE:
+		case OBJECT_DOMAIN:
+			{
+				TypeName   *typename = makeTypeNameFromNameList(objname);
+				ereport(NOTICE,
+						(errmsg("type \"%s\" does not exist, skipping",
+								TypeNameToString(typename))));
+			}
+			break;
+
+		case OBJECT_COLLATION:
+			ereport(NOTICE,
+					(errmsg("collation \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_CONVERSION:
+			ereport(NOTICE,
+					(errmsg("conversion \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_SCHEMA:
+			ereport(NOTICE,
+					(errmsg("schema \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_TSPARSER:
+			ereport(NOTICE,
+					(errmsg("text search parser \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_TSDICTIONARY:
+			ereport(NOTICE,
+					(errmsg("text search dictionary \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_TSTEMPLATE:
+			ereport(NOTICE,
+					(errmsg("text search template \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_TSCONFIGURATION:
+			ereport(NOTICE,
+					(errmsg("text search configuration \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		case OBJECT_EXTENSION:
+			ereport(NOTICE,
+					(errmsg("extension \"%s\" does not exist, skipping",
+							NameListToString(objname))));
+			break;
+
+		default:
+			elog(ERROR, "unrecognized drop object type: %d", (int) type);
+			break;
+	}
+}
+
+static Oid
+get_object_namespace(ObjectType type, const ObjectAddress *address)
+{
+	HeapTuple	tuple;
+	Oid			objectId = address->objectId;
+	Oid			namespaceId = InvalidOid;
+
+	switch (type)
+	{
+		case OBJECT_TABLE:
+		case OBJECT_INDEX:
+		case OBJECT_SEQUENCE:
+		case OBJECT_VIEW:
+		case OBJECT_FOREIGN_TABLE:
+			tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objectId));
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for relation %u", objectId);
+			namespaceId = ((Form_pg_class) GETSTRUCT(tuple))->relnamespace;
+			ReleaseSysCache(tuple);
+			break;
+
+		case OBJECT_TYPE:
+		case OBJECT_DOMAIN:
+			tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(objectId));
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for type %u", objectId);
+			namespaceId = ((Form_pg_type) GETSTRUCT(tuple))->typnamespace;
+			ReleaseSysCache(tuple);
+			break;
+
+		case OBJECT_COLLATION:
+			tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(objectId));
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for collation %u", objectId);
+			namespaceId = ((Form_pg_collation) GETSTRUCT(tuple))->collnamespace;
+			ReleaseSysCache(tuple);
+			break;
+
+		case OBJECT_CONVERSION:
+			tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(objectId));
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for conversion %u", objectId);
+			namespaceId = ((Form_pg_conversion) GETSTRUCT(tuple))->connamespace;
+			ReleaseSysCache(tuple);
+			break;
+
+		case OBJECT_TSPARSER:
+			tuple = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(objectId));
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for text search parser %u",
+					 objectId);
+			namespaceId = ((Form_pg_ts_parser) GETSTRUCT(tuple))->prsnamespace;
+			ReleaseSysCache(tuple);
+			break;
+
+		case OBJECT_TSDICTIONARY:
+			tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(objectId));
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for text search dictionary %u",
+					 objectId);
+			namespaceId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictnamespace;
+			ReleaseSysCache(tuple);
+			break;
+
+		case OBJECT_TSTEMPLATE:
+			tuple = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(objectId));
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for text search template %u",
+					 objectId);
+			namespaceId = ((Form_pg_ts_template) GETSTRUCT(tuple))->tmplnamespace;
+			ReleaseSysCache(tuple);
+			break;
+
+		case OBJECT_TSCONFIGURATION:
+			tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(objectId));
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for text search dictionary %u",
+					 objectId);
+			namespaceId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgnamespace;
+			ReleaseSysCache(tuple);
+			break;
+
+		default:
+			/*
+			 * The supplied object type does not have its namespace.
+			 */
+			namespaceId = InvalidOid;
+			break;
+	}
+	return namespaceId;
+}
+
+void
+RemoveObjects(DropStmt *stmt)
+{
+	ObjectAddresses *objects;
+	ListCell   *cell1;
+	ListCell   *cell2;
+
+	Assert(!stmt->arguments ||
+		   list_length(stmt->objects) == list_length(stmt->arguments));
+
+	objects = new_object_addresses();
+
+	for (cell1 = list_head(stmt->objects), cell2 = list_head(stmt->arguments);
+		 cell1 != NULL;
+		 cell1 = lnext(cell1), cell2 = (!cell2 ? NULL : lnext(cell2)))
+	{
+		ObjectAddress	address;
+		List	   *objname = lfirst(cell1);
+		List	   *objargs = (cell2 ? lfirst(cell2) : NIL);
+		Relation	relation = NULL;
+		Oid			namespaceId;
+
+		/*
+		 * Resolve object name and arguments into ObjectAddress
+		 */
+		address = get_object_address(stmt->removeType,
+									 objname, objargs,
+									 &relation,
+									 AccessExclusiveLock,
+									 stmt->missing_ok);
+
+		/*
+		 * Raise an notice, if supplied object was not found
+		 */
+		if (!OidIsValid(address.objectId))
+		{
+			notice_object_non_existent(stmt->removeType,
+									   objname, objargs);
+			continue;
+		}
+
+		/*
+		 * Permission checks
+		 */
+		namespaceId = get_object_namespace(stmt->removeType, &address);
+		if (!OidIsValid(namespaceId) ||
+			!pg_namespace_ownercheck(namespaceId, GetUserId()))
+			check_object_ownership(GetUserId(), stmt->removeType, address,
+								   objname, objargs, relation);
+
+		/*
+		 * Rest of sanity checks on objects deletion
+		 */
+		switch (stmt->removeType)
+		{
+			case OBJECT_TABLE:
+            case OBJECT_SEQUENCE:
+            case OBJECT_VIEW:
+            case OBJECT_INDEX:
+            case OBJECT_FOREIGN_TABLE:
+				if (!!allowSystemTableMods && IsSystemRelation(relation))
+					ereport(ERROR,
+							(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+						errmsg("permission denied: \"%s\" is a system catalog",
+							   RelationGetRelationName(relation))));
+				break;
+
+			default:
+				/* nothing to do */
+				break;
+		}
+
+		/*
+		 * If get_object_address() opened the relation for us, we close it
+		 * to keep the reference count correct - but we retain any locks
+		 * acquired by get_object_address() until commit time, to guard
+		 * against concurrent activities.
+		 */
+		if (relation)
+		{
+			heap_close(relation, NoLock);
+			RelationForgetRelation(address.objectId);
+		}
+
+		add_exact_object_address(&address, objects);
+	}
+	performMultipleDeletions(objects, stmt->behavior);
+
+	free_object_addresses(objects);
+}
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 08fb3d5..9ab8b1d 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1554,69 +1554,6 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
 	return extensionOid;
 }
 
-
-/*
- *	RemoveExtensions
- *		Implements DROP EXTENSION.
- */
-void
-RemoveExtensions(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	/*
-	 * First we identify all the extensions, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the extensions depends on another.
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *names = (List *) lfirst(cell);
-		char	   *extensionName;
-		Oid			extensionId;
-		ObjectAddress object;
-
-		if (list_length(names) != 1)
-			ereport(ERROR,
-					(errcode(ERRCODE_SYNTAX_ERROR),
-					 errmsg("extension name cannot be qualified")));
-		extensionName = strVal(linitial(names));
-
-		extensionId = get_extension_oid(extensionName, drop->missing_ok);
-
-		if (!OidIsValid(extensionId))
-		{
-			ereport(NOTICE,
-					(errmsg("extension \"%s\" does not exist, skipping",
-							extensionName)));
-			continue;
-		}
-
-		/* Permission check: must own extension */
-		if (!pg_extension_ownercheck(extensionId, GetUserId()))
-			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
-						   extensionName);
-
-		object.classId = ExtensionRelationId;
-		object.objectId = extensionId;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-	}
-
-	/*
-	 * Do the deletions.  Objects contained in the extension(s) are removed by
-	 * means of their dependency links to the extensions.
-	 */
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-
 /*
  * Guts of extension deletion.
  *
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 82bbf8f..3840ec0 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -147,69 +147,6 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
 	SetUserIdAndSecContext(saved_uid, save_sec_context);
 }
 
-
-/*
- *	RemoveSchemas
- *		Implements DROP SCHEMA.
- */
-void
-RemoveSchemas(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	/*
-	 * First we identify all the schemas, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the schemas depends on another.
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *names = (List *) lfirst(cell);
-		char	   *namespaceName;
-		Oid			namespaceId;
-		ObjectAddress object;
-
-		if (list_length(names) != 1)
-			ereport(ERROR,
-					(errcode(ERRCODE_SYNTAX_ERROR),
-					 errmsg("schema name cannot be qualified")));
-		namespaceName = strVal(linitial(names));
-
-		namespaceId = get_namespace_oid(namespaceName, drop->missing_ok);
-
-		if (!OidIsValid(namespaceId))
-		{
-			ereport(NOTICE,
-					(errmsg("schema \"%s\" does not exist, skipping",
-							namespaceName)));
-			continue;
-		}
-
-		/* Permission check */
-		if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
-			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
-						   namespaceName);
-
-		object.classId = NamespaceRelationId;
-		object.objectId = namespaceId;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-	}
-
-	/*
-	 * Do the deletions.  Objects contained in the schema(s) are removed by
-	 * means of their dependency links to the schema.
-	 */
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-
 /*
  * Guts of schema deletion.
  */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b2ba11c..648e781 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -182,59 +182,6 @@ typedef struct NewColumnValue
 	ExprState  *exprstate;		/* execution state */
 } NewColumnValue;
 
-/*
- * Error-reporting support for RemoveRelations
- */
-struct dropmsgstrings
-{
-	char		kind;
-	int			nonexistent_code;
-	const char *nonexistent_msg;
-	const char *skipping_msg;
-	const char *nota_msg;
-	const char *drophint_msg;
-};
-
-static const struct dropmsgstrings dropmsgstringarray[] = {
-	{RELKIND_RELATION,
-		ERRCODE_UNDEFINED_TABLE,
-		gettext_noop("table \"%s\" does not exist"),
-		gettext_noop("table \"%s\" does not exist, skipping"),
-		gettext_noop("\"%s\" is not a table"),
-	gettext_noop("Use DROP TABLE to remove a table.")},
-	{RELKIND_SEQUENCE,
-		ERRCODE_UNDEFINED_TABLE,
-		gettext_noop("sequence \"%s\" does not exist"),
-		gettext_noop("sequence \"%s\" does not exist, skipping"),
-		gettext_noop("\"%s\" is not a sequence"),
-	gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
-	{RELKIND_VIEW,
-		ERRCODE_UNDEFINED_TABLE,
-		gettext_noop("view \"%s\" does not exist"),
-		gettext_noop("view \"%s\" does not exist, skipping"),
-		gettext_noop("\"%s\" is not a view"),
-	gettext_noop("Use DROP VIEW to remove a view.")},
-	{RELKIND_INDEX,
-		ERRCODE_UNDEFINED_OBJECT,
-		gettext_noop("index \"%s\" does not exist"),
-		gettext_noop("index \"%s\" does not exist, skipping"),
-		gettext_noop("\"%s\" is not an index"),
-	gettext_noop("Use DROP INDEX to remove an index.")},
-	{RELKIND_COMPOSITE_TYPE,
-		ERRCODE_UNDEFINED_OBJECT,
-		gettext_noop("type \"%s\" does not exist"),
-		gettext_noop("type \"%s\" does not exist, skipping"),
-		gettext_noop("\"%s\" is not a type"),
-	gettext_noop("Use DROP TYPE to remove a type.")},
-	{RELKIND_FOREIGN_TABLE,
-		ERRCODE_UNDEFINED_OBJECT,
-		gettext_noop("foreign table \"%s\" does not exist"),
-		gettext_noop("foreign table \"%s\" does not exist, skipping"),
-		gettext_noop("\"%s\" is not a foreign table"),
-	gettext_noop("Use DROP FOREIGN TABLE to remove a foreign table.")},
-	{'\0', 0, NULL, NULL, NULL, NULL}
-};
-
 /* Alter table target-type flags for ATSimplePermissions */
 #define		ATT_TABLE				0x0001
 #define		ATT_VIEW				0x0002
@@ -634,201 +581,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
 }
 
 /*
- * Emit the right error or warning message for a "DROP" command issued on a
- * non-existent relation
- */
-static void
-DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
-{
-	const struct dropmsgstrings *rentry;
-
-	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
-	{
-		if (rentry->kind == rightkind)
-		{
-			if (!missing_ok)
-			{
-				ereport(ERROR,
-						(errcode(rentry->nonexistent_code),
-						 errmsg(rentry->nonexistent_msg, relname)));
-			}
-			else
-			{
-				ereport(NOTICE, (errmsg(rentry->skipping_msg, relname)));
-				break;
-			}
-		}
-	}
-
-	Assert(rentry->kind != '\0');		/* Should be impossible */
-}
-
-/*
- * Emit the right error message for a "DROP" command issued on a
- * relation of the wrong type
- */
-static void
-DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
-{
-	const struct dropmsgstrings *rentry;
-	const struct dropmsgstrings *wentry;
-
-	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
-		if (rentry->kind == rightkind)
-			break;
-	Assert(rentry->kind != '\0');
-
-	for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
-		if (wentry->kind == wrongkind)
-			break;
-	/* wrongkind could be something we don't have in our table... */
-
-	ereport(ERROR,
-			(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-			 errmsg(rentry->nota_msg, relname),
-	   (wentry->kind != '\0') ? errhint("%s", _(wentry->drophint_msg)) : 0));
-}
-
-/*
- * RemoveRelations
- *		Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
- *		DROP FOREIGN TABLE
- */
-void
-RemoveRelations(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	char		relkind;
-	ListCell   *cell;
-
-	/*
-	 * First we identify all the relations, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the relations depends on another.
-	 */
-
-	/* Determine required relkind */
-	switch (drop->removeType)
-	{
-		case OBJECT_TABLE:
-			relkind = RELKIND_RELATION;
-			break;
-
-		case OBJECT_INDEX:
-			relkind = RELKIND_INDEX;
-			break;
-
-		case OBJECT_SEQUENCE:
-			relkind = RELKIND_SEQUENCE;
-			break;
-
-		case OBJECT_VIEW:
-			relkind = RELKIND_VIEW;
-			break;
-
-		case OBJECT_FOREIGN_TABLE:
-			relkind = RELKIND_FOREIGN_TABLE;
-			break;
-
-		default:
-			elog(ERROR, "unrecognized drop object type: %d",
-				 (int) drop->removeType);
-			relkind = 0;		/* keep compiler quiet */
-			break;
-	}
-
-	/* Lock and validate each relation; build a list of object addresses */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
-		Oid			relOid;
-		HeapTuple	tuple;
-		Form_pg_class classform;
-		ObjectAddress obj;
-
-		/*
-		 * These next few steps are a great deal like relation_openrv, but we
-		 * don't bother building a relcache entry since we don't need it.
-		 *
-		 * Check for shared-cache-inval messages before trying to access the
-		 * relation.  This is needed to cover the case where the name
-		 * identifies a rel that has been dropped and recreated since the
-		 * start of our transaction: if we don't flush the old syscache entry,
-		 * then we'll latch onto that entry and suffer an error later.
-		 */
-		AcceptInvalidationMessages();
-
-		/* Look up the appropriate relation using namespace search */
-		relOid = RangeVarGetRelid(rel, true);
-
-		/* Not there? */
-		if (!OidIsValid(relOid))
-		{
-			DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
-			continue;
-		}
-
-		/*
-		 * In DROP INDEX, attempt to acquire lock on the parent table before
-		 * locking the index.  index_drop() will need this anyway, and since
-		 * regular queries lock tables before their indexes, we risk deadlock
-		 * if we do it the other way around.  No error if we don't find a
-		 * pg_index entry, though --- that most likely means it isn't an
-		 * index, and we'll fail below.
-		 */
-		if (relkind == RELKIND_INDEX)
-		{
-			tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
-			if (HeapTupleIsValid(tuple))
-			{
-				Form_pg_index index = (Form_pg_index) GETSTRUCT(tuple);
-
-				LockRelationOid(index->indrelid, AccessExclusiveLock);
-				ReleaseSysCache(tuple);
-			}
-		}
-
-		/* Get the lock before trying to fetch the syscache entry */
-		LockRelationOid(relOid, AccessExclusiveLock);
-
-		tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "cache lookup failed for relation %u", relOid);
-		classform = (Form_pg_class) GETSTRUCT(tuple);
-
-		if (classform->relkind != relkind)
-			DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
-
-		/* Allow DROP to either table owner or schema owner */
-		if (!pg_class_ownercheck(relOid, GetUserId()) &&
-			!pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
-			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
-						   rel->relname);
-
-		if (!allowSystemTableMods && IsSystemClass(classform))
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("permission denied: \"%s\" is a system catalog",
-							rel->relname)));
-
-		/* OK, we're ready to delete this one */
-		obj.classId = RelationRelationId;
-		obj.objectId = relOid;
-		obj.objectSubId = 0;
-
-		add_exact_object_address(&obj, objects);
-
-		ReleaseSysCache(tuple);
-	}
-
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-/*
  * ExecuteTruncate
  *		Executes a TRUNCATE command.
  *
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 3355eaa..197dce7 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -283,65 +283,6 @@ DefineTSParser(List *names, List *parameters)
 }
 
 /*
- * DROP TEXT SEARCH PARSER
- */
-void
-RemoveTSParsers(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to drop text search parsers")));
-
-	/*
-	 * First we identify all the objects, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the objects depends on another.
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *names = (List *) lfirst(cell);
-		Oid			prsOid;
-		ObjectAddress object;
-
-		prsOid = get_ts_parser_oid(names, true);
-
-		if (!OidIsValid(prsOid))
-		{
-			if (!drop->missing_ok)
-			{
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_OBJECT),
-						 errmsg("text search parser \"%s\" does not exist",
-								NameListToString(names))));
-			}
-			else
-			{
-				ereport(NOTICE,
-				(errmsg("text search parser \"%s\" does not exist, skipping",
-						NameListToString(names))));
-			}
-			continue;
-		}
-
-		object.classId = TSParserRelationId;
-		object.objectId = prsOid;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-	}
-
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-/*
  * Guts of TS parser deletion.
  */
 void
@@ -735,76 +676,6 @@ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
 }
 
 /*
- * DROP TEXT SEARCH DICTIONARY
- */
-void
-RemoveTSDictionaries(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	/*
-	 * First we identify all the objects, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the objects depends on another.
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *names = (List *) lfirst(cell);
-		Oid			dictOid;
-		ObjectAddress object;
-		HeapTuple	tup;
-		Oid			namespaceId;
-
-		dictOid = get_ts_dict_oid(names, true);
-
-		if (!OidIsValid(dictOid))
-		{
-			if (!drop->missing_ok)
-			{
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_OBJECT),
-					   errmsg("text search dictionary \"%s\" does not exist",
-							  NameListToString(names))));
-			}
-			else
-			{
-				ereport(NOTICE,
-						(errmsg("text search dictionary \"%s\" does not exist, skipping",
-								NameListToString(names))));
-			}
-			continue;
-		}
-
-		tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictOid));
-		if (!HeapTupleIsValid(tup))		/* should not happen */
-			elog(ERROR, "cache lookup failed for text search dictionary %u",
-				 dictOid);
-
-		/* Permission check: must own dictionary or its namespace */
-		namespaceId = ((Form_pg_ts_dict) GETSTRUCT(tup))->dictnamespace;
-		if (!pg_ts_dict_ownercheck(dictOid, GetUserId()) &&
-			!pg_namespace_ownercheck(namespaceId, GetUserId()))
-			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
-						   NameListToString(names));
-
-		object.classId = TSDictionaryRelationId;
-		object.objectId = dictOid;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-
-		ReleaseSysCache(tup);
-	}
-
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-/*
  * Guts of TS dictionary deletion.
  */
 void
@@ -1267,65 +1138,6 @@ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
 }
 
 /*
- * DROP TEXT SEARCH TEMPLATE
- */
-void
-RemoveTSTemplates(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to drop text search templates")));
-
-	/*
-	 * First we identify all the objects, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the objects depends on another.
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *names = (List *) lfirst(cell);
-		Oid			tmplOid;
-		ObjectAddress object;
-
-		tmplOid = get_ts_template_oid(names, true);
-
-		if (!OidIsValid(tmplOid))
-		{
-			if (!drop->missing_ok)
-			{
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_OBJECT),
-						 errmsg("text search template \"%s\" does not exist",
-								NameListToString(names))));
-			}
-			else
-			{
-				ereport(NOTICE,
-						(errmsg("text search template \"%s\" does not exist, skipping",
-								NameListToString(names))));
-			}
-			continue;
-		}
-
-		object.classId = TSTemplateRelationId;
-		object.objectId = tmplOid;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-	}
-
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-/*
  * Guts of TS template deletion.
  */
 void
@@ -1720,72 +1532,6 @@ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
 }
 
 /*
- * DROP TEXT SEARCH CONFIGURATION
- */
-void
-RemoveTSConfigurations(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	/*
-	 * First we identify all the objects, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the objects depends on another.
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *names = (List *) lfirst(cell);
-		Oid			cfgOid;
-		Oid			namespaceId;
-		ObjectAddress object;
-		HeapTuple	tup;
-
-		tup = GetTSConfigTuple(names);
-
-		if (!HeapTupleIsValid(tup))
-		{
-			if (!drop->missing_ok)
-			{
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_OBJECT),
-					errmsg("text search configuration \"%s\" does not exist",
-						   NameListToString(names))));
-			}
-			else
-			{
-				ereport(NOTICE,
-						(errmsg("text search configuration \"%s\" does not exist, skipping",
-								NameListToString(names))));
-			}
-			continue;
-		}
-
-		/* Permission check: must own configuration or its namespace */
-		cfgOid = HeapTupleGetOid(tup);
-		namespaceId = ((Form_pg_ts_config) GETSTRUCT(tup))->cfgnamespace;
-		if (!pg_ts_config_ownercheck(cfgOid, GetUserId()) &&
-			!pg_namespace_ownercheck(namespaceId, GetUserId()))
-			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
-						   NameListToString(names));
-
-		object.classId = TSConfigRelationId;
-		object.objectId = cfgOid;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-
-		ReleaseSysCache(tup);
-	}
-
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-/*
  * Guts of TS configuration deletion.
  */
 void
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 66c11de..fcb8395 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -616,98 +616,6 @@ DefineType(List *names, List *parameters)
 	pfree(array_type);
 }
 
-
-/*
- *	RemoveTypes
- *		Implements DROP TYPE and DROP DOMAIN
- *
- * Note: if DOMAIN is specified, we enforce that each type is a domain, but
- * we don't enforce the converse for DROP TYPE
- */
-void
-RemoveTypes(DropStmt *drop)
-{
-	ObjectAddresses *objects;
-	ListCell   *cell;
-
-	/*
-	 * First we identify all the types, then we delete them in a single
-	 * performMultipleDeletions() call.  This is to avoid unwanted DROP
-	 * RESTRICT errors if one of the types depends on another.
-	 */
-	objects = new_object_addresses();
-
-	foreach(cell, drop->objects)
-	{
-		List	   *names = (List *) lfirst(cell);
-		TypeName   *typename;
-		Oid			typeoid;
-		HeapTuple	tup;
-		ObjectAddress object;
-		Form_pg_type typ;
-
-		/* Make a TypeName so we can use standard type lookup machinery */
-		typename = makeTypeNameFromNameList(names);
-
-		/* Use LookupTypeName here so that shell types can be removed. */
-		tup = LookupTypeName(NULL, typename, NULL);
-		if (tup == NULL)
-		{
-			if (!drop->missing_ok)
-			{
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_OBJECT),
-						 errmsg("type \"%s\" does not exist",
-								TypeNameToString(typename))));
-			}
-			else
-			{
-				ereport(NOTICE,
-						(errmsg("type \"%s\" does not exist, skipping",
-								TypeNameToString(typename))));
-			}
-			continue;
-		}
-
-		typeoid = typeTypeId(tup);
-		typ = (Form_pg_type) GETSTRUCT(tup);
-
-		/* Permission check: must own type or its namespace */
-		if (!pg_type_ownercheck(typeoid, GetUserId()) &&
-			!pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
-			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
-						   format_type_be(typeoid));
-
-		if (drop->removeType == OBJECT_DOMAIN)
-		{
-			/* Check that this is actually a domain */
-			if (typ->typtype != TYPTYPE_DOMAIN)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a domain",
-								TypeNameToString(typename))));
-		}
-
-		/*
-		 * Note: we need no special check for array types here, as the normal
-		 * treatment of internal dependencies handles it just fine
-		 */
-
-		object.classId = TypeRelationId;
-		object.objectId = typeoid;
-		object.objectSubId = 0;
-
-		add_exact_object_address(&object, objects);
-
-		ReleaseSysCache(tup);
-	}
-
-	performMultipleDeletions(objects, drop->behavior);
-
-	free_object_addresses(objects);
-}
-
-
 /*
  * Guts of type deletion.
  */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index c9133dd..0bd8882 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2734,6 +2734,7 @@ _copyDropStmt(DropStmt *from)
 	DropStmt   *newnode = makeNode(DropStmt);
 
 	COPY_NODE_FIELD(objects);
+	COPY_NODE_FIELD(arguments);
 	COPY_SCALAR_FIELD(removeType);
 	COPY_SCALAR_FIELD(behavior);
 	COPY_SCALAR_FIELD(missing_ok);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3a0267c..ea972be 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1182,6 +1182,7 @@ static bool
 _equalDropStmt(DropStmt *a, DropStmt *b)
 {
 	COMPARE_NODE_FIELD(objects);
+	COMPARE_NODE_FIELD(arguments);
 	COMPARE_SCALAR_FIELD(removeType);
 	COMPARE_SCALAR_FIELD(behavior);
 	COMPARE_SCALAR_FIELD(missing_ok);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 62cff8a..9e27bf2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4721,6 +4721,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					n->removeType = $2;
 					n->missing_ok = TRUE;
 					n->objects = $5;
+					n->arguments = NIL;
 					n->behavior = $6;
 					$$ = (Node *)n;
 				}
@@ -4730,6 +4731,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					n->removeType = $2;
 					n->missing_ok = FALSE;
 					n->objects = $3;
+					n->arguments = NIL;
 					n->behavior = $4;
 					$$ = (Node *)n;
 				}
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 0559998..df13b8c 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -636,62 +636,7 @@ standard_ProcessUtility(Node *parsetree,
 			break;
 
 		case T_DropStmt:
-			{
-				DropStmt   *stmt = (DropStmt *) parsetree;
-
-				switch (stmt->removeType)
-				{
-					case OBJECT_TABLE:
-					case OBJECT_SEQUENCE:
-					case OBJECT_VIEW:
-					case OBJECT_INDEX:
-					case OBJECT_FOREIGN_TABLE:
-						RemoveRelations(stmt);
-						break;
-
-					case OBJECT_TYPE:
-					case OBJECT_DOMAIN:
-						RemoveTypes(stmt);
-						break;
-
-					case OBJECT_COLLATION:
-						DropCollationsCommand(stmt);
-						break;
-
-					case OBJECT_CONVERSION:
-						DropConversionsCommand(stmt);
-						break;
-
-					case OBJECT_SCHEMA:
-						RemoveSchemas(stmt);
-						break;
-
-					case OBJECT_TSPARSER:
-						RemoveTSParsers(stmt);
-						break;
-
-					case OBJECT_TSDICTIONARY:
-						RemoveTSDictionaries(stmt);
-						break;
-
-					case OBJECT_TSTEMPLATE:
-						RemoveTSTemplates(stmt);
-						break;
-
-					case OBJECT_TSCONFIGURATION:
-						RemoveTSConfigurations(stmt);
-						break;
-
-					case OBJECT_EXTENSION:
-						RemoveExtensions(stmt);
-						break;
-
-					default:
-						elog(ERROR, "unrecognized drop object type: %d",
-							 (int) stmt->removeType);
-						break;
-				}
-			}
+			RemoveObjects((DropStmt *) parsetree);
 			break;
 
 		case T_TruncateStmt:
diff --git a/src/include/commands/collationcmds.h b/src/include/commands/collationcmds.h
index 6dbeb75..ce4727c 100644
--- a/src/include/commands/collationcmds.h
+++ b/src/include/commands/collationcmds.h
@@ -18,7 +18,6 @@
 #include "nodes/parsenodes.h"
 
 extern void DefineCollation(List *names, List *parameters);
-extern void DropCollationsCommand(DropStmt *drop);
 extern void RenameCollation(List *name, const char *newname);
 extern void AlterCollationOwner(List *name, Oid newOwnerId);
 extern void AlterCollationOwner_oid(Oid collationOid, Oid newOwnerId);
diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h
index f77023f..c0e7cd9 100644
--- a/src/include/commands/conversioncmds.h
+++ b/src/include/commands/conversioncmds.h
@@ -18,7 +18,6 @@
 #include "nodes/parsenodes.h"
 
 extern void CreateConversionCommand(CreateConversionStmt *parsetree);
-extern void DropConversionsCommand(DropStmt *drop);
 extern void RenameConversion(List *name, const char *newname);
 extern void AlterConversionOwner(List *name, Oid newOwnerId);
 extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index bbc024f..641497b 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -16,6 +16,8 @@
 
 #include "nodes/parsenodes.h"
 
+/* commands/dropcmds.c */
+extern void RemoveObjects(DropStmt *stmt);
 
 /* commands/indexcmds.c */
 extern void DefineIndex(RangeVar *heapRelation,
@@ -116,12 +118,10 @@ extern void DefineTSParser(List *names, List *parameters);
 extern void RenameTSParser(List *oldname, const char *newname);
 extern void AlterTSParserNamespace(List *name, const char *newschema);
 extern Oid	AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
-extern void RemoveTSParsers(DropStmt *drop);
 extern void RemoveTSParserById(Oid prsId);
 
 extern void DefineTSDictionary(List *names, List *parameters);
 extern void RenameTSDictionary(List *oldname, const char *newname);
-extern void RemoveTSDictionaries(DropStmt *drop);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
@@ -132,12 +132,10 @@ extern void DefineTSTemplate(List *names, List *parameters);
 extern void RenameTSTemplate(List *oldname, const char *newname);
 extern void AlterTSTemplateNamespace(List *name, const char *newschema);
 extern Oid	AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
-extern void RemoveTSTemplates(DropStmt *stmt);
 extern void RemoveTSTemplateById(Oid tmplId);
 
 extern void DefineTSConfiguration(List *names, List *parameters);
 extern void RenameTSConfiguration(List *oldname, const char *newname);
-extern void RemoveTSConfigurations(DropStmt *stmt);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 extern void AlterTSConfigurationOwner(List *name, Oid newOwnerId);
diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h
index 2792c6d..f22ac80 100644
--- a/src/include/commands/extension.h
+++ b/src/include/commands/extension.h
@@ -29,7 +29,6 @@ extern Oid	CurrentExtensionObject;
 
 extern void CreateExtension(CreateExtensionStmt *stmt);
 
-extern void RemoveExtensions(DropStmt *stmt);
 extern void RemoveExtensionById(Oid extId);
 
 extern Oid InsertExtensionTuple(const char *extName, Oid extOwner,
diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h
index a9f8f6c..ec8d895 100644
--- a/src/include/commands/schemacmds.h
+++ b/src/include/commands/schemacmds.h
@@ -20,7 +20,6 @@
 extern void CreateSchemaCommand(CreateSchemaStmt *parsetree,
 					const char *queryString);
 
-extern void RemoveSchemas(DropStmt *drop);
 extern void RemoveSchemaById(Oid schemaOid);
 
 extern void RenameSchema(const char *oldname, const char *newname);
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 3f971eb..eb93841 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -21,8 +21,6 @@
 
 extern Oid	DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId);
 
-extern void RemoveRelations(DropStmt *drop);
-
 extern void AlterTable(AlterTableStmt *stmt);
 
 extern LOCKMODE AlterTableGetLockLevel(List *cmds);
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index 6d9d1cc..ac19015 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -20,7 +20,6 @@
 #define DEFAULT_TYPDELIM		','
 
 extern void DefineType(List *names, List *parameters);
-extern void RemoveTypes(DropStmt *drop);
 extern void RemoveTypeById(Oid typeOid);
 extern void DefineDomain(CreateDomainStmt *stmt);
 extern void DefineEnum(CreateEnumStmt *stmt);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index c65e3cd..9b4bfa1 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1916,6 +1916,7 @@ typedef struct DropStmt
 {
 	NodeTag		type;
 	List	   *objects;		/* list of sublists of names (as Values) */
+	List	   *arguments;		/* list of sublists of arguments (as Values) */
 	ObjectType	removeType;		/* object type */
 	DropBehavior behavior;		/* RESTRICT or CASCADE behavior */
 	bool		missing_ok;		/* skip error if object is missing? */
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 9ab84f9..74a16a5 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -1554,7 +1554,7 @@ create type lockmodes as enum (
 ,'AccessExclusiveLock'
 );
 drop view my_locks;
-ERROR:  view "my_locks" does not exist
+ERROR:  relation "my_locks" does not exist
 create or replace view my_locks as
 select case when c.relname like 'pg_toast%' then 'pg_toast' else c.relname end, max(mode::lockmodes) as max_lockmode
 from pg_locks l join pg_class c on l.relation = c.oid
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 2a23b4c..403bc06 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -3,37 +3,37 @@
 --
 -- table (will be really dropped at the end)
 DROP TABLE test_exists;
-ERROR:  table "test_exists" does not exist
+ERROR:  relation "test_exists" does not exist
 DROP TABLE IF EXISTS test_exists;
 NOTICE:  table "test_exists" does not exist, skipping
 CREATE TABLE test_exists (a int, b text);
 -- view
 DROP VIEW test_view_exists;
-ERROR:  view "test_view_exists" does not exist
+ERROR:  relation "test_view_exists" does not exist
 DROP VIEW IF EXISTS test_view_exists;
 NOTICE:  view "test_view_exists" does not exist, skipping
 CREATE VIEW test_view_exists AS select * from test_exists;
 DROP VIEW IF EXISTS test_view_exists;
 DROP VIEW test_view_exists;
-ERROR:  view "test_view_exists" does not exist
+ERROR:  relation "test_view_exists" does not exist
 -- index
 DROP INDEX test_index_exists;
-ERROR:  index "test_index_exists" does not exist
+ERROR:  relation "test_index_exists" does not exist
 DROP INDEX IF EXISTS test_index_exists;
 NOTICE:  index "test_index_exists" does not exist, skipping
 CREATE INDEX test_index_exists on test_exists(a);
 DROP INDEX IF EXISTS test_index_exists;
 DROP INDEX test_index_exists;
-ERROR:  index "test_index_exists" does not exist
+ERROR:  relation "test_index_exists" does not exist
 -- sequence
 DROP SEQUENCE test_sequence_exists;
-ERROR:  sequence "test_sequence_exists" does not exist
+ERROR:  relation "test_sequence_exists" does not exist
 DROP SEQUENCE IF EXISTS test_sequence_exists;
 NOTICE:  sequence "test_sequence_exists" does not exist, skipping
 CREATE SEQUENCE test_sequence_exists;
 DROP SEQUENCE IF EXISTS test_sequence_exists;
 DROP SEQUENCE test_sequence_exists;
-ERROR:  sequence "test_sequence_exists" does not exist
+ERROR:  relation "test_sequence_exists" does not exist
 -- schema
 DROP SCHEMA test_schema_exists;
 ERROR:  schema "test_schema_exists" does not exist
@@ -64,7 +64,7 @@ ERROR:  type "test_domain_exists" does not exist
 -- drop the table
 DROP TABLE IF EXISTS test_exists;
 DROP TABLE test_exists;
-ERROR:  table "test_exists" does not exist
+ERROR:  relation "test_exists" does not exist
 ---
 --- role/user/group
 ---
diff --git a/src/test/regress/expected/errors.out b/src/test/regress/expected/errors.out
index 4a10c6a..073dfec 100644
--- a/src/test/regress/expected/errors.out
+++ b/src/test/regress/expected/errors.out
@@ -76,7 +76,7 @@ LINE 1: drop table;
                   ^
 -- no such relation
 drop table nonesuch;
-ERROR:  table "nonesuch" does not exist
+ERROR:  relation "nonesuch" does not exist
 --
 -- ALTER TABLE
 -- relation renaming
@@ -146,7 +146,7 @@ LINE 1: drop index 314159;
                    ^
 -- no such index
 drop index nonesuch;
-ERROR:  index "nonesuch" does not exist
+ERROR:  relation "nonesuch" does not exist
 --
 -- DROP AGGREGATE
 -- missing aggregate name
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index def850b..9a8a6dc 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -1066,7 +1066,7 @@ ERROR:  must be owner of foreign server s9
 RESET ROLE;
 -- DROP FOREIGN TABLE
 DROP FOREIGN TABLE no_table;                                    -- ERROR
-ERROR:  foreign table "no_table" does not exist
+ERROR:  relation "no_table" does not exist
 DROP FOREIGN TABLE IF EXISTS no_table;
 NOTICE:  foreign table "no_table" does not exist, skipping
 DROP FOREIGN TABLE foreign_schema.foreign_table_1;
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index 87d573b..e7f7853 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -730,9 +730,9 @@ ERROR:  column "ftest2" referenced in foreign key constraint does not exist
 CREATE TABLE FKTABLE_FAIL2 ( ftest1 int, CONSTRAINT fkfail1 FOREIGN KEY (ftest1) REFERENCES PKTABLE(ptest2));
 ERROR:  column "ptest2" referenced in foreign key constraint does not exist
 DROP TABLE FKTABLE_FAIL1;
-ERROR:  table "fktable_fail1" does not exist
+ERROR:  relation "fktable_fail1" does not exist
 DROP TABLE FKTABLE_FAIL2;
-ERROR:  table "fktable_fail2" does not exist
+ERROR:  relation "fktable_fail2" does not exist
 DROP TABLE PKTABLE;
 -- Test for referencing column number smaller than referenced constraint
 CREATE TABLE PKTABLE (ptest1 int, ptest2 int, UNIQUE(ptest1, ptest2));
@@ -740,7 +740,7 @@ NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_ptest1_ptest2
 CREATE TABLE FKTABLE_FAIL1 (ftest1 int REFERENCES pktable(ptest1));
 ERROR:  there is no unique constraint matching given keys for referenced table "pktable"
 DROP TABLE FKTABLE_FAIL1;
-ERROR:  table "fktable_fail1" does not exist
+ERROR:  relation "fktable_fail1" does not exist
 DROP TABLE PKTABLE;
 --
 -- Tests for mismatched types
@@ -989,7 +989,7 @@ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" fo
 ERROR:  foreign key constraint "pktable_ptest2_fkey" cannot be implemented
 DETAIL:  Key columns "ptest2" and "base1" are of incompatible types: inet and integer.
 drop table pktable;
-ERROR:  table "pktable" does not exist
+ERROR:  relation "pktable" does not exist
 drop table pktable_base;
 --
 -- Deferrable constraints
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index 356a397..1a2ab6d 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" does not exist
+ERROR:  relation "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.0/26', '192.168.1.226');
diff --git a/src/test/regress/expected/prepared_xacts.out b/src/test/regress/expected/prepared_xacts.out
index 328cd74..b25768e 100644
--- a/src/test/regress/expected/prepared_xacts.out
+++ b/src/test/regress/expected/prepared_xacts.out
@@ -250,5 +250,5 @@ SELECT gid FROM pg_prepared_xacts;
 -- Clean up
 DROP TABLE pxtest2;
 DROP TABLE pxtest3;  -- will still be there if prepared xacts are disabled
-ERROR:  table "pxtest3" does not exist
+ERROR:  relation "pxtest3" does not exist
 DROP TABLE pxtest4;
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 5cda230..9100f1d 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -1228,7 +1228,7 @@ DROP VIEW atestv3 CASCADE;
 NOTICE:  drop cascades to view atestv4
 -- this should complain "does not exist"
 DROP VIEW atestv4;
-ERROR:  view "atestv4" does not exist
+ERROR:  relation "atestv4" does not exist
 DROP TABLE atest1;
 DROP TABLE atest2;
 DROP TABLE atest3;
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 968fcce..b9a5833 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -234,7 +234,7 @@ DROP SEQUENCE myseq3;
 DROP TABLE t1;
 -- Fails because no longer existent:
 DROP SEQUENCE t1_f1_seq;
-ERROR:  sequence "t1_f1_seq" does not exist
+ERROR:  relation "t1_f1_seq" does not exist
 -- Now OK:
 DROP SEQUENCE myseq2;
 --
