diff options
author | Robert Haas | 2011-11-18 02:31:29 +0000 |
---|---|---|
committer | Robert Haas | 2011-11-18 02:32:34 +0000 |
commit | fc6d1006bda783cc002c61a5f072905849dbde4b (patch) | |
tree | 555ab6461e7780c0f5a5f21cc80b8f7f17eb844d /src/backend/commands | |
parent | 709aca59608395eef9ceb7dcb79fd9d03a0709ef (diff) |
Further consolidation of DROP statement handling.
This gets rid of an impressive amount of duplicative code, with only
minimal behavior changes. DROP FOREIGN DATA WRAPPER now requires object
ownership rather than superuser privileges, matching the documentation
we already have. We also eliminate the historical warning about dropping
a built-in function as unuseful. All operations are now performed in the
same order for all object types handled by dropcmds.c.
KaiGai Kohei, with minor revisions by me
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/aggregatecmds.c | 53 | ||||
-rw-r--r-- | src/backend/commands/dropcmds.c | 107 | ||||
-rw-r--r-- | src/backend/commands/foreigncmds.c | 83 | ||||
-rw-r--r-- | src/backend/commands/functioncmds.c | 111 | ||||
-rw-r--r-- | src/backend/commands/opclasscmds.c | 98 | ||||
-rw-r--r-- | src/backend/commands/operatorcmds.c | 50 | ||||
-rw-r--r-- | src/backend/commands/proclang.c | 37 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 36 |
8 files changed, 103 insertions, 472 deletions
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index a2122c1d8b6..085a2059199 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -208,59 +208,10 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) /* - * RemoveAggregate - * Deletes an aggregate. + * RenameAggregate + * Rename an aggregate. */ void -RemoveAggregate(RemoveFuncStmt *stmt) -{ - List *aggName = stmt->name; - List *aggArgs = stmt->args; - Oid procOid; - HeapTuple tup; - ObjectAddress object; - - /* Look up function and make sure it's an aggregate */ - procOid = LookupAggNameTypeNames(aggName, aggArgs, stmt->missing_ok); - - if (!OidIsValid(procOid)) - { - /* we only get here if stmt->missing_ok is true */ - ereport(NOTICE, - (errmsg("aggregate %s(%s) does not exist, skipping", - NameListToString(aggName), - TypeNameListToString(aggArgs)))); - return; - } - - /* - * Find the function tuple, do permissions and validity checks - */ - tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procOid)); - if (!HeapTupleIsValid(tup)) /* should not happen */ - elog(ERROR, "cache lookup failed for function %u", procOid); - - /* Permission check: must own agg or its namespace */ - if (!pg_proc_ownercheck(procOid, GetUserId()) && - !pg_namespace_ownercheck(((Form_pg_proc) GETSTRUCT(tup))->pronamespace, - GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - NameListToString(aggName)); - - ReleaseSysCache(tup); - - /* - * Do the deletion - */ - object.classId = ProcedureRelationId; - object.objectId = procOid; - object.objectSubId = 0; - - performDeletion(&object, stmt->behavior); -} - - -void RenameAggregate(List *name, List *args, const char *newname) { Oid procOid; diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 8297730e3cf..c9f9ea921dc 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -20,13 +20,17 @@ #include "catalog/namespace.h" #include "catalog/objectaddress.h" #include "catalog/pg_class.h" +#include "catalog/pg_proc.h" #include "commands/defrem.h" #include "miscadmin.h" #include "nodes/makefuncs.h" #include "parser/parse_type.h" #include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/syscache.h" -static void does_not_exist_skipping(ObjectType objtype, List *objname); +static void does_not_exist_skipping(ObjectType objtype, + List *objname, List *objargs); /* * Drop one or more objects. @@ -44,6 +48,7 @@ RemoveObjects(DropStmt *stmt) { ObjectAddresses *objects; ListCell *cell1; + ListCell *cell2 = NULL; objects = new_object_addresses(); @@ -51,12 +56,19 @@ RemoveObjects(DropStmt *stmt) { 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); + } + /* Get an ObjectAddress for the object. */ address = get_object_address(stmt->removeType, - objname, NIL, + objname, objargs, &relation, AccessExclusiveLock, stmt->missing_ok); @@ -64,16 +76,40 @@ RemoveObjects(DropStmt *stmt) /* Issue NOTICE if supplied object was not found. */ if (!OidIsValid(address.objectId)) { - does_not_exist_skipping(stmt->removeType, objname); + does_not_exist_skipping(stmt->removeType, objname, objargs); continue; } + /* + * Although COMMENT ON FUNCTION, SECURITY LABEL ON FUNCTION, etc. are + * happy to operate on an aggregate as on any other function, we have + * historically not allowed this for DROP FUNCTION. + */ + if (stmt->removeType == OBJECT_FUNCTION) + { + Oid funcOid = address.objectId; + HeapTuple tup; + + tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid)); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for function %u", funcOid); + + if (((Form_pg_proc) GETSTRUCT(tup))->proisagg) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is an aggregate function", + NameListToString(objname)), + errhint("Use DROP AGGREGATE to drop aggregate functions."))); + + ReleaseSysCache(tup); + } + /* 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); + objname, objargs, relation); /* Release any relcache reference count, but keep lock until commit. */ if (relation) @@ -94,10 +130,11 @@ RemoveObjects(DropStmt *stmt) * get_object_address() will throw an ERROR. */ static void -does_not_exist_skipping(ObjectType objtype, List *objname) +does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs) { const char *msg = NULL; char *name = NULL; + char *args = NULL; switch (objtype) { @@ -138,10 +175,68 @@ does_not_exist_skipping(ObjectType objtype, List *objname) msg = gettext_noop("extension \"%s\" does not exist, skipping"); name = NameListToString(objname); break; + case OBJECT_FUNCTION: + msg = gettext_noop("function %s(%s) does not exist, skipping"); + name = NameListToString(objname); + args = TypeNameListToString(objargs); + break; + case OBJECT_AGGREGATE: + msg = gettext_noop("aggregate %s(%s) does not exist, skipping"); + name = NameListToString(objname); + args = TypeNameListToString(objargs); + break; + case OBJECT_OPERATOR: + msg = gettext_noop("operator %s does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_LANGUAGE: + msg = gettext_noop("language \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_CAST: + msg = gettext_noop("cast from type %s to type %s does not exist, skipping"); + name = format_type_be(typenameTypeId(NULL, + (TypeName *) linitial(objname))); + args = format_type_be(typenameTypeId(NULL, + (TypeName *) linitial(objargs))); + break; + case OBJECT_TRIGGER: + msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping"); + name = strVal(llast(objname)); + args = NameListToString(list_truncate(objname, + list_length(objname) - 1)); + break; + case OBJECT_RULE: + msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping"); + name = strVal(llast(objname)); + args = NameListToString(list_truncate(objname, + list_length(objname) - 1)); + break; + case OBJECT_FDW: + msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_FOREIGN_SERVER: + msg = gettext_noop("server \"%s\" does not exist, skipping"); + name = NameListToString(objname); + break; + case OBJECT_OPCLASS: + msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping"); + name = NameListToString(objname); + args = strVal(linitial(objargs)); + break; + case OBJECT_OPFAMILY: + msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping"); + name = NameListToString(objname); + args = strVal(linitial(objargs)); + break; default: elog(ERROR, "unexpected object type (%d)", (int)objtype); break; } - ereport(NOTICE, (errmsg(msg, name))); + if (!args) + ereport(NOTICE, (errmsg(msg, name))); + else + ereport(NOTICE, (errmsg(msg, name, args))); } diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index d9c27d187a7..b30ff409235 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -686,50 +686,6 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) /* - * Drop foreign-data wrapper - */ -void -RemoveForeignDataWrapper(DropFdwStmt *stmt) -{ - Oid fdwId; - ObjectAddress object; - - fdwId = get_foreign_data_wrapper_oid(stmt->fdwname, true); - - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied to drop foreign-data wrapper \"%s\"", - stmt->fdwname), - errhint("Must be superuser to drop a foreign-data wrapper."))); - - if (!OidIsValid(fdwId)) - { - if (!stmt->missing_ok) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("foreign-data wrapper \"%s\" does not exist", - stmt->fdwname))); - - /* IF EXISTS specified, just note it */ - ereport(NOTICE, - (errmsg("foreign-data wrapper \"%s\" does not exist, skipping", - stmt->fdwname))); - return; - } - - /* - * Do the deletion - */ - object.classId = ForeignDataWrapperRelationId; - object.objectId = fdwId; - object.objectSubId = 0; - - performDeletion(&object, stmt->behavior); -} - - -/* * Drop foreign-data wrapper by OID */ void @@ -958,45 +914,6 @@ AlterForeignServer(AlterForeignServerStmt *stmt) /* - * Drop foreign server - */ -void -RemoveForeignServer(DropForeignServerStmt *stmt) -{ - Oid srvId; - ObjectAddress object; - - srvId = get_foreign_server_oid(stmt->servername, true); - - if (!OidIsValid(srvId)) - { - /* Server not found, complain or notice */ - if (!stmt->missing_ok) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("server \"%s\" does not exist", stmt->servername))); - - /* IF EXISTS specified, just note it */ - ereport(NOTICE, - (errmsg("server \"%s\" does not exist, skipping", - stmt->servername))); - return; - } - - /* Only allow DROP if the server is owned by the user. */ - if (!pg_foreign_server_ownercheck(srvId, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER, - stmt->servername); - - object.classId = ForeignServerRelationId; - object.objectId = srvId; - object.objectSubId = 0; - - performDeletion(&object, stmt->behavior); -} - - -/* * Drop foreign server by OID */ void diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index c4746618ae5..45fdfee2175 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -961,72 +961,6 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) /* - * RemoveFunction - * Deletes a function. - */ -void -RemoveFunction(RemoveFuncStmt *stmt) -{ - List *functionName = stmt->name; - List *argTypes = stmt->args; /* list of TypeName nodes */ - Oid funcOid; - HeapTuple tup; - ObjectAddress object; - - /* - * Find the function, do permissions and validity checks - */ - funcOid = LookupFuncNameTypeNames(functionName, argTypes, stmt->missing_ok); - if (!OidIsValid(funcOid)) - { - /* can only get here if stmt->missing_ok */ - ereport(NOTICE, - (errmsg("function %s(%s) does not exist, skipping", - NameListToString(functionName), - TypeNameListToString(argTypes)))); - return; - } - - tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid)); - if (!HeapTupleIsValid(tup)) /* should not happen */ - elog(ERROR, "cache lookup failed for function %u", funcOid); - - /* Permission check: must own func or its namespace */ - if (!pg_proc_ownercheck(funcOid, GetUserId()) && - !pg_namespace_ownercheck(((Form_pg_proc) GETSTRUCT(tup))->pronamespace, - GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, - NameListToString(functionName)); - - if (((Form_pg_proc) GETSTRUCT(tup))->proisagg) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is an aggregate function", - NameListToString(functionName)), - errhint("Use DROP AGGREGATE to drop aggregate functions."))); - - if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId) - { - /* "Helpful" NOTICE when removing a builtin function ... */ - ereport(NOTICE, - (errcode(ERRCODE_WARNING), - errmsg("removing built-in function \"%s\"", - NameListToString(functionName)))); - } - - ReleaseSysCache(tup); - - /* - * Do the deletion - */ - object.classId = ProcedureRelationId; - object.objectId = funcOid; - object.objectSubId = 0; - - performDeletion(&object, stmt->behavior); -} - -/* * Guts of function deletion. * * Note: this is also used for aggregate deletion, since the OIDs of @@ -1772,51 +1706,6 @@ CreateCast(CreateCastStmt *stmt) heap_close(relation, RowExclusiveLock); } - - -/* - * DROP CAST - */ -void -DropCast(DropCastStmt *stmt) -{ - Oid sourcetypeid; - Oid targettypeid; - ObjectAddress object; - - /* when dropping a cast, the types must exist even if you use IF EXISTS */ - sourcetypeid = typenameTypeId(NULL, stmt->sourcetype); - targettypeid = typenameTypeId(NULL, stmt->targettype); - - object.classId = CastRelationId; - object.objectId = get_cast_oid(sourcetypeid, targettypeid, - stmt->missing_ok); - object.objectSubId = 0; - - if (!OidIsValid(object.objectId)) - { - ereport(NOTICE, - (errmsg("cast from type %s to type %s does not exist, skipping", - format_type_be(sourcetypeid), - format_type_be(targettypeid)))); - return; - } - - /* Permission check */ - if (!pg_type_ownercheck(sourcetypeid, GetUserId()) - && !pg_type_ownercheck(targettypeid, GetUserId())) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be owner of type %s or type %s", - format_type_be(sourcetypeid), - format_type_be(targettypeid)))); - - /* - * Do the deletion - */ - performDeletion(&object, stmt->behavior); -} - /* * get_cast_oid - given two type OIDs, look up a cast OID * diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index af0de05a032..0ef3584bb2f 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -1543,104 +1543,6 @@ dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, } } - -/* - * RemoveOpClass - * Deletes an opclass. - */ -void -RemoveOpClass(RemoveOpClassStmt *stmt) -{ - Oid amID, - opcID; - HeapTuple tuple; - ObjectAddress object; - - /* Get the access method's OID. */ - amID = get_am_oid(stmt->amname, false); - - /* Look up the opclass. */ - tuple = OpClassCacheLookup(amID, stmt->opclassname, stmt->missing_ok); - if (!HeapTupleIsValid(tuple)) - { - ereport(NOTICE, - (errmsg("operator class \"%s\" does not exist for access method \"%s\", skipping", - NameListToString(stmt->opclassname), stmt->amname))); - return; - } - - opcID = HeapTupleGetOid(tuple); - - /* Permission check: must own opclass or its namespace */ - if (!pg_opclass_ownercheck(opcID, GetUserId()) && - !pg_namespace_ownercheck(((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace, - GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, - NameListToString(stmt->opclassname)); - - ReleaseSysCache(tuple); - - /* - * Do the deletion - */ - object.classId = OperatorClassRelationId; - object.objectId = opcID; - object.objectSubId = 0; - - performDeletion(&object, stmt->behavior); -} - -/* - * RemoveOpFamily - * Deletes an opfamily. - */ -void -RemoveOpFamily(RemoveOpFamilyStmt *stmt) -{ - Oid amID, - opfID; - HeapTuple tuple; - ObjectAddress object; - - /* - * Get the access method's OID. - */ - amID = get_am_oid(stmt->amname, false); - - /* - * Look up the opfamily. - */ - tuple = OpFamilyCacheLookup(amID, stmt->opfamilyname, stmt->missing_ok); - if (!HeapTupleIsValid(tuple)) - { - ereport(NOTICE, - (errmsg("operator family \"%s\" does not exist for access method \"%s\", skipping", - NameListToString(stmt->opfamilyname), stmt->amname))); - return; - } - - opfID = HeapTupleGetOid(tuple); - - /* Permission check: must own opfamily or its namespace */ - if (!pg_opfamily_ownercheck(opfID, GetUserId()) && - !pg_namespace_ownercheck(((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace, - GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY, - NameListToString(stmt->opfamilyname)); - - ReleaseSysCache(tuple); - - /* - * Do the deletion - */ - object.classId = OperatorFamilyRelationId; - object.objectId = opfID; - object.objectSubId = 0; - - performDeletion(&object, stmt->behavior); -} - - /* * Deletion subroutines for use by dependency.c. */ diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index c5c18ee4fcc..1e6c5ce2ad7 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -291,56 +291,6 @@ DefineOperator(List *names, List *parameters) /* - * RemoveOperator - * Deletes an operator. - */ -void -RemoveOperator(RemoveFuncStmt *stmt) -{ - List *operatorName = stmt->name; - TypeName *typeName1 = (TypeName *) linitial(stmt->args); - TypeName *typeName2 = (TypeName *) lsecond(stmt->args); - Oid operOid; - HeapTuple tup; - ObjectAddress object; - - Assert(list_length(stmt->args) == 2); - operOid = LookupOperNameTypeNames(NULL, operatorName, - typeName1, typeName2, - stmt->missing_ok, -1); - - if (stmt->missing_ok && !OidIsValid(operOid)) - { - ereport(NOTICE, - (errmsg("operator %s does not exist, skipping", - NameListToString(operatorName)))); - return; - } - - tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); - if (!HeapTupleIsValid(tup)) /* should not happen */ - elog(ERROR, "cache lookup failed for operator %u", operOid); - - /* Permission check: must own operator or its namespace */ - if (!pg_oper_ownercheck(operOid, GetUserId()) && - !pg_namespace_ownercheck(((Form_pg_operator) GETSTRUCT(tup))->oprnamespace, - GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, - NameListToString(operatorName)); - - ReleaseSysCache(tup); - - /* - * Do the deletion - */ - object.classId = OperatorRelationId; - object.objectId = operOid; - object.objectSubId = 0; - - performDeletion(&object, stmt->behavior); -} - -/* * Guts of operator deletion. */ void diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 7a37e96c402..e4cd2ab33d1 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -507,43 +507,6 @@ PLTemplateExists(const char *languageName) return (find_language_template(languageName) != NULL); } - -/* --------------------------------------------------------------------- - * DROP PROCEDURAL LANGUAGE - * --------------------------------------------------------------------- - */ -void -DropProceduralLanguage(DropPLangStmt *stmt) -{ - Oid oid; - ObjectAddress object; - - oid = get_language_oid(stmt->plname, stmt->missing_ok); - if (!OidIsValid(oid)) - { - ereport(NOTICE, - (errmsg("language \"%s\" does not exist, skipping", - stmt->plname))); - return; - } - - /* - * Check permission - */ - if (!pg_language_ownercheck(oid, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE, - stmt->plname); - - object.classId = LanguageRelationId; - object.objectId = oid; - object.objectSubId = 0; - - /* - * Do the deletion - */ - performDeletion(&object, stmt->behavior); -} - /* * Guts of language dropping. */ diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index a6e7268aa78..5589528e5ca 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -1026,42 +1026,6 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) } } - -/* - * DropTrigger - drop an individual trigger by name - */ -void -DropTrigger(RangeVar *relation, const char *trigname, DropBehavior behavior, - bool missing_ok) -{ - Oid relid; - ObjectAddress object; - - /* lock level should match RemoveTriggerById */ - relid = RangeVarGetRelid(relation, AccessExclusiveLock, false, false); - - object.classId = TriggerRelationId; - object.objectId = get_trigger_oid(relid, trigname, missing_ok); - object.objectSubId = 0; - - if (!OidIsValid(object.objectId)) - { - ereport(NOTICE, - (errmsg("trigger \"%s\" for table \"%s\" does not exist, skipping", - trigname, get_rel_name(relid)))); - return; - } - - if (!pg_class_ownercheck(relid, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - get_rel_name(relid)); - - /* - * Do the deletion - */ - performDeletion(&object, behavior); -} - /* * Guts of trigger deletion. */ |