1 /*-------------------------------------------------------------------------
2 *
3 * dropcmds.c
4 * handle various "DROP" operations
5 *
6 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/commands/dropcmds.c
12 *
13 *-------------------------------------------------------------------------
14 */
15 #include "postgres.h"
16
17 #include "access/htup_details.h"
18 #include "access/table.h"
19 #include "access/xact.h"
20 #include "catalog/dependency.h"
21 #include "catalog/namespace.h"
22 #include "catalog/objectaddress.h"
23 #include "catalog/pg_class.h"
24 #include "catalog/pg_proc.h"
25 #include "commands/defrem.h"
26 #include "miscadmin.h"
27 #include "nodes/makefuncs.h"
28 #include "parser/parse_type.h"
29 #include "utils/acl.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/syscache.h"
33
34
35 static void does_not_exist_skipping(ObjectType objtype,
36 Node *object);
37 static bool owningrel_does_not_exist_skipping(List *object,
38 const char **msg, char **name);
39 static bool schema_does_not_exist_skipping(List *object,
40 const char **msg, char **name);
41 static bool type_in_list_does_not_exist_skipping(List *typenames,
42 const char **msg, char **name);
43
44
45 /*
46 * Drop one or more objects.
47 *
48 * We don't currently handle all object types here. Relations, for example,
49 * require special handling, because (for example) indexes have additional
50 * locking requirements.
51 *
52 * We look up all the objects first, and then delete them in a single
53 * performMultipleDeletions() call. This avoids unnecessary DROP RESTRICT
54 * errors if there are dependencies between them.
55 */
56 void
RemoveObjects(DropStmt * stmt)57 RemoveObjects(DropStmt *stmt)
58 {
59 ObjectAddresses *objects;
60 ListCell *cell1;
61
62 objects = new_object_addresses();
63
64 foreach(cell1, stmt->objects)
65 {
66 ObjectAddress address;
67 Node *object = lfirst(cell1);
68 Relation relation = NULL;
69 Oid namespaceId;
70
71 /* Get an ObjectAddress for the object. */
72 address = get_object_address(stmt->removeType,
73 object,
74 &relation,
75 AccessExclusiveLock,
76 stmt->missing_ok);
77
78 /*
79 * Issue NOTICE if supplied object was not found. Note this is only
80 * relevant in the missing_ok case, because otherwise
81 * get_object_address would have thrown an error.
82 */
83 if (!OidIsValid(address.objectId))
84 {
85 Assert(stmt->missing_ok);
86 does_not_exist_skipping(stmt->removeType, object);
87 continue;
88 }
89
90 /*
91 * Although COMMENT ON FUNCTION, SECURITY LABEL ON FUNCTION, etc. are
92 * happy to operate on an aggregate as on any other function, we have
93 * historically not allowed this for DROP FUNCTION.
94 */
95 if (stmt->removeType == OBJECT_FUNCTION)
96 {
97 if (get_func_prokind(address.objectId) == PROKIND_AGGREGATE)
98 ereport(ERROR,
99 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
100 errmsg("\"%s\" is an aggregate function",
101 NameListToString(castNode(ObjectWithArgs, object)->objname)),
102 errhint("Use DROP AGGREGATE to drop aggregate functions.")));
103 }
104
105 /* Check permissions. */
106 namespaceId = get_object_namespace(&address);
107 if (!OidIsValid(namespaceId) ||
108 !pg_namespace_ownercheck(namespaceId, GetUserId()))
109 check_object_ownership(GetUserId(), stmt->removeType, address,
110 object, relation);
111
112 /*
113 * Make note if a temporary namespace has been accessed in this
114 * transaction.
115 */
116 if (OidIsValid(namespaceId) && isTempNamespace(namespaceId))
117 MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
118
119 /* Release any relcache reference count, but keep lock until commit. */
120 if (relation)
121 table_close(relation, NoLock);
122
123 add_exact_object_address(&address, objects);
124 }
125
126 /* Here we really delete them. */
127 performMultipleDeletions(objects, stmt->behavior, 0);
128
129 free_object_addresses(objects);
130 }
131
132 /*
133 * owningrel_does_not_exist_skipping
134 * Subroutine for RemoveObjects
135 *
136 * After determining that a specification for a rule or trigger returns that
137 * the specified object does not exist, test whether its owning relation, and
138 * its schema, exist or not; if they do, return false --- the trigger or rule
139 * itself is missing instead. If the owning relation or its schema do not
140 * exist, fill the error message format string and name, and return true.
141 */
142 static bool
owningrel_does_not_exist_skipping(List * object,const char ** msg,char ** name)143 owningrel_does_not_exist_skipping(List *object, const char **msg, char **name)
144 {
145 List *parent_object;
146 RangeVar *parent_rel;
147
148 parent_object = list_truncate(list_copy(object),
149 list_length(object) - 1);
150
151 if (schema_does_not_exist_skipping(parent_object, msg, name))
152 return true;
153
154 parent_rel = makeRangeVarFromNameList(parent_object);
155
156 if (!OidIsValid(RangeVarGetRelid(parent_rel, NoLock, true)))
157 {
158 *msg = gettext_noop("relation \"%s\" does not exist, skipping");
159 *name = NameListToString(parent_object);
160
161 return true;
162 }
163
164 return false;
165 }
166
167 /*
168 * schema_does_not_exist_skipping
169 * Subroutine for RemoveObjects
170 *
171 * After determining that a specification for a schema-qualifiable object
172 * refers to an object that does not exist, test whether the specified schema
173 * exists or not. If no schema was specified, or if the schema does exist,
174 * return false -- the object itself is missing instead. If the specified
175 * schema does not exist, fill the error message format string and the
176 * specified schema name, and return true.
177 */
178 static bool
schema_does_not_exist_skipping(List * object,const char ** msg,char ** name)179 schema_does_not_exist_skipping(List *object, const char **msg, char **name)
180 {
181 RangeVar *rel;
182
183 rel = makeRangeVarFromNameList(object);
184
185 if (rel->schemaname != NULL &&
186 !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
187 {
188 *msg = gettext_noop("schema \"%s\" does not exist, skipping");
189 *name = rel->schemaname;
190
191 return true;
192 }
193
194 return false;
195 }
196
197 /*
198 * type_in_list_does_not_exist_skipping
199 * Subroutine for RemoveObjects
200 *
201 * After determining that a specification for a function, cast, aggregate or
202 * operator returns that the specified object does not exist, test whether the
203 * involved datatypes, and their schemas, exist or not; if they do, return
204 * false --- the original object itself is missing instead. If the datatypes
205 * or schemas do not exist, fill the error message format string and the
206 * missing name, and return true.
207 *
208 * First parameter is a list of TypeNames.
209 */
210 static bool
type_in_list_does_not_exist_skipping(List * typenames,const char ** msg,char ** name)211 type_in_list_does_not_exist_skipping(List *typenames, const char **msg,
212 char **name)
213 {
214 ListCell *l;
215
216 foreach(l, typenames)
217 {
218 TypeName *typeName = lfirst_node(TypeName, l);
219
220 if (typeName != NULL)
221 {
222 if (!OidIsValid(LookupTypeNameOid(NULL, typeName, true)))
223 {
224 /* type doesn't exist, try to find why */
225 if (schema_does_not_exist_skipping(typeName->names, msg, name))
226 return true;
227
228 *msg = gettext_noop("type \"%s\" does not exist, skipping");
229 *name = TypeNameToString(typeName);
230
231 return true;
232 }
233 }
234 }
235
236 return false;
237 }
238
239 /*
240 * does_not_exist_skipping
241 * Subroutine for RemoveObjects
242 *
243 * Generate a NOTICE stating that the named object was not found, and is
244 * being skipped. This is only relevant when "IF EXISTS" is used; otherwise,
245 * get_object_address() in RemoveObjects would have thrown an ERROR.
246 */
247 static void
does_not_exist_skipping(ObjectType objtype,Node * object)248 does_not_exist_skipping(ObjectType objtype, Node *object)
249 {
250 const char *msg = NULL;
251 char *name = NULL;
252 char *args = NULL;
253
254 switch (objtype)
255 {
256 case OBJECT_ACCESS_METHOD:
257 msg = gettext_noop("access method \"%s\" does not exist, skipping");
258 name = strVal((Value *) object);
259 break;
260 case OBJECT_TYPE:
261 case OBJECT_DOMAIN:
262 {
263 TypeName *typ = castNode(TypeName, object);
264
265 if (!schema_does_not_exist_skipping(typ->names, &msg, &name))
266 {
267 msg = gettext_noop("type \"%s\" does not exist, skipping");
268 name = TypeNameToString(typ);
269 }
270 }
271 break;
272 case OBJECT_COLLATION:
273 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
274 {
275 msg = gettext_noop("collation \"%s\" does not exist, skipping");
276 name = NameListToString(castNode(List, object));
277 }
278 break;
279 case OBJECT_CONVERSION:
280 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
281 {
282 msg = gettext_noop("conversion \"%s\" does not exist, skipping");
283 name = NameListToString(castNode(List, object));
284 }
285 break;
286 case OBJECT_SCHEMA:
287 msg = gettext_noop("schema \"%s\" does not exist, skipping");
288 name = strVal((Value *) object);
289 break;
290 case OBJECT_STATISTIC_EXT:
291 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
292 {
293 msg = gettext_noop("statistics object \"%s\" does not exist, skipping");
294 name = NameListToString(castNode(List, object));
295 }
296 break;
297 case OBJECT_TSPARSER:
298 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
299 {
300 msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
301 name = NameListToString(castNode(List, object));
302 }
303 break;
304 case OBJECT_TSDICTIONARY:
305 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
306 {
307 msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
308 name = NameListToString(castNode(List, object));
309 }
310 break;
311 case OBJECT_TSTEMPLATE:
312 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
313 {
314 msg = gettext_noop("text search template \"%s\" does not exist, skipping");
315 name = NameListToString(castNode(List, object));
316 }
317 break;
318 case OBJECT_TSCONFIGURATION:
319 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
320 {
321 msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
322 name = NameListToString(castNode(List, object));
323 }
324 break;
325 case OBJECT_EXTENSION:
326 msg = gettext_noop("extension \"%s\" does not exist, skipping");
327 name = strVal((Value *) object);
328 break;
329 case OBJECT_FUNCTION:
330 {
331 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
332
333 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
334 !type_in_list_does_not_exist_skipping(owa->objargs, &msg, &name))
335 {
336 msg = gettext_noop("function %s(%s) does not exist, skipping");
337 name = NameListToString(owa->objname);
338 args = TypeNameListToString(owa->objargs);
339 }
340 break;
341 }
342 case OBJECT_PROCEDURE:
343 {
344 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
345
346 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
347 !type_in_list_does_not_exist_skipping(owa->objargs, &msg, &name))
348 {
349 msg = gettext_noop("procedure %s(%s) does not exist, skipping");
350 name = NameListToString(owa->objname);
351 args = TypeNameListToString(owa->objargs);
352 }
353 break;
354 }
355 case OBJECT_ROUTINE:
356 {
357 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
358
359 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
360 !type_in_list_does_not_exist_skipping(owa->objargs, &msg, &name))
361 {
362 msg = gettext_noop("routine %s(%s) does not exist, skipping");
363 name = NameListToString(owa->objname);
364 args = TypeNameListToString(owa->objargs);
365 }
366 break;
367 }
368 case OBJECT_AGGREGATE:
369 {
370 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
371
372 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
373 !type_in_list_does_not_exist_skipping(owa->objargs, &msg, &name))
374 {
375 msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
376 name = NameListToString(owa->objname);
377 args = TypeNameListToString(owa->objargs);
378 }
379 break;
380 }
381 case OBJECT_OPERATOR:
382 {
383 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
384
385 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
386 !type_in_list_does_not_exist_skipping(owa->objargs, &msg, &name))
387 {
388 msg = gettext_noop("operator %s does not exist, skipping");
389 name = NameListToString(owa->objname);
390 }
391 break;
392 }
393 case OBJECT_LANGUAGE:
394 msg = gettext_noop("language \"%s\" does not exist, skipping");
395 name = strVal((Value *) object);
396 break;
397 case OBJECT_CAST:
398 {
399 if (!type_in_list_does_not_exist_skipping(list_make1(linitial(castNode(List, object))), &msg, &name) &&
400 !type_in_list_does_not_exist_skipping(list_make1(lsecond(castNode(List, object))), &msg, &name))
401 {
402 /* XXX quote or no quote? */
403 msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
404 name = TypeNameToString(linitial_node(TypeName, castNode(List, object)));
405 args = TypeNameToString(lsecond_node(TypeName, castNode(List, object)));
406 }
407 }
408 break;
409 case OBJECT_TRANSFORM:
410 if (!type_in_list_does_not_exist_skipping(list_make1(linitial(castNode(List, object))), &msg, &name))
411 {
412 msg = gettext_noop("transform for type %s language \"%s\" does not exist, skipping");
413 name = TypeNameToString(linitial_node(TypeName, castNode(List, object)));
414 args = strVal(lsecond(castNode(List, object)));
415 }
416 break;
417 case OBJECT_TRIGGER:
418 if (!owningrel_does_not_exist_skipping(castNode(List, object), &msg, &name))
419 {
420 msg = gettext_noop("trigger \"%s\" for relation \"%s\" does not exist, skipping");
421 name = strVal(llast(castNode(List, object)));
422 args = NameListToString(list_truncate(list_copy(castNode(List, object)),
423 list_length(castNode(List, object)) - 1));
424 }
425 break;
426 case OBJECT_POLICY:
427 if (!owningrel_does_not_exist_skipping(castNode(List, object), &msg, &name))
428 {
429 msg = gettext_noop("policy \"%s\" for relation \"%s\" does not exist, skipping");
430 name = strVal(llast(castNode(List, object)));
431 args = NameListToString(list_truncate(list_copy(castNode(List, object)),
432 list_length(castNode(List, object)) - 1));
433 }
434 break;
435 case OBJECT_EVENT_TRIGGER:
436 msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
437 name = strVal((Value *) object);
438 break;
439 case OBJECT_RULE:
440 if (!owningrel_does_not_exist_skipping(castNode(List, object), &msg, &name))
441 {
442 msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
443 name = strVal(llast(castNode(List, object)));
444 args = NameListToString(list_truncate(list_copy(castNode(List, object)),
445 list_length(castNode(List, object)) - 1));
446 }
447 break;
448 case OBJECT_FDW:
449 msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
450 name = strVal((Value *) object);
451 break;
452 case OBJECT_FOREIGN_SERVER:
453 msg = gettext_noop("server \"%s\" does not exist, skipping");
454 name = strVal((Value *) object);
455 break;
456 case OBJECT_OPCLASS:
457 {
458 List *opcname = list_copy_tail(castNode(List, object), 1);
459
460 if (!schema_does_not_exist_skipping(opcname, &msg, &name))
461 {
462 msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
463 name = NameListToString(opcname);
464 args = strVal(linitial(castNode(List, object)));
465 }
466 }
467 break;
468 case OBJECT_OPFAMILY:
469 {
470 List *opfname = list_copy_tail(castNode(List, object), 1);
471
472 if (!schema_does_not_exist_skipping(opfname, &msg, &name))
473 {
474 msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
475 name = NameListToString(opfname);
476 args = strVal(linitial(castNode(List, object)));
477 }
478 }
479 break;
480 case OBJECT_PUBLICATION:
481 msg = gettext_noop("publication \"%s\" does not exist, skipping");
482 name = strVal((Value *) object);
483 break;
484 default:
485 elog(ERROR, "unrecognized object type: %d", (int) objtype);
486 break;
487 }
488
489 if (!args)
490 ereport(NOTICE, (errmsg(msg, name)));
491 else
492 ereport(NOTICE, (errmsg(msg, name, args)));
493 }
494