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