pgsql-v9.2-drop-reworks-2.v5.patch

application/octet-stream

Filename: pgsql-v9.2-drop-reworks-2.v5.patch
Type: application/octet-stream
Part: 0
Message: Re: [v9.2] DROP statement reworks

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v9
File+
src/backend/catalog/objectaddress.c 126 24
src/backend/commands/collationcmds.c 0 61
src/backend/commands/conversioncmds.c 0 61
src/backend/commands/dropcmds.c 160 0
src/backend/commands/extension.c 0 63
src/backend/commands/Makefile 1 1
src/backend/commands/schemacmds.c 0 63
src/backend/commands/tsearchcmds.c 0 254
src/backend/commands/typecmds.c 0 92
src/backend/nodes/copyfuncs.c 1 0
src/backend/nodes/equalfuncs.c 1 0
src/backend/parser/gram.y 2 0
src/backend/tcop/utility.c 11 54
src/include/catalog/objectaddress.h 2 0
src/include/commands/collationcmds.h 0 1
src/include/commands/conversioncmds.h 0 1
src/include/commands/defrem.h 2 4
src/include/commands/extension.h 0 1
src/include/commands/schemacmds.h 0 1
src/include/commands/typecmds.h 0 1
src/include/nodes/parsenodes.h 1 0
src/test/regress/expected/drop_if_exists.out 35 0
src/test/regress/sql/drop_if_exists.sql 41 0
 src/backend/catalog/objectaddress.c          |  150 +++++++++++++---
 src/backend/commands/Makefile                |    2 +-
 src/backend/commands/collationcmds.c         |   61 ------
 src/backend/commands/conversioncmds.c        |   61 ------
 src/backend/commands/dropcmds.c              |  160 ++++++++++++++++
 src/backend/commands/extension.c             |   63 -------
 src/backend/commands/schemacmds.c            |   63 -------
 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                   |   65 +------
 src/include/catalog/objectaddress.h          |    2 +
 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/typecmds.h              |    1 -
 src/include/nodes/parsenodes.h               |    1 +
 src/test/regress/expected/drop_if_exists.out |   35 ++++
 src/test/regress/sql/drop_if_exists.sql      |   41 ++++
 23 files changed, 383 insertions(+), 682 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 84381dd..6841263 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -93,6 +93,7 @@ typedef struct
 	Oid			class_oid;			/* oid of catalog */
 	Oid			oid_index_oid; 		/* oid of index on system oid column */
 	int			oid_catcache_id;	/* id of catcache on system oid column  */
+	AttrNumber	attnum_namespace;	/* attnum of namespace field */
 } ObjectPropertyType;
 
 static ObjectPropertyType ObjectProperty[] =
