PostgreSQL Source Code  git master
dropcmds.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "catalog/dependency.h"
#include "catalog/namespace.h"
#include "catalog/objectaddress.h"
#include "catalog/pg_class.h"
#include "catalog/pg_proc.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
Include dependency graph for dropcmds.c:

Go to the source code of this file.

Functions

static void does_not_exist_skipping (ObjectType objtype, Node *object)
 
static bool owningrel_does_not_exist_skipping (List *object, const char **msg, char **name)
 
static bool schema_does_not_exist_skipping (List *object, const char **msg, char **name)
 
static bool type_in_list_does_not_exist_skipping (List *typenames, const char **msg, char **name)
 
void RemoveObjects (DropStmt *stmt)
 

Function Documentation

◆ does_not_exist_skipping()

static void does_not_exist_skipping ( ObjectType  objtype,
Node object 
)
static

Definition at line 247 of file dropcmds.c.

References generate_unaccent_rules::args, castNode, elog, ereport, errmsg(), ERROR, gettext_noop, linitial, linitial_node, list_copy(), list_copy_tail(), list_length(), list_make1, list_truncate(), llast, lsecond, lsecond_node, name, NameListToString(), TypeName::names, NOTICE, ObjectWithArgs::objargs, OBJECT_ACCESS_METHOD, OBJECT_AGGREGATE, OBJECT_CAST, OBJECT_COLLATION, OBJECT_CONVERSION, OBJECT_DOMAIN, OBJECT_EVENT_TRIGGER, OBJECT_EXTENSION, OBJECT_FDW, OBJECT_FOREIGN_SERVER, OBJECT_FUNCTION, OBJECT_LANGUAGE, OBJECT_OPCLASS, OBJECT_OPERATOR, OBJECT_OPFAMILY, OBJECT_POLICY, OBJECT_PUBLICATION, OBJECT_RULE, OBJECT_SCHEMA, OBJECT_STATISTIC_EXT, OBJECT_TRANSFORM, OBJECT_TRIGGER, OBJECT_TSCONFIGURATION, OBJECT_TSDICTIONARY, OBJECT_TSPARSER, OBJECT_TSTEMPLATE, OBJECT_TYPE, ObjectWithArgs::objname, owningrel_does_not_exist_skipping(), schema_does_not_exist_skipping(), strVal, type_in_list_does_not_exist_skipping(), TypeNameListToString(), and TypeNameToString().

