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