Skip to content

Commit fc6d100

Browse files
committed
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
1 parent 709aca5 commit fc6d100

21 files changed

+241
-1148
lines changed

src/backend/commands/aggregatecmds.c

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -208,58 +208,9 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
208208

209209

210210
/*
211-
* RemoveAggregate
212-
* Deletes an aggregate.
211+
* RenameAggregate
212+
* Rename an aggregate.
213213
*/
214-
void
215-
RemoveAggregate(RemoveFuncStmt *stmt)
216-
{
217-
List *aggName = stmt->name;
218-
List *aggArgs = stmt->args;
219-
Oid procOid;
220-
HeapTuple tup;
221-
ObjectAddress object;
222-
223-
/* Look up function and make sure it's an aggregate */
224-
procOid = LookupAggNameTypeNames(aggName, aggArgs, stmt->missing_ok);
225-
226-
if (!OidIsValid(procOid))
227-
{
228-
/* we only get here if stmt->missing_ok is true */
229-
ereport(NOTICE,
230-
(errmsg("aggregate %s(%s) does not exist, skipping",
231-
NameListToString(aggName),
232-
TypeNameListToString(aggArgs))));
233-
return;
234-
}
235-
236-
/*
237-
* Find the function tuple, do permissions and validity checks
238-
*/
239-
tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procOid));
240-
if (!HeapTupleIsValid(tup)) /* should not happen */
241-
elog(ERROR, "cache lookup failed for function %u", procOid);
242-
243-
/* Permission check: must own agg or its namespace */
244-
if (!pg_proc_ownercheck(procOid, GetUserId()) &&
245-
!pg_namespace_ownercheck(((Form_pg_proc) GETSTRUCT(tup))->pronamespace,
246-
GetUserId()))
247-
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
248-
NameListToString(aggName));
249-
250-
ReleaseSysCache(tup);
251-
252-
/*
253-
* Do the deletion
254-
*/
255-
object.classId = ProcedureRelationId;
256-
object.objectId = procOid;
257-
object.objectSubId = 0;
258-
259-
performDeletion(&object, stmt->behavior);
260-
}
261-
262-
263214
void
264215
RenameAggregate(List *name, List *args, const char *newname)
265216
{

src/backend/commands/dropcmds.c

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,17 @@
2020
#include "catalog/namespace.h"
2121
#include "catalog/objectaddress.h"
2222
#include "catalog/pg_class.h"
23+
#include "catalog/pg_proc.h"
2324
#include "commands/defrem.h"
2425
#include "miscadmin.h"
2526
#include "nodes/makefuncs.h"
2627
#include "parser/parse_type.h"
2728
#include "utils/acl.h"
29+
#include "utils/builtins.h"
30+
#include "utils/syscache.h"
2831

29-
static void does_not_exist_skipping(ObjectType objtype, List *objname);
32+
static void does_not_exist_skipping(ObjectType objtype,
33+
List *objname, List *objargs);
3034

3135
/*
3236
* Drop one or more objects.
@@ -44,36 +48,68 @@ RemoveObjects(DropStmt *stmt)
4448
{
4549
ObjectAddresses *objects;
4650
ListCell *cell1;
51+
ListCell *cell2 = NULL;
4752

4853
objects = new_object_addresses();
4954

5055
foreach(cell1, stmt->objects)
5156
{
5257
ObjectAddress address;
5358
List *objname = lfirst(cell1);
59+
List *objargs = NIL;
5460
Relation relation = NULL;
5561
Oid namespaceId;
5662

63+
if (stmt->arguments)
64+
{
65+
cell2 = (!cell2 ? list_head(stmt->arguments) : lnext(cell2));
66+
objargs = lfirst(cell2);
67+
}
68+
5769
/* Get an ObjectAddress for the object. */
5870
address = get_object_address(stmt->removeType,
59-
objname, NIL,
71+
objname, objargs,
6072
&relation,
6173
AccessExclusiveLock,
6274
stmt->missing_ok);
6375

6476
/* Issue NOTICE if supplied object was not found. */
6577
if (!OidIsValid(address.objectId))
6678
{
67-
does_not_exist_skipping(stmt->removeType, objname);
79+
does_not_exist_skipping(stmt->removeType, objname, objargs);
6880
continue;
6981
}
7082

83+
/*
84+
* Although COMMENT ON FUNCTION, SECURITY LABEL ON FUNCTION, etc. are
85+
* happy to operate on an aggregate as on any other function, we have
86+
* historically not allowed this for DROP FUNCTION.
87+
*/
88+
if (stmt->removeType == OBJECT_FUNCTION)
89+
{
90+
Oid funcOid = address.objectId;
91+
HeapTuple tup;
92+
93+
tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
94+
if (!HeapTupleIsValid(tup)) /* should not happen */
95+
elog(ERROR, "cache lookup failed for function %u", funcOid);
96+
97+
if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
98+
ereport(ERROR,
99+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
100+
errmsg("\"%s\" is an aggregate function",
101+
NameListToString(objname)),
102+
errhint("Use DROP AGGREGATE to drop aggregate functions.")));
103+
104+
ReleaseSysCache(tup);
105+
}
106+
71107
/* Check permissions. */
72108
namespaceId = get_object_namespace(&address);
73109
if (!OidIsValid(namespaceId) ||
74110
!pg_namespace_ownercheck(namespaceId, GetUserId()))
75111
check_object_ownership(GetUserId(), stmt->removeType, address,
76-
objname, NIL, relation);
112+
objname, objargs, relation);
77113

