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