Referenced by RemoveObjects().

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_AGGREGATE:
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("aggregate %s(%s) does not exist, skipping");
349  name = NameListToString(owa->objname);
350  args = TypeNameListToString(owa->objargs);
351  }
352  break;
353  }
354  case OBJECT_OPERATOR:
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("operator %s does not exist, skipping");
362  name = NameListToString(owa->objname);
363  }
364  break;
365  }
366  case OBJECT_LANGUAGE:
367  msg = gettext_noop("language \"%s\" does not exist, skipping");
368  name = strVal((Value *) object);
369  break;
370  case OBJECT_CAST:
371  {
372  if (!type_in_list_does_not_exist_skipping(list_make1(linitial(castNode(List, object))), &msg, &name) &&
374  {
375  /* XXX quote or no quote? */
376  msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
379  }
380  }
381  break;
382  case OBJECT_TRANSFORM:
384  {
385  msg = gettext_noop("transform for type %s language \"%s\" does not exist, skipping");
387  args = strVal(lsecond(castNode(List, object)));
388  }
389  break;
390  case OBJECT_TRIGGER:
391  if (!owningrel_does_not_exist_skipping(castNode(List, object), &msg, &name))
392  {
393  msg = gettext_noop("trigger \"%s\" for relation \"%s\" does not exist, skipping");
394  name = strVal(llast(castNode(List, object)));
396  list_length(castNode(List, object)) - 1));
397  }
398  break;
399  case OBJECT_POLICY:
400  if (!owningrel_does_not_exist_skipping(castNode(List, object), &msg, &name))
401  {
402  msg = gettext_noop("policy \"%s\" for relation \"%s\" does not exist, skipping");
403  name = strVal(llast(castNode(List, object)));
405  list_length(castNode(List, object)) - 1));
406  }
407  break;
409  msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
410  name = strVal((Value *) object);
411  break;
412  case OBJECT_RULE:
413  if (!owningrel_does_not_exist_skipping(castNode(List, object), &msg, &name))
414  {
415  msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
416  name = strVal(llast(castNode(List, object)));
418  list_length(castNode(List, object)) - 1));
419  }
420  break;
421  case OBJECT_FDW:
422  msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
423  name = strVal((Value *) object);
424  break;
426  msg = gettext_noop("server \"%s\" does not exist, skipping");
427  name = strVal((Value *) object);
428  break;
429  case OBJECT_OPCLASS:
430  {
431  List *opcname = list_copy_tail(castNode(List, object), 1);
432 
433  if (!schema_does_not_exist_skipping(opcname, &msg, &name))
434  {
435  msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
436  name = NameListToString(opcname);
437  args = strVal(linitial(castNode(List, object)));
438  }
439  }
440  break;
441  case OBJECT_OPFAMILY:
442  {
443  List *opfname = list_copy_tail(castNode(List, object), 1);
444 
445  if (!schema_does_not_exist_skipping(opfname, &msg, &name))
446  {
447  msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
448  name = NameListToString(opfname);
449  args = strVal(linitial(castNode(List, object)));
450  }
451  }
452  break;
453  case OBJECT_PUBLICATION:
454  msg = gettext_noop("publication \"%s\" does not exist, skipping");
455  name = strVal((Value *) object);
456  break;
457  default:
458  elog(ERROR, "unrecognized object type: %d", (int) objtype);
459  break;
460  }
461 
462  if (!args)
463  ereport(NOTICE, (errmsg(msg, name)));
464  else
465  ereport(NOTICE, (errmsg(msg, name, args)));
466 }
static bool schema_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:178
List * names
Definition: parsenodes.h:208
#define castNode(_type_, nodeptr)
Definition: nodes.h:580
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
#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:981
List * list_copy(const List *oldlist)
Definition: list.c:1160
#define strVal(v)
Definition: value.h:54
char * TypeNameListToString(List *typenames)
Definition: parse_type.c:473
List * list_copy_tail(const List *oldlist, int nskip)
Definition: list.c:1203
#define linitial_node(type, l)
Definition: pg_list.h:114
#define lsecond(l)
Definition: pg_list.h:116
#define list_make1(x1)
Definition: pg_list.h:139
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
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: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
Definition: value.h:42
static int list_length(const List *l)
Definition: pg_list.h:89
const char * name
Definition: encode.c:521
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ owningrel_does_not_exist_skipping()

static bool owningrel_does_not_exist_skipping ( List object,
const char **  msg,
char **  name 
)
static

Definition at line 142 of file dropcmds.c.

References gettext_noop, list_copy(), list_length(), list_truncate(), makeRangeVarFromNameList(), NameListToString(), NoLock, OidIsValid, RangeVarGetRelid, and schema_does_not_exist_skipping().

Referenced by does_not_exist_skipping().

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 }
static bool schema_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:178
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:53
List * list_truncate(List *list, int new_size)
Definition: list.c:350
#define gettext_noop(x)
Definition: c.h:981
List * list_copy(const List *oldlist)
Definition: list.c:1160
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3023
#define OidIsValid(objectId)
Definition: c.h:576
#define NoLock
Definition: lockdefs.h:34
char * NameListToString(List *names)
Definition: namespace.c:3063
static int list_length(const List *l)
Definition: pg_list.h:89
const char * name
Definition: encode.c:521
Definition: pg_list.h:45

◆ RemoveObjects()

void RemoveObjects ( DropStmt stmt)

Definition at line 54 of file dropcmds.c.