@@ -100,127 +101,152 @@ static ObjectPropertyType ObjectProperty[] =
 	{
 		CastRelationId,
 		CastOidIndexId,
-		-1
+		-1,
+		InvalidAttrNumber
 	},
 	{
 		CollationRelationId,
 		CollationOidIndexId,
-		COLLOID
+		COLLOID,
+		Anum_pg_collation_collnamespace
 	},
 	{
 		ConstraintRelationId,
 		ConstraintOidIndexId,
-		CONSTROID
+		CONSTROID,
+		Anum_pg_constraint_connamespace
 	},
 	{
 		ConversionRelationId,
 		ConversionOidIndexId,
-		CONVOID
+		CONVOID,
+		Anum_pg_conversion_connamespace
 	},
 	{
 		DatabaseRelationId,
 		DatabaseOidIndexId,
-		DATABASEOID
+		DATABASEOID,
+		InvalidAttrNumber
 	},
 	{
 		ExtensionRelationId,
 		ExtensionOidIndexId,
-		-1
+		-1,
+		Anum_pg_extension_extnamespace
 	},
 	{
 		ForeignDataWrapperRelationId,
 		ForeignDataWrapperOidIndexId,
-		FOREIGNDATAWRAPPEROID
+		FOREIGNDATAWRAPPEROID,
+		InvalidAttrNumber
 	},
 	{
 		ForeignServerRelationId,
 		ForeignServerOidIndexId,
-		FOREIGNSERVEROID
+		FOREIGNSERVEROID,
+		InvalidAttrNumber
 	},
 	{
 		ProcedureRelationId,
 		ProcedureOidIndexId,
-		PROCOID
+		PROCOID,
+		Anum_pg_proc_pronamespace
 	},
 	{
 		LanguageRelationId,
 		LanguageOidIndexId,
-		LANGOID
+		LANGOID,
+		InvalidAttrNumber,
 	},
 	{
 		LargeObjectMetadataRelationId,
 		LargeObjectMetadataOidIndexId,
-		-1
+		-1,
+		InvalidAttrNumber
 	},
 	{
 		OperatorClassRelationId,
 		OpclassOidIndexId,
-		CLAOID
+		CLAOID,
+		Anum_pg_opclass_opcnamespace,
 	},
 	{
 		OperatorRelationId,
 		OperatorOidIndexId,
-		OPEROID
+		OPEROID,
+		Anum_pg_operator_oprnamespace
 	},
 	{
 		OperatorFamilyRelationId,
 		OpfamilyOidIndexId,
-		OPFAMILYOID
+		OPFAMILYOID,
+		Anum_pg_opfamily_opfnamespace
 	},
 	{
 		AuthIdRelationId,
 		AuthIdOidIndexId,
-		AUTHOID
+		AUTHOID,
+		InvalidAttrNumber
 	},
 	{
 		RewriteRelationId,
 		RewriteOidIndexId,
-		-1
+		-1,
+		InvalidAttrNumber
 	},
 	{
 		NamespaceRelationId,
 		NamespaceOidIndexId,
-		NAMESPACEOID
+		NAMESPACEOID,
+		InvalidAttrNumber
 	},
 	{
 		RelationRelationId,
 		ClassOidIndexId,
-		RELOID
+		RELOID,
+		Anum_pg_class_relnamespace
 	},
 	{
 		TableSpaceRelationId,
 		TablespaceOidIndexId,
 		TABLESPACEOID,
+		InvalidAttrNumber
 	},
 	{
 		TriggerRelationId,
 		TriggerOidIndexId,
-		-1
+		-1,
+		InvalidAttrNumber
 	},
 	{
 		TSConfigRelationId,
 		TSConfigOidIndexId,
-		TSCONFIGOID
+		TSCONFIGOID,
+		Anum_pg_ts_config_cfgnamespace
 	},
 	{
 		TSDictionaryRelationId,
 		TSDictionaryOidIndexId,
-		TSDICTOID
+		TSDICTOID,
+		Anum_pg_ts_dict_dictnamespace
 	},
 	{
 		TSParserRelationId,
 		TSParserOidIndexId,
-		TSPARSEROID
+		TSPARSEROID,
+		Anum_pg_ts_parser_prsnamespace
 	},
 	{
 		TSTemplateRelationId,
 		TSTemplateOidIndexId,
-		TSTEMPLATEOID
+		TSTEMPLATEOID,
+		Anum_pg_ts_template_tmplnamespace,
 	},
 	{
 		TypeRelationId,
 		TypeOidIndexId,
-		TYPEOID
+		TYPEOID,
+		Anum_pg_type_typnamespace
 	}
 };
 
@@ -1060,3 +1086,79 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
 				 (int) objtype);
 	}
 }
