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