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-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 
34 static void does_not_exist_skipping(ObjectType objtype,
35  Node *object);
36 static bool owningrel_does_not_exist_skipping(List *object,
37  const char **msg, char **name);
38 static bool schema_does_not_exist_skipping(List *object,
39  const char **msg, char **name);
40 static 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  */
55 void
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,
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))
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  */
141 static bool
142 owningrel_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  */
177 static bool
178 schema_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 &&
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  */
209 static bool
210 type_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  */
246 static void
248 {
249  const char *msg = NULL;
250  char *name = NULL;
251  char *args = NULL;
252 
253  switch (objtype)
254  {
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;
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;
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) &&
400  {
401  /* XXX quote or no quote? */
402  msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
405  }
406  }
407  break;
408  case OBJECT_TRANSFORM:
410  {
411  msg = gettext_noop("transform for type %s language \"%s\" does not exist, skipping");
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)));
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)));
431  list_length(castNode(List, object)) - 1));
432  }
433  break;
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)));
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;
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 }
static bool schema_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:178
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:974
List * names
Definition: parsenodes.h:209
Oid GetUserId(void)
Definition: miscinit.c:380
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:63
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:477
List * objects
Definition: parsenodes.h:2631
bool missing_ok
Definition: parsenodes.h:2634
#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:1117
List * list_copy(const List *oldlist)
Definition: list.c:1404
Definition: nodes.h:525
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:570
char * TypeNameListToString(List *typenames)
Definition: parse_type.c:491
bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
Definition: aclchk.c:4931
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3054
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2435
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2380
List * list_copy_tail(const List *oldlist, int nskip)
Definition: list.c:1423
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2675
unsigned int Oid
Definition: postgres_ext.h:31
void RemoveObjects(DropStmt *stmt)
Definition: dropcmds.c:56
#define linitial_node(type, l)
Definition: pg_list.h:198
#define OidIsValid(objectId)
Definition: c.h:638
#define lsecond(l)
Definition: pg_list.h:200
ObjectType removeType
Definition: parsenodes.h:2632
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:2633
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3149
#define ereport(elevel, rest)
Definition: elog.h:141
ObjectType
Definition: parsenodes.h:1669
int MyXactFlags
Definition: xact.c:119
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:97
char * NameListToString(List *names)
Definition: namespace.c:3094
char get_func_prokind(Oid funcid)
Definition: lsyscache.c:1620
#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:210
static bool owningrel_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:142
#define NOTICE
Definition: elog.h:37
#define Assert(condition)
Definition: c.h:732
#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:784
#define elog(elevel,...)
Definition: elog.h:226
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:374
Definition: pg_list.h:50
static void does_not_exist_skipping(ObjectType objtype, Node *object)
Definition: dropcmds.c:247
Oid LookupNamespaceNoError(const char *nspname)
Definition: namespace.c:2855
Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
Definition: parse_type.c:233