mirror of
https://github.com/postgres/postgres.git
synced 2025-10-16 17:07:43 +03:00
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
This commit is contained in:
@@ -208,58 +208,9 @@ 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)
|
||||
{
|
||||
|
@@ -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)));
|
||||
}
|
||||
|
@@ -685,50 +685,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
|
||||
*/
|
||||
@@ -957,45 +913,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
|
||||
*/
|
||||
|
@@ -960,72 +960,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.
|
||||
*
|
||||
@@ -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
|
||||
*
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -290,56 +290,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.
|
||||
*/
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user