78114
/* Release any relcache reference count, but keep lock until commit. */
79115
if (relation)
@@ -94,10 +130,11 @@ RemoveObjects(DropStmt *stmt)
94130
* get_object_address() will throw an ERROR.
95131
*/
96132
static void
97-
does_not_exist_skipping(ObjectType objtype, List *objname)
133+
does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
98134
{
99135
const char *msg = NULL;
100136
char *name = NULL;
137+
char *args = NULL;
101138

102139
switch (objtype)
103140
{
@@ -138,10 +175,68 @@ does_not_exist_skipping(ObjectType objtype, List *objname)
138175
msg = gettext_noop("extension \"%s\" does not exist, skipping");
139176
name = NameListToString(objname);
140177
break;
178+
case OBJECT_FUNCTION:
179+
msg = gettext_noop("function %s(%s) does not exist, skipping");
180+
name = NameListToString(objname);
181+
args = TypeNameListToString(objargs);
182+
break;
183+
case OBJECT_AGGREGATE:
184+
msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
185+
name = NameListToString(objname);
186+
args = TypeNameListToString(objargs);
187+
break;
188+
case OBJECT_OPERATOR:
189+
msg = gettext_noop("operator %s does not exist, skipping");
190+
name = NameListToString(objname);
191+
break;
192+
case OBJECT_LANGUAGE:
193+
msg = gettext_noop("language \"%s\" does not exist, skipping");
194+
name = NameListToString(objname);
195+
break;
196+
case OBJECT_CAST:
197+
msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
198+
name = format_type_be(typenameTypeId(NULL,
199+
(TypeName *) linitial(objname)));
200+
args = format_type_be(typenameTypeId(NULL,
201+
(TypeName *) linitial(objargs)));
202+
break;
203+
case OBJECT_TRIGGER:
204+
msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
205+
name = strVal(llast(objname));
206+
args = NameListToString(list_truncate(objname,
207+
list_length(objname) - 1));
208+
break;
209+
case OBJECT_RULE:
210+
msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
211+
name = strVal(llast(objname));
212+
args = NameListToString(list_truncate(objname,
213+
list_length(objname) - 1));
214+
break;
215+
case OBJECT_FDW:
216+
msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
217+
name = NameListToString(objname);
218+
break;
219+
case OBJECT_FOREIGN_SERVER:
220+
msg = gettext_noop("server \"%s\" does not exist, skipping");
221+
name = NameListToString(objname);
222+
break;
223+
case OBJECT_OPCLASS:
224+
msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
225+
name = NameListToString(objname);
226+
args = strVal(linitial(objargs));
227+
break;
228+
case OBJECT_OPFAMILY:
229+
msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
230+
name = NameListToString(objname);
231+
args = strVal(linitial(objargs));
232+
break;
141233
default:
142234
elog(ERROR, "unexpected object type (%d)", (int)objtype);
143235
break;
144236
}
145237

146-
ereport(NOTICE, (errmsg(msg, name)));
238+
if (!args)
239+
ereport(NOTICE, (errmsg(msg, name)));
240+
else
241+
ereport(NOTICE, (errmsg(msg, name, args)));
147242
}

