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-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
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,
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))
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
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
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 &&
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
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
249 {
250  const char *msg = NULL;
251  char *name = NULL;
252  char *args = NULL;
253 
254  switch (objtype)
255  {
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;
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;
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) &&
401  {
402  /* XXX quote or no quote? */
403  msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
406  }
407  }
408  break;
409  case OBJECT_TRANSFORM:
411  {
412  msg = gettext_noop("transform for type %s language \"%s\" does not exist, skipping");
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)));
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)));
432  list_length(castNode(List, object)) - 1));
433  }
434  break;
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)));
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;
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 }
static bool schema_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:179
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1071
List * names
Definition: parsenodes.h:209
Oid GetUserId(void)
Definition: miscinit.c:439
#define castNode(_type_, nodeptr)
Definition: nodes.h:595
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:78
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:476
List * objects
Definition: parsenodes.h:2651
bool missing_ok
Definition: parsenodes.h:2654
#define llast(l)
Definition: pg_list.h:215
List * list_truncate(List *list, int new_size)
Definition: list.c:586
#define gettext_noop(x)
Definition: c.h:1160
List * list_copy(const List *oldlist)
Definition: list.c:1404
Definition: nodes.h:526
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:610
char * TypeNameListToString(List *typenames)
Definition: parse_type.c:490
bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
Definition: aclchk.c:4929
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3062
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2470
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2415
List * list_copy_tail(const List *oldlist, int nskip)
Definition: list.c:1423
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2710
unsigned int Oid
Definition: postgres_ext.h:31
void RemoveObjects(DropStmt *stmt)
Definition: dropcmds.c:57
#define linitial_node(type, l)
Definition: pg_list.h:198
#define OidIsValid(objectId)
Definition: c.h:644
#define lsecond(l)
Definition: pg_list.h:200
ObjectType removeType
Definition: parsenodes.h:2652
char * schemaname
Definition: primnodes.h:67
#define list_make1(x1)
Definition: pg_list.h:227
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define NoLock
Definition: lockdefs.h:34
DropBehavior behavior
Definition: parsenodes.h:2653
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3157
ObjectType
Definition: parsenodes.h:1690
int MyXactFlags
Definition: xact.c:118
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:97
char * NameListToString(List *names)
Definition: namespace.c:3102
char get_func_prokind(Oid funcid)
Definition: lsyscache.c:1646
#define lsecond_node(type, l)
Definition: pg_list.h:203
static bool type_in_list_does_not_exist_skipping(List *typenames, const char **msg, char **name)
Definition: dropcmds.c:211
static bool owningrel_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:143
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
Definition: value.h:42
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
static int list_length(const List *l)
Definition: pg_list.h:169
const char * name
Definition: encode.c:521
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
Oid get_object_namespace(const ObjectAddress *address)
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:375
Definition: pg_list.h:50
static void does_not_exist_skipping(ObjectType objtype, Node *object)
Definition: dropcmds.c:248
Oid LookupNamespaceNoError(const char *nspname)
Definition: namespace.c:2863
Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
Definition: parse_type.c:232