References AccessExclusiveLock, add_exact_object_address(), Assert, DropStmt::behavior, castNode, check_object_ownership(), does_not_exist_skipping(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, free_object_addresses(), get_object_address(), get_object_namespace(), GETSTRUCT, GetUserId(), heap_close, HeapTupleIsValid, lfirst, DropStmt::missing_ok, NameListToString(), new_object_addresses(), NoLock, OBJECT_FUNCTION, ObjectAddress::objectId, ObjectIdGetDatum, DropStmt::objects, OidIsValid, performMultipleDeletions(), pg_namespace_ownercheck(), PROCOID, ReleaseSysCache(), DropStmt::removeType, and SearchSysCache1().

Referenced by ExecDropStmt().

55 {
56  ObjectAddresses *objects;
57  ListCell *cell1;
58 
59  objects = new_object_addresses();
60 
61  foreach(cell1, stmt->objects)
62  {
63  ObjectAddress address;
64  Node *object = lfirst(cell1);
65  Relation relation = NULL;
66  Oid namespaceId;
67 
68  /* Get an ObjectAddress for the object. */
69  address = get_object_address(stmt->removeType,
70  object,
71  &relation,
73  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  if (!OidIsValid(address.objectId))
81  {
82  Assert(stmt->missing_ok);
83  does_not_exist_skipping(stmt->removeType, object);
84  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  if (stmt->removeType == OBJECT_FUNCTION)
93  {
94  Oid funcOid = address.objectId;
95  HeapTuple tup;
96 
97  tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
98  if (!HeapTupleIsValid(tup)) /* should not happen */
99  elog(ERROR, "cache lookup failed for function %u", funcOid);
100 
101  if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
102  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  ReleaseSysCache(tup);
109  }
110 
111  /* Check permissions. */
112  namespaceId = get_object_namespace(&address);
113  if (!OidIsValid(namespaceId) ||
114  !pg_namespace_ownercheck(namespaceId, GetUserId()))
115  check_object_ownership(GetUserId(), stmt->removeType, address,
116  object, relation);
117 
118  /* Release any relcache reference count, but keep lock until commit. */
119  if (relation)
120  heap_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 }
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
Oid GetUserId(void)
Definition: miscinit.c:284
#define castNode(_type_, nodeptr)
Definition: nodes.h:580
List * objects
Definition: parsenodes.h:2585
bool missing_ok
Definition: parsenodes.h:2588
Definition: nodes.h:511
int errcode(int sqlerrcode)
Definition: elog.c:575
bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
Definition: aclchk.c:4722
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
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2376
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
ObjectType removeType
Definition: parsenodes.h:2586
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
DropBehavior behavior
Definition: parsenodes.h:2587
#define ereport(elevel, rest)
Definition: elog.h:122
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
char * NameListToString(List *names)
Definition: namespace.c:3063
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
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
static void does_not_exist_skipping(ObjectType objtype, Node *object)
Definition: dropcmds.c:247

◆ schema_does_not_exist_skipping()

static bool schema_does_not_exist_skipping ( List object,
const char **  msg,
char **  name 
)
static

Definition at line 178 of file dropcmds.c.

References gettext_noop, LookupNamespaceNoError(), makeRangeVarFromNameList(), OidIsValid, and RangeVar::schemaname.

Referenced by does_not_exist_skipping(), owningrel_does_not_exist_skipping(), and type_in_list_does_not_exist_skipping().

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 }
#define gettext_noop(x)
Definition: c.h:981
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3023
#define OidIsValid(objectId)
Definition: c.h:576
char * schemaname
Definition: primnodes.h:67
const char * name
Definition: encode.c:521
Oid LookupNamespaceNoError(const char *nspname)
Definition: namespace.c:2823

◆ type_in_list_does_not_exist_skipping()

static bool type_in_list_does_not_exist_skipping ( List typenames,
const char **  msg,
char **  name 
)
static

Definition at line 210 of file dropcmds.c.

References gettext_noop, lfirst_node, LookupTypeNameOid(), TypeName::names, OidIsValid, schema_does_not_exist_skipping(), and TypeNameToString().

Referenced by does_not_exist_skipping().

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 }
static bool schema_does_not_exist_skipping(List *object, const char **msg, char **name)
Definition: dropcmds.c:178
List * names
Definition: parsenodes.h:208
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
#define gettext_noop(x)
Definition: c.h:981
#define OidIsValid(objectId)
Definition: c.h:576
#define lfirst_node(type, lc)
Definition: pg_list.h:109
const char * name
Definition: encode.c:521
Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
Definition: parse_type.c:215