src/backend/catalog/objectaddress.c | 153 +++++++++++++++++--- 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 + 21 files changed, 310 insertions(+), 682 deletions(-) diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 395c116..11654e9 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 } }; @@ -635,6 +661,9 @@ get_object_address_relobject(ObjectType objtype, List *objname, get_rewrite_oid_without_relid(depname, &reloid, missing_ok); address.objectSubId = 0; + if (!OidIsValid(address.objectId)) + return address; + /* * Caller is expecting to get back the relation, even though we * didn't end up using it to find the rule. @@ -1060,3 +1089,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 ba1e2c4..c334ca9 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 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? */