From 82a4a777d94bec965ab2f1d04b6e6a3f0447b377 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 19 Oct 2011 23:25:20 -0400 Subject: [PATCH] Consolidate DROP handling for some object types. This gets rid of a significant amount of duplicative code. KaiGai Kohei, reviewed in earlier versions by Dimitri Fontaine, with further review and cleanup by me. --- src/backend/catalog/objectaddress.c | 409 +++++++++++++++----------- src/backend/commands/Makefile | 2 +- src/backend/commands/collationcmds.c | 61 ---- src/backend/commands/conversioncmds.c | 61 ---- src/backend/commands/dropcmds.c | 147 +++++++++ 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/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 - 17 files changed, 402 insertions(+), 828 deletions(-) create mode 100644 src/backend/commands/dropcmds.c diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 395c11605a..de2a26dada 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -66,6 +66,174 @@ #include "utils/syscache.h" #include "utils/tqual.h" +/* + * ObjectProperty + * + * This array provides a common part of system object structure; to help + * consolidate routines to handle various kind of object classes. + */ +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[] = +{ + { + CastRelationId, + CastOidIndexId, + -1, + InvalidAttrNumber + }, + { + CollationRelationId, + CollationOidIndexId, + COLLOID, + Anum_pg_collation_collnamespace + }, + { + ConstraintRelationId, + ConstraintOidIndexId, + CONSTROID, + Anum_pg_constraint_connamespace + }, + { + ConversionRelationId, + ConversionOidIndexId, + CONVOID, + Anum_pg_conversion_connamespace + }, + { + DatabaseRelationId, + DatabaseOidIndexId, + DATABASEOID, + InvalidAttrNumber + }, + { + ExtensionRelationId, + ExtensionOidIndexId, + -1, + Anum_pg_extension_extnamespace + }, + { + ForeignDataWrapperRelationId, + ForeignDataWrapperOidIndexId, + FOREIGNDATAWRAPPEROID, + InvalidAttrNumber + }, + { + ForeignServerRelationId, + ForeignServerOidIndexId, + FOREIGNSERVEROID, + InvalidAttrNumber + }, + { + ProcedureRelationId, + ProcedureOidIndexId, + PROCOID, + Anum_pg_proc_pronamespace + }, + { + LanguageRelationId, + LanguageOidIndexId, + LANGOID, + InvalidAttrNumber, + }, + { + LargeObjectMetadataRelationId, + LargeObjectMetadataOidIndexId, + -1, + InvalidAttrNumber + }, + { + OperatorClassRelationId, + OpclassOidIndexId, + CLAOID, + Anum_pg_opclass_opcnamespace, + }, + { + OperatorRelationId, + OperatorOidIndexId, + OPEROID, + Anum_pg_operator_oprnamespace + }, + { + OperatorFamilyRelationId, + OpfamilyOidIndexId, + OPFAMILYOID, + Anum_pg_opfamily_opfnamespace + }, + { + AuthIdRelationId, + AuthIdOidIndexId, + AUTHOID, + InvalidAttrNumber + }, + { + RewriteRelationId, + RewriteOidIndexId, + -1, + InvalidAttrNumber + }, + { + NamespaceRelationId, + NamespaceOidIndexId, + NAMESPACEOID, + InvalidAttrNumber + }, + { + RelationRelationId, + ClassOidIndexId, + RELOID, + Anum_pg_class_relnamespace + }, + { + TableSpaceRelationId, + TablespaceOidIndexId, + TABLESPACEOID, + InvalidAttrNumber + }, + { + TriggerRelationId, + TriggerOidIndexId, + -1, + InvalidAttrNumber + }, + { + TSConfigRelationId, + TSConfigOidIndexId, + TSCONFIGOID, + Anum_pg_ts_config_cfgnamespace + }, + { + TSDictionaryRelationId, + TSDictionaryOidIndexId, + TSDICTOID, + Anum_pg_ts_dict_dictnamespace + }, + { + TSParserRelationId, + TSParserOidIndexId, + TSPARSEROID, + Anum_pg_ts_parser_prsnamespace + }, + { + TSTemplateRelationId, + TSTemplateOidIndexId, + TSTEMPLATEOID, + Anum_pg_ts_template_tmplnamespace, + }, + { + TypeRelationId, + TypeOidIndexId, + TYPEOID, + Anum_pg_type_typnamespace + } +}; + static ObjectAddress get_object_address_unqualified(ObjectType objtype, List *qualname, bool missing_ok); static ObjectAddress get_relation_by_qualified_name(ObjectType objtype, @@ -81,148 +249,7 @@ static ObjectAddress get_object_address_type(ObjectType objtype, static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname, List *objargs, bool missing_ok); static bool object_exists(ObjectAddress address); - -/* - * ObjectProperty - * - * This array provides a common part of system object structure; to help - * consolidate routines to handle various kind of object classes. - */ -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 */ -} ObjectPropertyType; - -static ObjectPropertyType ObjectProperty[] = -{ - { - CastRelationId, - CastOidIndexId, - -1 - }, - { - CollationRelationId, - CollationOidIndexId, - COLLOID - }, - { - ConstraintRelationId, - ConstraintOidIndexId, - CONSTROID - }, - { - ConversionRelationId, - ConversionOidIndexId, - CONVOID - }, - { - DatabaseRelationId, - DatabaseOidIndexId, - DATABASEOID - }, - { - ExtensionRelationId, - ExtensionOidIndexId, - -1 - }, - { - ForeignDataWrapperRelationId, - ForeignDataWrapperOidIndexId, - FOREIGNDATAWRAPPEROID - }, - { - ForeignServerRelationId, - ForeignServerOidIndexId, - FOREIGNSERVEROID - }, - { - ProcedureRelationId, - ProcedureOidIndexId, - PROCOID - }, - { - LanguageRelationId, - LanguageOidIndexId, - LANGOID - }, - { - LargeObjectMetadataRelationId, - LargeObjectMetadataOidIndexId, - -1 - }, - { - OperatorClassRelationId, - OpclassOidIndexId, - CLAOID - }, - { - OperatorRelationId, - OperatorOidIndexId, - OPEROID - }, - { - OperatorFamilyRelationId, - OpfamilyOidIndexId, - OPFAMILYOID - }, - { - AuthIdRelationId, - AuthIdOidIndexId, - AUTHOID - }, - { - RewriteRelationId, - RewriteOidIndexId, - -1 - }, - { - NamespaceRelationId, - NamespaceOidIndexId, - NAMESPACEOID - }, - { - RelationRelationId, - ClassOidIndexId, - RELOID - }, - { - TableSpaceRelationId, - TablespaceOidIndexId, - TABLESPACEOID, - }, - { - TriggerRelationId, - TriggerOidIndexId, - -1 - }, - { - TSConfigRelationId, - TSConfigOidIndexId, - TSCONFIGOID - }, - { - TSDictionaryRelationId, - TSDictionaryOidIndexId, - TSDICTOID - }, - { - TSParserRelationId, - TSParserOidIndexId, - TSPARSEROID - }, - { - TSTemplateRelationId, - TSTemplateOidIndexId, - TSTEMPLATEOID - }, - { - TypeRelationId, - TypeOidIndexId, - TYPEOID - } -}; +static ObjectPropertyType *get_object_property_data(Oid class_id); /* * Translate an object name and arguments (as passed by the parser) to an @@ -828,6 +855,7 @@ object_exists(ObjectAddress address) ScanKeyData skey[1]; SysScanDesc sd; bool found; + ObjectPropertyType *property; /* Sub-objects require special treatment. */ if (address.objectSubId != 0) @@ -847,35 +875,22 @@ object_exists(ObjectAddress address) } return found; } - else - { - int index; - /* - * 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) - address.classId = LargeObjectMetadataRelationId; + /* + * 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) + address.classId = LargeObjectMetadataRelationId; - /* - * For object types that have a relevant syscache, we use it; for - * everything else, we'll have to do an index-scan. Search the - * ObjectProperty array to find out which it is. - */ - for (index = 0; index < lengthof(ObjectProperty); index++) - { - if (ObjectProperty[index].class_oid == address.classId) - { - cache = ObjectProperty[index].oid_catcache_id; - indexoid = ObjectProperty[index].oid_index_oid; - break; - } - } - if (index == lengthof(ObjectProperty)) - elog(ERROR, "unrecognized classid: %u", address.classId); - } + /* + * For object types that have a relevant syscache, we use it; for + * everything else, we'll have to do an index-scan. + */ + property = get_object_property_data(address.classId); + cache = property->oid_catcache_id; + indexoid = property->oid_index_oid; /* Found a syscache? */ if (cache != -1) @@ -895,7 +910,6 @@ object_exists(ObjectAddress address) return found; } - /* * Check ownership of an object previously identified by get_object_address. */ @@ -1060,3 +1074,58 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, (int) objtype); } } + +/* + * get_object_namespace + * + * Find the schema containing the specified object. For non-schema objects, + * this function returns InvalidOid. + */ +Oid +get_object_namespace(const ObjectAddress *address) +{ + int cache; + HeapTuple tuple; + bool isnull; + Oid oid; + ObjectPropertyType *property; + + /* If not owned by a namespace, just return InvalidOid. */ + property = get_object_property_data(address->classId); + if (property->attnum_namespace == InvalidAttrNumber) + return InvalidOid; + + /* Currently, we can only handle object types with system caches. */ + cache = property->oid_catcache_id; + Assert(cache != -1); + + /* Fetch tuple from syscache and extract namespace attribute. */ + tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for cache %d oid %u", + cache, address->objectId); + oid = DatumGetObjectId(SysCacheGetAttr(cache, + tuple, + property->attnum_namespace, + &isnull)); + Assert(!isnull); + ReleaseSysCache(tuple); + + return oid; +} + +/* + * Find ObjectProperty structure by class_id. + */ +static ObjectPropertyType * +get_object_property_data(Oid class_id) +{ + int index; + + for (index = 0; index < lengthof(ObjectProperty); index++) + if (ObjectProperty[index].class_oid == class_id) + return &ObjectProperty[index]; + + elog(ERROR, "unrecognized class id: %u", class_id); + return NULL; /* not reached */ +} diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 81fd6581f3..4af7aad00b 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 a0a0c7d068..20aa204403 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -144,67 +144,6 @@ DefineCollation(List *names, List *parameters) (void) pg_newlocale_from_collation(newoid); } -/* - * 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 */ diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index cd7ae600ff..7d6063de1a 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -117,67 +117,6 @@ CreateConversionCommand(CreateConversionStmt *stmt) from_encoding, to_encoding, funcoid, stmt->def); } -/* - * 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 */ diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c new file mode 100644 index 0000000000..8297730e3c --- /dev/null +++ b/src/backend/commands/dropcmds.c @@ -0,0 +1,147 @@ +/*------------------------------------------------------------------------- + * + * dropcmds.c + * handle various "DROP" operations + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/dropcmds.c + * + *------------------------------------------------------------------------- + */ + +#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" + +static void does_not_exist_skipping(ObjectType objtype, List *objname); + +/* + * Drop one or more objects. + * + * We don't currently handle all object types here. Relations, for example, + * require special handling, because (for example) indexes have additional + * locking requirements. + * + * We look up all the objects first, and then delete them in a single + * performMultipleDeletions() call. This avoids unnecessary DROP RESTRICT + * errors if there are dependencies between them. + */ +void +RemoveObjects(DropStmt *stmt) +{ + ObjectAddresses *objects; + ListCell *cell1; + + objects = new_object_addresses(); + + foreach(cell1, stmt->objects) + { + ObjectAddress address; + List *objname = lfirst(cell1); + Relation relation = NULL; + Oid namespaceId; + + /* Get an ObjectAddress for the object. */ + address = get_object_address(stmt->removeType, + objname, NIL, + &relation, + AccessExclusiveLock, + stmt->missing_ok); + + /* Issue NOTICE if supplied object was not found. */ + if (!OidIsValid(address.objectId)) + { + does_not_exist_skipping(stmt->removeType, objname); + continue; + } + + /* Check permissions. */ + namespaceId = get_object_namespace(&address); + if (!OidIsValid(namespaceId) || + !pg_namespace_ownercheck(namespaceId, GetUserId())) + check_object_ownership(GetUserId(), stmt->removeType, address, + objname, NIL, relation); + + /* Release any relcache reference count, but keep lock until commit. */ + if (relation) + heap_close(relation, NoLock); + + add_exact_object_address(&address, objects); + } + + /* Here we really delete them. */ + performMultipleDeletions(objects, stmt->behavior); + + free_object_addresses(objects); +} + +/* + * Generate a NOTICE stating that the named object was not found, and is + * being skipped. This is only relevant when "IF EXISTS" is used; otherwise, + * get_object_address() will throw an ERROR. + */ +static void +does_not_exist_skipping(ObjectType objtype, List *objname) +{ + const char *msg = NULL; + char *name = NULL; + + switch (objtype) + { + case OBJECT_TYPE: + case OBJECT_DOMAIN: + msg = gettext_noop("type \"%s\" does not exist, skipping"); + name = TypeNameToString(makeTypeNameFromNameList(objname)); + break; + case OBJECT_COLLATION: + msg = gettext_noop("collation \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_CONVERSION: + msg = gettext_noop("conversion \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_SCHEMA: + msg = gettext_noop("schema \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_TSPARSER: + msg = gettext_noop("text search parser \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_TSDICTIONARY: + msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_TSTEMPLATE: + msg = gettext_noop("text search template \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_TSCONFIGURATION: + msg = gettext_noop("text search configuration \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_EXTENSION: + msg = gettext_noop("extension \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + default: + elog(ERROR, "unexpected object type (%d)", (int)objtype); + break; + } + + ereport(NOTICE, (errmsg(msg, name))); +} diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index ba1e2c45cd..c334ca9cf8 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1563,69 +1563,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 9d1d6535fd..8daa9d0e36 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 16e6940d13..5f206d8440 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -278,65 +278,6 @@ DefineTSParser(List *names, List *parameters) heap_close(prsRel, RowExclusiveLock); } -/* - * 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. */ @@ -730,76 +671,6 @@ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid) return oldNspOid; } -/* - * 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. */ @@ -1262,65 +1133,6 @@ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid) return oldNspOid; } -/* - * 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. */ @@ -1714,72 +1526,6 @@ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid) return oldNspOid; } -/* - * 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. */ diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 7c27f85cdc..5069c5759e 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/tcop/utility.c b/src/backend/tcop/utility.c index 0749227398..a74019a0d6 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 2da6309054..eddccb8801 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 6dbeb751aa..ce4727c0f1 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 f77023ffe3..c0e7cd9d71 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 81c515ebed..64eeb73670 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 2792c6dd49..f22ac80735 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 a9f8f6cb5d..ec8d8957d9 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 23726fb0fb..429a964f91 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);