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