src/backend/commands/foreigncmds.c

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -685,50 +685,6 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
685685
}
686686

687687

688-
/*
689-
* Drop foreign-data wrapper
690-
*/
691-
void
692-
RemoveForeignDataWrapper(DropFdwStmt *stmt)
693-
{
694-
Oid fdwId;
695-
ObjectAddress object;
696-
697-
fdwId = get_foreign_data_wrapper_oid(stmt->fdwname, true);
698-
699-
if (!superuser())
700-
ereport(ERROR,
701-
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
702-
errmsg("permission denied to drop foreign-data wrapper \"%s\"",
703-
stmt->fdwname),
704-
errhint("Must be superuser to drop a foreign-data wrapper.")));
705-
706-
if (!OidIsValid(fdwId))
707-
{
708-
if (!stmt->missing_ok)
709-
ereport(ERROR,
710-
(errcode(ERRCODE_UNDEFINED_OBJECT),
711-
errmsg("foreign-data wrapper \"%s\" does not exist",
712-
stmt->fdwname)));
713-
714-
/* IF EXISTS specified, just note it */
715-
ereport(NOTICE,
716-
(errmsg("foreign-data wrapper \"%s\" does not exist, skipping",
717-
stmt->fdwname)));
718-
return;
719-
}
720-
721-
/*
722-
* Do the deletion
723-
*/
724-
object.classId = ForeignDataWrapperRelationId;
725-
object.objectId = fdwId;
726-
object.objectSubId = 0;
727-
728-
performDeletion(&object, stmt->behavior);
729-
}
730-
731-
732688
/*
733689
* Drop foreign-data wrapper by OID
734690
*/
@@ -957,45 +913,6 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
957913
}
958914

959915

960-
/*
961-
* Drop foreign server
962-
*/
963-
void
964-
RemoveForeignServer(DropForeignServerStmt *stmt)
965-
{
966-
Oid srvId;
967-
ObjectAddress object;
968-
969-
srvId = get_foreign_server_oid(stmt->servername, true);
970-
971-
if (!OidIsValid(srvId))
972-
{
973-
/* Server not found, complain or notice */
974-
if (!stmt->missing_ok)
975-
ereport(ERROR,
976-
(errcode(ERRCODE_UNDEFINED_OBJECT),
977-
errmsg("server \"%s\" does not exist", stmt->servername)));
978-
979-
/* IF EXISTS specified, just note it */
980-
ereport(NOTICE,
981-
(errmsg("server \"%s\" does not exist, skipping",
982-
stmt->servername)));
983-
return;
984-
}
985-
986-
/* Only allow DROP if the server is owned by the user. */
987-
if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
988-
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
989-
stmt->servername);
990-
991-
object.classId = ForeignServerRelationId;
992-
object.objectId = srvId;
993-
object.objectSubId = 0;
994-
995-
performDeletion(&object, stmt->behavior);
996-
}
997-
998-
999916
/*
1000917
* Drop foreign server by OID
1001918
*/

0 commit comments

Comments
 (0)