+
+/*
+ * get_object_namespace
+ *
+ * It returns OID of the namespace that owns the object specified with
+ * 'address' argument. If the required object type does not belong to
+ * a particula namespace, it returns InvalidOid.
+ */
+Oid
+get_object_namespace(const ObjectAddress *address)
+{
+	Oid			class_oid = address->classId;
+	int			index;
+	int			cache = -1;
+	AttrNumber	attnum_namespace = InvalidAttrNumber;
+	HeapTuple	tuple;
+	bool		isnull;
+	Oid			namespace_oid;
+
+	/*
+	 * Currently, attributes are the only sub-objects and it does not
+	 * owned by particular namespace.
+	 */
+	if (address->objectSubId != 0)
+	{
+		Assert(address->classId == RelationRelationId);
+
+		return InvalidOid;
+	}
+
+	/*
+	 * Weird backward compatibility hack: ObjectAddress notation uses
+	 * LargeObjectRelationId for large objects, but since PostgreSQL
+	 * 9.0, the relevant catalog is actually LargeObjectMetadataRelationId.
+	 */
+	if (address->classId == LargeObjectRelationId)
+		class_oid = LargeObjectMetadataRelationId;
+
+	for (index = 0; index < lengthof(ObjectProperty); index++)
+	{
+		if (ObjectProperty[index].class_oid == class_oid)
+		{
+			cache = ObjectProperty[index].oid_catcache_id;
+			attnum_namespace = ObjectProperty[index].attnum_namespace;
+			break;
+		}
+	}
+	if (index == lengthof(ObjectProperty))
+   		elog(ERROR, "unrecognized classid: %u", address->classId);
+
+	/*
+	 * This object type is not owned by a particular namespace
+	 */
+	if (attnum_namespace == InvalidAttrNumber)
+		return InvalidOid;
+
+	/*
+	 * XXX - Right now, we have no object types being owned by
+	 * a particular namespace; without syscache support.
+	 */
+	Assert(cache != -1);
+
+	tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for cache: %d, oid: %u",
+			 cache, address->objectId);
+
+	namespace_oid = DatumGetObjectId(SysCacheGetAttr(cache,
+													 tuple,
+													 attnum_namespace,
+													 &isnull));
+	Assert(!isnull);
+	ReleaseSysCache(tuple);
+
+	return namespace_oid;
+}
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 a0a0c7d..20aa204 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 cd7ae60..7d6063d 100644
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -118,67 +118,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..cf8792e
--- /dev/null
+++ b/src/backend/commands/dropcmds.c
@@ -0,0 +1,160 @@
+/*
+ * dropcmds.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/dependency.h"
+#include "catalog/namespace.h"
+#include "catalog/objectaddress.h"
+#include "catalog/pg_class.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+
+/*
+ * XXX - The reason why we have whole error messages instead of just only
+ * text representation of object types is to keep message translation to
+ * language other than English easy.
+ */
+static void
+DropErrorMsgNonExistent(ObjectType objtype, List *objname, List *objargs)
+{
+	const char *msgfmt = NULL;
+	char	   *marg1 = NULL;
+	char	   *marg2 = NULL;
+
+	switch (objtype)
+	{
+		case OBJECT_TYPE:
+		case OBJECT_DOMAIN:
+			msgfmt = gettext_noop("type \"%s\" does not exist, skipping");
+			marg1 = TypeNameToString(makeTypeNameFromNameList(objname));
+			break;
+		case OBJECT_COLLATION:
+			msgfmt = gettext_noop("collation \"%s\" does not exist, skipping");
+			marg1 = NameListToString(objname);
+			break;
+		case OBJECT_CONVERSION:
+			msgfmt = gettext_noop("conversion \"%s\" does not exist, skipping");
+			marg1 =  NameListToString(objname);
+			break;
+		case OBJECT_SCHEMA:
+			msgfmt = gettext_noop("schema \"%s\" does not exist, skipping");
+			marg1 = NameListToString(objname);
+			break;
+		case OBJECT_TSPARSER:
+			msgfmt = gettext_noop("text search parser \"%s\" does not exist, skipping");
+			marg1 = NameListToString(objname);
+			break;
+		case OBJECT_TSDICTIONARY:
+			msgfmt = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
+			marg1 = NameListToString(objname);
+			break;
+		case OBJECT_TSTEMPLATE:
+			msgfmt = gettext_noop("text search template \"%s\" does not exist, skipping");
+			marg1 = NameListToString(objname);
+			break;
+		case OBJECT_TSCONFIGURATION:
+			msgfmt = gettext_noop("text search configuration \"%s\" does not exist, skipping");
+			marg1 = NameListToString(objname);
+			break;
+		case OBJECT_EXTENSION:
+			msgfmt = gettext_noop("extension \"%s\" does not exist, skipping");
+			marg1 = NameListToString(objname);
+			break;
+		default:
+			elog(ERROR, "unexpected object type (%d)", (int)objtype);
+			break;
+	}
+	if (marg2 == NULL)
+		ereport(NOTICE, (errmsg(msgfmt, marg1)));
+	else
+		ereport(NOTICE, (errmsg(msgfmt, marg1, marg2)));
+}
+
+/*
+ * RemoveObjects
+ *
+ * Implements most of DROP xxx statements.
+ */
+void
+RemoveObjects(DropStmt *stmt)
+{
+	ObjectAddresses *objects;
+	ListCell   *cell1;
+	ListCell   *cell2 = NULL;
+
+	Assert(!stmt->arguments ||
+		   list_length(stmt->objects) == list_length(stmt->arguments));
+
+	objects = new_object_addresses();
+
+	foreach(cell1, stmt->objects)
+	{
+		ObjectAddress	address;
+		List	   *objname = lfirst(cell1);
+		List	   *objargs = NIL;
+		Relation	relation = NULL;
+		Oid			namespaceId;
+
+		if (stmt->arguments)
+		{
+			cell2 = (!cell2 ? list_head(stmt->arguments) : lnext(cell2));
+			objargs = lfirst(cell2);
+		}
+
+		/*
+		 * Resolve object name and arguments into ObjectAddress
+		 */
+		address = get_object_address(stmt->removeType,
+									 objname, objargs,
+									 &relation,
+									 AccessExclusiveLock,
+									 stmt->missing_ok);
+
+		/*
+		 * XXX - Unable to consolidate the code with relation types
+		 * because of a requirement to additional locks on DROP INDEX.
+		 */
+		Assert(address.classId != RelationRelationId);
+
+		/*
+		 * Raise an notice, if supplied object was not found
+		 */
+		if (!OidIsValid(address.objectId))
+		{
+			DropErrorMsgNonExistent(stmt->removeType, objname, objargs);
+			continue;
+		}
+
+		/*
+		 * Permission checks
+		 */
+		namespaceId = get_object_namespace(&address);
+		if (!OidIsValid(namespaceId) ||
+			!pg_namespace_ownercheck(namespaceId, GetUserId()))
+			check_object_ownership(GetUserId(), stmt->removeType, address,
+								   objname, objargs, relation);
+
+		/*
+		 * 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);
+
+		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 3af15dd..0b2546c 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1548,69 +1548,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 9d1d653..8daa9d0 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -146,69 +146,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/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 16e6940..5f206d8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -279,65 +279,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
@@ -731,76 +672,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
@@ -1263,65 +1134,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
@@ -1715,72 +1527,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 7c27f85..5069c57 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -618,98 +618,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 24ac529..1451fdf 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2755,6 +2755,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 4052a9a..7f7bda1 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 e9f3896..f583917 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4732,6 +4732,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;
 				}
@@ -4741,6 +4742,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 0749227..a74019a 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -644,61 +644,18 @@ standard_ProcessUtility(Node *parsetree,
 			break;
 
 		case T_DropStmt:
+			switch (((DropStmt *) parsetree)->removeType)
 			{
-				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;
-				}
+				case OBJECT_TABLE:
+				case OBJECT_SEQUENCE:
+				case OBJECT_VIEW:
+				case OBJECT_INDEX:
+				case OBJECT_FOREIGN_TABLE:
+					RemoveRelations((DropStmt *) parsetree);
+					break;
+				default:
+					RemoveObjects((DropStmt *) parsetree);
+					break;
 			}
 			break;
 
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 2da6309..eddccb8 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -35,4 +35,6 @@ extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
 					   List *objname, List *objargs, Relation relation);
 
+extern Oid	get_object_namespace(const ObjectAddress *address);
+
 #endif   /* PARSE_OBJECT_H */
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 81c515e..64eeb73 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 Oid DefineIndex(RangeVar *heapRelation,
@@ -122,12 +124,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);
@@ -138,12 +138,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/typecmds.h b/src/include/commands/typecmds.h
index 23726fb..429a964 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 9998e2f..b124d63 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1921,6 +1921,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/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 2a23b4c..def9dd2 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -89,3 +89,38 @@ DROP GROUP IF EXISTS tg1, tg2;
 NOTICE:  role "tg2" does not exist, skipping
 DROP GROUP tg1;
 ERROR:  role "tg1" does not exist
+-- collation
+DROP COLLATION test_collation_exists;
+ERROR:  collation "test_collation_exists" for encoding "UTF8" does not exist
+DROP COLLATION IF EXISTS test_collation_exists;
+NOTICE:  collation "test_collation_exists" does not exist, skipping
+-- conversion
+DROP CONVERSION test_conversion_exists;
+ERROR:  conversion "test_conversion_exists" does not exist
+DROP CONVERSION IF EXISTS test_conversion_exists;
+NOTICE:  conversion "test_conversion_exists" does not exist, skipping
+-- text search parser
+DROP TEXT SEARCH PARSER test_tsparser_exists;
+ERROR:  text search parser "test_tsparser_exists" does not exist
+DROP TEXT SEARCH PARSER IF EXISTS test_tsparser_exists;
+NOTICE:  text search parser "test_tsparser_exists" does not exist, skipping
+-- text search dictionary
+DROP TEXT SEARCH DICTIONARY test_tsdict_exists;
+ERROR:  text search dictionary "test_tsdict_exists" does not exist
+DROP TEXT SEARCH DICTIONARY IF EXISTS test_tsdict_exists;
+NOTICE:  text search dictionary "test_tsdict_exists" does not exist, skipping
+-- test search template
+DROP TEXT SEARCH TEMPLATE test_tstemplate_exists;
+ERROR:  text search template "test_tstemplate_exists" does not exist
+DROP TEXT SEARCH TEMPLATE IF EXISTS test_tstemplate_exists;
+NOTICE:  text search template "test_tstemplate_exists" does not exist, skipping
+-- text search configuration
+DROP TEXT SEARCH CONFIGURATION test_tsconfig_exists;
+ERROR:  text search configuration "test_tsconfig_exists" does not exist
+DROP TEXT SEARCH CONFIGURATION IF EXISTS test_tsconfig_exists;
+NOTICE:  text search configuration "test_tsconfig_exists" does not exist, skipping
+-- extension
+DROP EXTENSION test_extension_exists;
+ERROR:  extension "test_extension_exists" does not exist
+DROP EXTENSION IF EXISTS test_extension_exists;
+NOTICE:  extension "test_extension_exists" does not exist, skipping
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
index 3d7e46c..67a863b 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -115,3 +115,44 @@ DROP GROUP tg2;
 DROP GROUP IF EXISTS tg1, tg2;
 
 DROP GROUP tg1;
+
+-- collation
+DROP COLLATION test_collation_exists;
+DROP COLLATION IF EXISTS test_collation_exists;
+CREATE COLLATION test_collation_exists FROM "POSIX";
+DROP COLLATION test_collation_exists;
+
+-- conversion
+DROP CONVERSION test_conversion_exists;
+DROP CONVERSION IF EXISTS test_conversion_exists;
+CREATE CONVERSION test_conversion_exists
+    FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
+DROP CONVERSION test_conversion_exists;
+
+-- text search parser
+DROP TEXT SEARCH PARSER test_tsparser_exists;
+DROP TEXT SEARCH PARSER IF EXISTS test_tsparser_exists;
+
+-- text search dictionary
+DROP TEXT SEARCH DICTIONARY test_tsdict_exists;
+DROP TEXT SEARCH DICTIONARY IF EXISTS test_tsdict_exists;
+CREATE TEXT SEARCH DICTIONARY test_tsdict_exists (
+        Template=ispell,
+        DictFile=ispell_sample,
+        AffFile=ispell_sample
+);
+DROP TEXT SEARCH DICTIONARY test_tsdict_exists;
+
+-- test search template
+DROP TEXT SEARCH TEMPLATE test_tstemplate_exists;
+DROP TEXT SEARCH TEMPLATE IF EXISTS test_tstemplate_exists;
+
+-- text search configuration
+DROP TEXT SEARCH CONFIGURATION test_tsconfig_exists;
+DROP TEXT SEARCH CONFIGURATION IF EXISTS test_tsconfig_exists;
+CREATE TEXT SEARCH CONFIGURATION test_tsconfig_exists (COPY=english);
+DROP TEXT SEARCH CONFIGURATION test_tsconfig_exists;
+
+-- extension
+DROP EXTENSION test_extension_exists;
+DROP EXTENSION IF EXISTS test_extension_exists;