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