PostgreSQL Source Code git master
dropcmds.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * dropcmds.c
4 * handle various "DROP" operations
5 *
6 * Portions Copyright (c) 1996-2025, 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"
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
31static void does_not_exist_skipping(ObjectType objtype,
32 Node *object);
33static bool owningrel_does_not_exist_skipping(List *object,
34 const char **msg, char **name);
35static bool schema_does_not_exist_skipping(List *object,
36 const char **msg, char **name);
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 */
52void
54{
55 ObjectAddresses *objects;
56 ListCell *cell1;
57
58 objects = new_object_addresses();
59
60 foreach(cell1, stmt->objects)
61 {
62 ObjectAddress address;
63 Node *object = lfirst(cell1);
64 Relation relation = NULL;
65 Oid namespaceId;
66
67 /* Get an ObjectAddress for the object. */
68 address = get_object_address(stmt->removeType,
69 object,
70 &relation,
72 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 if (!OidIsValid(address.objectId))
80 {
81 Assert(stmt->missing_ok);
82 does_not_exist_skipping(stmt->removeType, object);
83 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 if (stmt->removeType == OBJECT_FUNCTION)
92 {
93 if (get_func_prokind(address.objectId) == PROKIND_AGGREGATE)
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 namespaceId = get_object_namespace(&address);
103 if (!OidIsValid(namespaceId) ||
104 !object_ownercheck(NamespaceRelationId, namespaceId, GetUserId()))
105 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 if (OidIsValid(namespaceId) && isTempNamespace(namespaceId))
114
115 /* Release any relcache reference count, but keep lock until commit. */
116 if (relation)
117 table_close(relation, NoLock);
118
119 add_exact_object_address(&address, objects);
120 }
121
122 /* Here we really delete them. */
123 performMultipleDeletions(objects, stmt->behavior, 0);
124
125 free_object_addresses(objects);
126}
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 */
138static bool
139owningrel_does_not_exist_skipping(List *object, const char **msg, char **name)
140{
141 List *parent_object;
142 RangeVar *parent_rel;
143
144 parent_object = list_copy_head(object, list_length(object) - 1);
145
146 if (schema_does_not_exist_skipping(parent_object, msg, name))
147 return true;
148
149 parent_rel = makeRangeVarFromNameList(parent_object);
150
151 if (!OidIsValid(RangeVarGetRelid(parent_rel, NoLock, true)))
152 {
153 *msg = gettext_noop("relation \"%s\" does not exist, skipping");
154 *name = NameListToString(parent_object);
155
156 return true;
157 }
158
159 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 */
173static bool
174schema_does_not_exist_skipping(List *object, const char **msg, char **name)
175{
176 RangeVar *rel;
177
178 rel = makeRangeVarFromNameList(object);
179
180 if (rel->schemaname != NULL &&
182 {
183 *msg = gettext_noop("schema \"%s\" does not exist, skipping");
184 *name = rel->schemaname;
185
186 return true;
187 }
188
189 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 */
205static bool
207 char **name)
208{
209 ListCell *l;
210
211 foreach(l, typenames)
212 {
213 TypeName *typeName = lfirst_node(TypeName, l);
214
215 if (typeName != NULL)
216 {
217 if (!OidIsValid(LookupTypeNameOid(NULL, typeName, true)))
218 {
219 /* type doesn't exist, try to find why */
220 if (schema_does_not_exist_skipping(typeName->names, msg, name))
221 return true;
222
223 *msg = gettext_noop("type \"%s\" does not exist, skipping");
224 *name = TypeNameToString(typeName);
225
226 return true;
227 }
228 }
229 }
230
231 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 */
242static void
244{
245 const char *msg = NULL;
246 char *name = NULL;
247 char *args = NULL;
248
249 switch (objtype)
250 {
252 msg = gettext_noop("access method \"%s\" does not exist, skipping");
253 name = strVal(object);
254 break;
255 case OBJECT_TYPE:
256 case OBJECT_DOMAIN:
257 {
258 TypeName *typ = castNode(TypeName, object);
259
260 if (!schema_does_not_exist_skipping(typ->names, &msg, &name))
261 {
262 msg = gettext_noop("type \"%s\" does not exist, skipping");
263 name = TypeNameToString(typ);
264 }
265 }
266 break;
267 case OBJECT_COLLATION:
268 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
269 {
270 msg = gettext_noop("collation \"%s\" does not exist, skipping");
272 }
273 break;
275 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
276 {
277 msg = gettext_noop("conversion \"%s\" does not exist, skipping");
279 }
280 break;
281 case OBJECT_SCHEMA:
282 msg = gettext_noop("schema \"%s\" does not exist, skipping");
283 name = strVal(object);
284 break;
286 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
287 {
288 msg = gettext_noop("statistics object \"%s\" does not exist, skipping");
290 }
291 break;
292 case OBJECT_TSPARSER:
293 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
294 {
295 msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
297 }
298 break;
300 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
301 {
302 msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
304 }
305 break;
307 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
308 {
309 msg = gettext_noop("text search template \"%s\" does not exist, skipping");
311 }
312 break;
314 if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name))
315 {
316 msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
318 }
319 break;
320 case OBJECT_EXTENSION:
321 msg = gettext_noop("extension \"%s\" does not exist, skipping");
322 name = strVal(object);
323 break;
324 case OBJECT_FUNCTION:
325 {
326 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
327
328 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
330 {
331 msg = gettext_noop("function %s(%s) does not exist, skipping");
334 }
335 break;
336 }
337 case OBJECT_PROCEDURE:
338 {
339 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
340
341 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
343 {
344 msg = gettext_noop("procedure %s(%s) does not exist, skipping");
347 }
348 break;
349 }
350 case OBJECT_ROUTINE:
351 {
352 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
353
354 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
356 {
357 msg = gettext_noop("routine %s(%s) does not exist, skipping");
360 }
361 break;
362 }
363 case OBJECT_AGGREGATE:
364 {
365 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
366
367 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
369 {
370 msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
373 }
374 break;
375 }
376 case OBJECT_OPERATOR:
377 {
378 ObjectWithArgs *owa = castNode(ObjectWithArgs, object);
379
380 if (!schema_does_not_exist_skipping(owa->objname, &msg, &name) &&
382 {
383 msg = gettext_noop("operator %s does not exist, skipping");
385 }
386 break;
387 }
388 case OBJECT_LANGUAGE:
389 msg = gettext_noop("language \"%s\" does not exist, skipping");
390 name = strVal(object);
391 break;
392 case OBJECT_CAST:
393 {
396 {
397 /* XXX quote or no quote? */
398 msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
401 }
402 }
403 break;
404 case OBJECT_TRANSFORM:
406 {
407 msg = gettext_noop("transform for type %s language \"%s\" does not exist, skipping");
409 args = strVal(lsecond(castNode(List, object)));
410 }
411 break;
412 case OBJECT_TRIGGER:
414 {
415 msg = gettext_noop("trigger \"%s\" for relation \"%s\" does not exist, skipping");
416 name = strVal(llast(castNode(List, object)));
418 list_length(castNode(List, object)) - 1));
419 }
420 break;
421 case OBJECT_POLICY:
423 {
424 msg = gettext_noop("policy \"%s\" for relation \"%s\" does not exist, skipping");
425 name = strVal(llast(castNode(List, object)));
427 list_length(castNode(List, object)) - 1));
428 }
429 break;
431 msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
432 name = strVal(object);
433 break;
434 case OBJECT_RULE:
436 {
437 msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
438 name = strVal(llast(castNode(List, object)));
440 list_length(castNode(List, object)) - 1));
441 }
442 break;
443 case OBJECT_FDW:
444 msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
445 name = strVal(object);
446 break;
448 msg = gettext_noop("server \"%s\" does not exist, skipping");
449 name = strVal(object);
450 break;
451 case OBJECT_OPCLASS:
452 {
453 List *opcname = list_copy_tail(castNode(List, object), 1);
454
455 if (!schema_does_not_exist_skipping(opcname, &msg, &name))
456 {
457 msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
458 name = NameListToString(opcname);
459 args = strVal(linitial(castNode(List, object)));
460 }
461 }
462 break;
463 case OBJECT_OPFAMILY:
464 {
465 List *opfname = list_copy_tail(castNode(List, object), 1);
466
467 if (!schema_does_not_exist_skipping(opfname, &msg, &name))
468 {
469 msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
470 name = NameListToString(opfname);
471 args = strVal(linitial(castNode(List, object)));
472 }
473 }
474 break;
476 msg = gettext_noop("publication \"%s\" does not exist, skipping");
477 name = strVal(object);
478 break;
479
480 case OBJECT_COLUMN:
481 case OBJECT_DATABASE:
483 case OBJECT_INDEX:
484 case OBJECT_MATVIEW:
485 case OBJECT_ROLE:
486 case OBJECT_SEQUENCE:
488 case OBJECT_TABLE:
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 elog(ERROR, "unsupported object type: %d", (int) objtype);
497 break;
498
499 case OBJECT_AMOP:
500 case OBJECT_AMPROC:
501 case OBJECT_ATTRIBUTE:
502 case OBJECT_DEFAULT:
503 case OBJECT_DEFACL:
511 /* These are currently not used or needed. */
512 elog(ERROR, "unsupported object type: %d", (int) objtype);
513 break;
514
515 /* no default, to let compiler warn about missing case */
516 }
517 if (!msg)
518 elog(ERROR, "unrecognized object type: %d", (int) objtype);
519
520 if (!args)
521 ereport(NOTICE, (errmsg(msg, name)));
522 else
523 ereport(NOTICE, (errmsg(msg, name, args)));
524}
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4058
#define gettext_noop(x)
Definition: c.h:1153
#define Assert(condition)
Definition: c.h:815
#define OidIsValid(objectId)
Definition: c.h:732
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
static bool type_in_list_does_not_exist_skipping(List *typenames, const char **msg, char **name)
Definition: dropcmds.c:206
void RemoveObjects(DropStmt *stmt)
Definition: dropcmds.c:53
static void does_not_exist_skipping(ObjectType objtype, Node *object)
Definition: dropcmds.c:243
static bool owningrel_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:139
static bool schema_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:174
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
#define stmt
Definition: indent_codes.h:59
const char ** typenames
Definition: lexi.c:115
List * list_copy_tail(const List *oldlist, int nskip)
Definition: list.c:1613
List * list_copy_head(const List *oldlist, int len)
Definition: list.c:1593
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
char get_func_prokind(Oid funcid)
Definition: lsyscache.c:1845
Oid GetUserId(void)
Definition: miscinit.c:517
char * NameListToString(const List *names)
Definition: namespace.c:3594
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3649
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3554
Oid LookupNamespaceNoError(const char *nspname)
Definition: namespace.c:3355
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
Oid get_object_namespace(const ObjectAddress *address)
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:478
char * TypeNameListToString(List *typenames)
Definition: parse_type.c:492
Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
Definition: parse_type.c:232
ObjectType
Definition: parsenodes.h:2311
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2326
@ OBJECT_FDW
Definition: parsenodes.h:2328
@ OBJECT_TSPARSER
Definition: parsenodes.h:2359
@ OBJECT_COLLATION
Definition: parsenodes.h:2319
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2362
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2312
@ OBJECT_OPCLASS
Definition: parsenodes.h:2336
@ OBJECT_DEFACL
Definition: parsenodes.h:2323
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2313
@ OBJECT_MATVIEW
Definition: parsenodes.h:2335
@ OBJECT_SCHEMA
Definition: parsenodes.h:2348
@ OBJECT_POLICY
Definition: parsenodes.h:2340
@ OBJECT_OPERATOR
Definition: parsenodes.h:2337
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2330
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2357
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2338
@ OBJECT_DOMAIN
Definition: parsenodes.h:2324
@ OBJECT_COLUMN
Definition: parsenodes.h:2318
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2354
@ OBJECT_ROLE
Definition: parsenodes.h:2345
@ OBJECT_ROUTINE
Definition: parsenodes.h:2346
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2334
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2343
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2341
@ OBJECT_EXTENSION
Definition: parsenodes.h:2327
@ OBJECT_INDEX
Definition: parsenodes.h:2332
@ OBJECT_DEFAULT
Definition: parsenodes.h:2322
@ OBJECT_DATABASE
Definition: parsenodes.h:2321
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2349
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2360
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2333
@ OBJECT_AMOP
Definition: parsenodes.h:2314
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2344
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2329
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2358
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2316
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2342
@ OBJECT_RULE
Definition: parsenodes.h:2347
@ OBJECT_CONVERSION
Definition: parsenodes.h:2320
@ OBJECT_AMPROC
Definition: parsenodes.h:2315
@ OBJECT_TABLE
Definition: parsenodes.h:2353
@ OBJECT_VIEW
Definition: parsenodes.h:2363
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2339
@ OBJECT_TYPE
Definition: parsenodes.h:2361
@ OBJECT_FUNCTION
Definition: parsenodes.h:2331
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2352
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2325
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2350
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2351
@ OBJECT_CAST
Definition: parsenodes.h:2317
@ OBJECT_TRIGGER
Definition: parsenodes.h:2356
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2355
#define lfirst(lc)
Definition: pg_list.h:172
#define llast(l)
Definition: pg_list.h:198
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define lsecond_node(type, l)
Definition: pg_list.h:186
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
unsigned int Oid
Definition: postgres_ext.h:32
Definition: pg_list.h:54
Definition: nodes.h:129
char * schemaname
Definition: primnodes.h:80
List * names
Definition: parsenodes.h:279
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
#define strVal(v)
Definition: value.h:82
const char * name
int MyXactFlags
Definition: xact.c:135
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102