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