Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * dependency.c
4 : : * Routines to support inter-object dependencies.
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/catalog/dependency.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "access/genam.h"
18 : : #include "access/htup_details.h"
19 : : #include "access/table.h"
20 : : #include "access/xact.h"
21 : : #include "catalog/catalog.h"
22 : : #include "catalog/dependency.h"
23 : : #include "catalog/heap.h"
24 : : #include "catalog/index.h"
25 : : #include "catalog/namespace.h"
26 : : #include "catalog/objectaccess.h"
27 : : #include "catalog/pg_am.h"
28 : : #include "catalog/pg_amop.h"
29 : : #include "catalog/pg_amproc.h"
30 : : #include "catalog/pg_attrdef.h"
31 : : #include "catalog/pg_authid.h"
32 : : #include "catalog/pg_auth_members.h"
33 : : #include "catalog/pg_cast.h"
34 : : #include "catalog/pg_collation.h"
35 : : #include "catalog/pg_constraint.h"
36 : : #include "catalog/pg_conversion.h"
37 : : #include "catalog/pg_database.h"
38 : : #include "catalog/pg_default_acl.h"
39 : : #include "catalog/pg_depend.h"
40 : : #include "catalog/pg_event_trigger.h"
41 : : #include "catalog/pg_extension.h"
42 : : #include "catalog/pg_foreign_data_wrapper.h"
43 : : #include "catalog/pg_foreign_server.h"
44 : : #include "catalog/pg_init_privs.h"
45 : : #include "catalog/pg_language.h"
46 : : #include "catalog/pg_largeobject.h"
47 : : #include "catalog/pg_namespace.h"
48 : : #include "catalog/pg_opclass.h"
49 : : #include "catalog/pg_operator.h"
50 : : #include "catalog/pg_opfamily.h"
51 : : #include "catalog/pg_parameter_acl.h"
52 : : #include "catalog/pg_policy.h"
53 : : #include "catalog/pg_proc.h"
54 : : #include "catalog/pg_propgraph_element.h"
55 : : #include "catalog/pg_propgraph_element_label.h"
56 : : #include "catalog/pg_propgraph_label.h"
57 : : #include "catalog/pg_propgraph_label_property.h"
58 : : #include "catalog/pg_propgraph_property.h"
59 : : #include "catalog/pg_publication.h"
60 : : #include "catalog/pg_publication_namespace.h"
61 : : #include "catalog/pg_publication_rel.h"
62 : : #include "catalog/pg_rewrite.h"
63 : : #include "catalog/pg_statistic_ext.h"
64 : : #include "catalog/pg_subscription.h"
65 : : #include "catalog/pg_tablespace.h"
66 : : #include "catalog/pg_transform.h"
67 : : #include "catalog/pg_trigger.h"
68 : : #include "catalog/pg_ts_config.h"
69 : : #include "catalog/pg_ts_dict.h"
70 : : #include "catalog/pg_ts_parser.h"
71 : : #include "catalog/pg_ts_template.h"
72 : : #include "catalog/pg_type.h"
73 : : #include "catalog/pg_user_mapping.h"
74 : : #include "commands/comment.h"
75 : : #include "commands/defrem.h"
76 : : #include "commands/event_trigger.h"
77 : : #include "commands/extension.h"
78 : : #include "commands/policy.h"
79 : : #include "commands/publicationcmds.h"
80 : : #include "commands/seclabel.h"
81 : : #include "commands/sequence.h"
82 : : #include "commands/trigger.h"
83 : : #include "commands/typecmds.h"
84 : : #include "funcapi.h"
85 : : #include "miscadmin.h"
86 : : #include "nodes/nodeFuncs.h"
87 : : #include "parser/parsetree.h"
88 : : #include "rewrite/rewriteRemove.h"
89 : : #include "storage/lmgr.h"
90 : : #include "utils/fmgroids.h"
91 : : #include "utils/lsyscache.h"
92 : : #include "utils/syscache.h"
93 : :
94 : :
95 : : /*
96 : : * Deletion processing requires additional state for each ObjectAddress that
97 : : * it's planning to delete. For simplicity and code-sharing we make the
98 : : * ObjectAddresses code support arrays with or without this extra state.
99 : : */
100 : : typedef struct
101 : : {
102 : : int flags; /* bitmask, see bit definitions below */
103 : : ObjectAddress dependee; /* object whose deletion forced this one */
104 : : } ObjectAddressExtra;
105 : :
106 : : /* ObjectAddressExtra flag bits */
107 : : #define DEPFLAG_ORIGINAL 0x0001 /* an original deletion target */
108 : : #define DEPFLAG_NORMAL 0x0002 /* reached via normal dependency */
109 : : #define DEPFLAG_AUTO 0x0004 /* reached via auto dependency */
110 : : #define DEPFLAG_INTERNAL 0x0008 /* reached via internal dependency */
111 : : #define DEPFLAG_PARTITION 0x0010 /* reached via partition dependency */
112 : : #define DEPFLAG_EXTENSION 0x0020 /* reached via extension dependency */
113 : : #define DEPFLAG_REVERSE 0x0040 /* reverse internal/extension link */
114 : : #define DEPFLAG_IS_PART 0x0080 /* has a partition dependency */
115 : : #define DEPFLAG_SUBOBJECT 0x0100 /* subobject of another deletable object */
116 : :
117 : :
118 : : /* expansible list of ObjectAddresses */
119 : : struct ObjectAddresses
120 : : {
121 : : ObjectAddress *refs; /* => palloc'd array */
122 : : ObjectAddressExtra *extras; /* => palloc'd array, or NULL if not used */
123 : : int numrefs; /* current number of references */
124 : : int maxrefs; /* current size of palloc'd array(s) */
125 : : };
126 : :
127 : : /* typedef ObjectAddresses appears in dependency.h */
128 : :
129 : : /* threaded list of ObjectAddresses, for recursion detection */
130 : : typedef struct ObjectAddressStack
131 : : {
132 : : const ObjectAddress *object; /* object being visited */
133 : : int flags; /* its current flag bits */
134 : : struct ObjectAddressStack *next; /* next outer stack level */
135 : : } ObjectAddressStack;
136 : :
137 : : /* temporary storage in findDependentObjects */
138 : : typedef struct
139 : : {
140 : : ObjectAddress obj; /* object to be deleted --- MUST BE FIRST */
141 : : int subflags; /* flags to pass down when recursing to obj */
142 : : } ObjectAddressAndFlags;
143 : :
144 : : /* for find_expr_references_walker */
145 : : typedef struct
146 : : {
147 : : ObjectAddresses *addrs; /* addresses being accumulated */
148 : : List *rtables; /* list of rangetables to resolve Vars */
149 : : } find_expr_references_context;
150 : :
151 : :
152 : : static void findDependentObjects(const ObjectAddress *object,
153 : : int objflags,
154 : : int flags,
155 : : ObjectAddressStack *stack,
156 : : ObjectAddresses *targetObjects,
157 : : const ObjectAddresses *pendingObjects,
158 : : Relation *depRel);
159 : : static void reportDependentObjects(const ObjectAddresses *targetObjects,
160 : : DropBehavior behavior,
161 : : int flags,
162 : : const ObjectAddress *origObject);
163 : : static void deleteOneObject(const ObjectAddress *object,
164 : : Relation *depRel, int32 flags);
165 : : static void doDeletion(const ObjectAddress *object, int flags);
166 : : static bool find_expr_references_walker(Node *node,
167 : : find_expr_references_context *context);
168 : : static void process_function_rte_ref(RangeTblEntry *rte, AttrNumber attnum,
169 : : find_expr_references_context *context);
170 : : static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
171 : : static int object_address_comparator(const void *a, const void *b);
172 : : static void add_object_address(Oid classId, Oid objectId, int32 subId,
173 : : ObjectAddresses *addrs);
174 : : static void add_exact_object_address_extra(const ObjectAddress *object,
175 : : const ObjectAddressExtra *extra,
176 : : ObjectAddresses *addrs);
177 : : static bool object_address_present_add_flags(const ObjectAddress *object,
178 : : int flags,
179 : : ObjectAddresses *addrs);
180 : : static bool stack_address_present_add_flags(const ObjectAddress *object,
181 : : int flags,
182 : : ObjectAddressStack *stack);
183 : : static void DeleteInitPrivs(const ObjectAddress *object);
184 : :
185 : :
186 : : /*
187 : : * Go through the objects given running the final actions on them, and execute
188 : : * the actual deletion.
189 : : */
190 : : static void
4901 alvherre@alvh.no-ip. 191 :CBC 22574 : deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel,
192 : : int flags)
193 : : {
194 : : int i;
195 : :
196 : : /*
197 : : * Keep track of objects for event triggers, if necessary.
198 : : */
4269 199 [ + + + + ]: 22574 : if (trackDroppedObjectsNeeded() && !(flags & PERFORM_DELETION_INTERNAL))
200 : : {
4901 201 [ + + ]: 3374 : for (i = 0; i < targetObjects->numrefs; i++)
202 : : {
4269 203 : 2874 : const ObjectAddress *thisobj = &targetObjects->refs[i];
204 : 2874 : const ObjectAddressExtra *extra = &targetObjects->extras[i];
4114 bruce@momjian.us 205 : 2874 : bool original = false;
206 : 2874 : bool normal = false;
207 : :
4269 alvherre@alvh.no-ip. 208 [ + + ]: 2874 : if (extra->flags & DEPFLAG_ORIGINAL)
209 : 563 : original = true;
210 [ + + ]: 2874 : if (extra->flags & DEPFLAG_NORMAL)
211 : 266 : normal = true;
212 [ + + ]: 2874 : if (extra->flags & DEPFLAG_REVERSE)
213 : 3 : normal = true;
214 : :
884 peter@eisentraut.org 215 [ + + ]: 2874 : if (EventTriggerSupportsObject(thisobj))
216 : : {
4269 alvherre@alvh.no-ip. 217 : 2800 : EventTriggerSQLDropAddObject(thisobj, original, normal);
218 : : }
219 : : }
220 : : }
221 : :
222 : : /*
223 : : * Delete all the objects in the proper order, except that if told to, we
224 : : * should skip the original object(s).
225 : : */
4901 226 [ + + ]: 170938 : for (i = 0; i < targetObjects->numrefs; i++)
227 : : {
228 : 148370 : ObjectAddress *thisobj = targetObjects->refs + i;
3555 tgl@sss.pgh.pa.us 229 : 148370 : ObjectAddressExtra *thisextra = targetObjects->extras + i;
230 : :
231 [ + + ]: 148370 : if ((flags & PERFORM_DELETION_SKIP_ORIGINAL) &&
232 [ + + ]: 6766 : (thisextra->flags & DEPFLAG_ORIGINAL))
233 : 601 : continue;
234 : :
4901 alvherre@alvh.no-ip. 235 : 147769 : deleteOneObject(thisobj, depRel, flags);
236 : : }
237 : 22568 : }
238 : :
239 : : /*
240 : : * performDeletion: attempt to drop the specified object. If CASCADE
241 : : * behavior is specified, also drop any dependent objects (recursively).
242 : : * If RESTRICT behavior is specified, error out if there are any dependent
243 : : * objects, except for those that should be implicitly dropped anyway
244 : : * according to the dependency type.
245 : : *
246 : : * This is the outer control routine for all forms of DROP that drop objects
247 : : * that can participate in dependencies. Note that performMultipleDeletions
248 : : * is a variant on the same theme; if you change anything here you'll likely
249 : : * need to fix that too.
250 : : *
251 : : * Bits in the flags argument can include:
252 : : *
253 : : * PERFORM_DELETION_INTERNAL: indicates that the drop operation is not the
254 : : * direct result of a user-initiated action. For example, when a temporary
255 : : * schema is cleaned out so that a new backend can use it, or when a column
256 : : * default is dropped as an intermediate step while adding a new one, that's
257 : : * an internal operation. On the other hand, when we drop something because
258 : : * the user issued a DROP statement against it, that's not internal. Currently
259 : : * this suppresses calling event triggers and making some permissions checks.
260 : : *
261 : : * PERFORM_DELETION_CONCURRENTLY: perform the drop concurrently. This does
262 : : * not currently work for anything except dropping indexes; don't set it for
263 : : * other object types or you may get strange results.
264 : : *
265 : : * PERFORM_DELETION_QUIETLY: reduce message level from NOTICE to DEBUG2.
266 : : *
267 : : * PERFORM_DELETION_SKIP_ORIGINAL: do not delete the specified object(s),
268 : : * but only what depends on it/them.
269 : : *
270 : : * PERFORM_DELETION_SKIP_EXTENSIONS: do not delete extensions, even when
271 : : * deleting objects that are part of an extension. This should generally
272 : : * be used only when dropping temporary objects.
273 : : *
274 : : * PERFORM_DELETION_CONCURRENT_LOCK: perform the drop normally but with a lock
275 : : * as if it were concurrent. This is used by REINDEX CONCURRENTLY.
276 : : *
277 : : */
278 : : void
8812 tgl@sss.pgh.pa.us 279 : 4380 : performDeletion(const ObjectAddress *object,
280 : : DropBehavior behavior, int flags)
281 : : {
282 : : Relation depRel;
283 : : ObjectAddresses *targetObjects;
284 : :
285 : : /*
286 : : * We save some cycles by opening pg_depend just once and passing the
287 : : * Relation pointer down to all the recursive deletion steps.
288 : : */
2775 andres@anarazel.de 289 : 4380 : depRel = table_open(DependRelationId, RowExclusiveLock);
290 : :
291 : : /*
292 : : * Acquire deletion lock on the target object. (Ideally the caller has
293 : : * done this already, but many places are sloppy about it.)
294 : : */
5256 simon@2ndQuadrant.co 295 : 4380 : AcquireDeletionLock(object, 0);
296 : :
297 : : /*
298 : : * Construct a list of objects to delete (ie, the given object plus
299 : : * everything directly or indirectly dependent on it).
300 : : */
6654 tgl@sss.pgh.pa.us 301 : 4380 : targetObjects = new_object_addresses();
302 : :
303 : 4380 : findDependentObjects(object,
304 : : DEPFLAG_ORIGINAL,
305 : : flags,
306 : : NULL, /* empty stack */
307 : : targetObjects,
308 : : NULL, /* no pendingObjects */
309 : : &depRel);
310 : :
311 : : /*
312 : : * Check if deletion is allowed, and report about cascaded deletes.
313 : : */
314 : 4380 : reportDependentObjects(targetObjects,
315 : : behavior,
316 : : flags,
317 : : object);
318 : :
319 : : /* do the deed */
4901 alvherre@alvh.no-ip. 320 : 4340 : deleteObjectsInList(targetObjects, &depRel, flags);
321 : :
322 : : /* And clean up */
6654 tgl@sss.pgh.pa.us 323 : 4339 : free_object_addresses(targetObjects);
324 : :
2775 andres@anarazel.de 325 : 4339 : table_close(depRel, RowExclusiveLock);
7312 alvherre@alvh.no-ip. 326 : 4339 : }
327 : :
328 : : /*
329 : : * performMultipleDeletions: Similar to performDeletion, but act on multiple
330 : : * objects at once.
331 : : *
332 : : * The main difference from issuing multiple performDeletion calls is that the
333 : : * list of objects that would be implicitly dropped, for each object to be
334 : : * dropped, is the union of the implicit-object list for all objects. This
335 : : * makes each check be more relaxed.
336 : : */
337 : : void
338 : 20103 : performMultipleDeletions(const ObjectAddresses *objects,
339 : : DropBehavior behavior, int flags)
340 : : {
341 : : Relation depRel;
342 : : ObjectAddresses *targetObjects;
343 : : int i;
344 : :
345 : : /* No work if no objects... */
6648 tgl@sss.pgh.pa.us 346 [ + + ]: 20103 : if (objects->numrefs <= 0)
347 : 1602 : return;
348 : :
349 : : /*
350 : : * We save some cycles by opening pg_depend just once and passing the
351 : : * Relation pointer down to all the recursive deletion steps.
352 : : */
2775 andres@anarazel.de 353 : 18501 : depRel = table_open(DependRelationId, RowExclusiveLock);
354 : :
355 : : /*
356 : : * Construct a list of objects to delete (ie, the given objects plus
357 : : * everything directly or indirectly dependent on them). Note that
358 : : * because we pass the whole objects list as pendingObjects context, we
359 : : * won't get a failure from trying to delete an object that is internally
360 : : * dependent on another one in the list; we'll just skip that object and
361 : : * delete it when we reach its owner.
362 : : */
6654 tgl@sss.pgh.pa.us 363 : 18501 : targetObjects = new_object_addresses();
364 : :
7312 alvherre@alvh.no-ip. 365 [ + + ]: 40750 : for (i = 0; i < objects->numrefs; i++)
366 : : {
6654 tgl@sss.pgh.pa.us 367 : 22280 : const ObjectAddress *thisobj = objects->refs + i;
368 : :
369 : : /*
370 : : * Acquire deletion lock on each target object. (Ideally the caller
371 : : * has done this already, but many places are sloppy about it.)
372 : : */
5256 simon@2ndQuadrant.co 373 : 22280 : AcquireDeletionLock(thisobj, flags);
374 : :
6654 tgl@sss.pgh.pa.us 375 : 22280 : findDependentObjects(thisobj,
376 : : DEPFLAG_ORIGINAL,
377 : : flags,
378 : : NULL, /* empty stack */
379 : : targetObjects,
380 : : objects,
381 : : &depRel);
382 : : }
383 : :
384 : : /*
385 : : * Check if deletion is allowed, and report about cascaded deletes.
386 : : *
387 : : * If there's exactly one object being deleted, report it the same way as
388 : : * in performDeletion(), else we have to be vaguer.
389 : : */
390 : 18470 : reportDependentObjects(targetObjects,
391 : : behavior,
392 : : flags,
6648 393 [ + + ]: 18470 : (objects->numrefs == 1 ? objects->refs : NULL));
394 : :
395 : : /* do the deed */
4901 alvherre@alvh.no-ip. 396 : 18234 : deleteObjectsInList(targetObjects, &depRel, flags);
397 : :
398 : : /* And clean up */
6654 tgl@sss.pgh.pa.us 399 : 18229 : free_object_addresses(targetObjects);
400 : :
2775 andres@anarazel.de 401 : 18229 : table_close(depRel, RowExclusiveLock);
402 : : }
403 : :
404 : : /*
405 : : * findDependentObjects - find all objects that depend on 'object'
406 : : *
407 : : * For every object that depends on the starting object, acquire a deletion
408 : : * lock on the object, add it to targetObjects (if not already there),
409 : : * and recursively find objects that depend on it. An object's dependencies
410 : : * will be placed into targetObjects before the object itself; this means
411 : : * that the finished list's order represents a safe deletion order.
412 : : *
413 : : * The caller must already have a deletion lock on 'object' itself,
414 : : * but must not have added it to targetObjects. (Note: there are corner
415 : : * cases where we won't add the object either, and will also release the
416 : : * caller-taken lock. This is a bit ugly, but the API is set up this way
417 : : * to allow easy rechecking of an object's liveness after we lock it. See
418 : : * notes within the function.)
419 : : *
420 : : * When dropping a whole object (subId = 0), we find dependencies for
421 : : * its sub-objects too.
422 : : *
423 : : * object: the object to add to targetObjects and find dependencies on
424 : : * objflags: flags to be ORed into the object's targetObjects entry
425 : : * flags: PERFORM_DELETION_xxx flags for the deletion operation as a whole
426 : : * stack: list of objects being visited in current recursion; topmost item
427 : : * is the object that we recursed from (NULL for external callers)
428 : : * targetObjects: list of objects that are scheduled to be deleted
429 : : * pendingObjects: list of other objects slated for destruction, but
430 : : * not necessarily in targetObjects yet (can be NULL if none)
431 : : * *depRel: already opened pg_depend relation
432 : : *
433 : : * Note: objflags describes the reason for visiting this particular object
434 : : * at this time, and is not passed down when recursing. The flags argument
435 : : * is passed down, since it describes what we're doing overall.
436 : : */
437 : : static void
6654 tgl@sss.pgh.pa.us 438 : 184894 : findDependentObjects(const ObjectAddress *object,
439 : : int objflags,
440 : : int flags,
441 : : ObjectAddressStack *stack,
442 : : ObjectAddresses *targetObjects,
443 : : const ObjectAddresses *pendingObjects,
444 : : Relation *depRel)
445 : : {
446 : : ScanKeyData key[3];
447 : : int nkeys;
448 : : SysScanDesc scan;
449 : : HeapTuple tup;
450 : : ObjectAddress otherObject;
451 : : ObjectAddress owningObject;
452 : : ObjectAddress partitionObject;
453 : : ObjectAddressAndFlags *dependentObjects;
454 : : int numDependentObjects;
455 : : int maxDependentObjects;
456 : : ObjectAddressStack mystack;
457 : : ObjectAddressExtra extra;
458 : :
459 : : /*
460 : : * If the target object is already being visited in an outer recursion
461 : : * level, just report the current objflags back to that level and exit.
462 : : * This is needed to avoid infinite recursion in the face of circular
463 : : * dependencies.
464 : : *
465 : : * The stack check alone would result in dependency loops being broken at
466 : : * an arbitrary point, ie, the first member object of the loop to be
467 : : * visited is the last one to be deleted. This is obviously unworkable.
468 : : * However, the check for internal dependency below guarantees that we
469 : : * will not break a loop at an internal dependency: if we enter the loop
470 : : * at an "owned" object we will switch and start at the "owning" object
471 : : * instead. We could probably hack something up to avoid breaking at an
472 : : * auto dependency, too, if we had to. However there are no known cases
473 : : * where that would be necessary.
474 : : */
3555 475 [ + + ]: 184894 : if (stack_address_present_add_flags(object, objflags, stack))
5482 476 : 33499 : return;
477 : :
478 : : /*
479 : : * since this function recurses, it could be driven to stack overflow,
480 : : * because of the deep dependency tree, not only due to dependency loops.
481 : : */
923 akorotkov@postgresql 482 : 184684 : check_stack_depth();
483 : :
484 : : /*
485 : : * It's also possible that the target object has already been completely
486 : : * processed and put into targetObjects. If so, again we just add the
487 : : * specified objflags to its entry and return.
488 : : *
489 : : * (Note: in these early-exit cases we could release the caller-taken
490 : : * lock, since the object is presumably now locked multiple times; but it
491 : : * seems not worth the cycles.)
492 : : */
3555 tgl@sss.pgh.pa.us 493 [ + + ]: 184684 : if (object_address_present_add_flags(object, objflags, targetObjects))
6654 494 : 32021 : return;
495 : :
496 : : /*
497 : : * If the target object is pinned, we can just error out immediately; it
498 : : * won't have any objects recorded as depending on it.
499 : : */
1869 500 [ + + ]: 152663 : if (IsPinnedObject(object->classId, object->objectId))
501 [ + - ]: 1 : ereport(ERROR,
502 : : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
503 : : errmsg("cannot drop %s because it is required by the database system",
504 : : getObjectDescription(object, false))));
505 : :
506 : : /*
507 : : * The target object might be internally dependent on some other object
508 : : * (its "owner"), and/or be a member of an extension (also considered its
509 : : * owner). If so, and if we aren't recursing from the owning object, we
510 : : * have to transform this deletion request into a deletion request of the
511 : : * owning object. (We'll eventually recurse back to this object, but the
512 : : * owning object has to be visited first so it will be deleted after.) The
513 : : * way to find out about this is to scan the pg_depend entries that show
514 : : * what this object depends on.
515 : : */
8324 516 : 152662 : ScanKeyInit(&key[0],
517 : : Anum_pg_depend_classid,
518 : : BTEqualStrategyNumber, F_OIDEQ,
519 : 152662 : ObjectIdGetDatum(object->classId));
520 : 152662 : ScanKeyInit(&key[1],
521 : : Anum_pg_depend_objid,
522 : : BTEqualStrategyNumber, F_OIDEQ,
523 : 152662 : ObjectIdGetDatum(object->objectId));
8812 524 [ + + ]: 152662 : if (object->objectSubId != 0)
525 : : {
526 : : /* Consider only dependencies of this sub-object */
8324 527 : 1486 : ScanKeyInit(&key[2],
528 : : Anum_pg_depend_objsubid,
529 : : BTEqualStrategyNumber, F_INT4EQ,
530 : 1486 : Int32GetDatum(object->objectSubId));
8812 531 : 1486 : nkeys = 3;
532 : : }
533 : : else
534 : : {
535 : : /* Consider dependencies of this object and any sub-objects it has */
536 : 151176 : nkeys = 2;
537 : : }
538 : :
5013 539 : 152662 : scan = systable_beginscan(*depRel, DependDependerIndexId, true,
540 : : NULL, nkeys, key);
541 : :
542 : : /* initialize variables that loop may fill */
2754 543 : 152662 : memset(&owningObject, 0, sizeof(owningObject));
544 : 152662 : memset(&partitionObject, 0, sizeof(partitionObject));
545 : :
8812 546 [ + + ]: 364654 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
547 : : {
8758 bruce@momjian.us 548 : 213260 : Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
549 : :
8812 tgl@sss.pgh.pa.us 550 : 213260 : otherObject.classId = foundDep->refclassid;
551 : 213260 : otherObject.objectId = foundDep->refobjid;
552 : 213260 : otherObject.objectSubId = foundDep->refobjsubid;
553 : :
554 : : /*
555 : : * When scanning dependencies of a whole object, we may find rows
556 : : * linking sub-objects of the object to the object itself. (Normally,
557 : : * such a dependency is implicit, but we must make explicit ones in
558 : : * some cases involving partitioning.) We must ignore such rows to
559 : : * avoid infinite recursion.
560 : : */
2593 561 [ + + ]: 213260 : if (otherObject.classId == object->classId &&
562 [ + + ]: 69272 : otherObject.objectId == object->objectId &&
563 [ + + ]: 2901 : object->objectSubId == 0)
564 : 2885 : continue;
565 : :
8812 566 [ + + + + : 210375 : switch (foundDep->deptype)
+ - ]
567 : : {
568 : 122935 : case DEPENDENCY_NORMAL:
569 : : case DEPENDENCY_AUTO:
570 : : case DEPENDENCY_AUTO_EXTENSION:
571 : : /* no problem */
572 : 122935 : break;
573 : :
5679 574 : 2881 : case DEPENDENCY_EXTENSION:
575 : :
576 : : /*
577 : : * If told to, ignore EXTENSION dependencies altogether. This
578 : : * flag is normally used to prevent dropping extensions during
579 : : * temporary-object cleanup, even if a temp object was created
580 : : * during an extension script.
581 : : */
3555 582 [ + + ]: 2881 : if (flags & PERFORM_DELETION_SKIP_EXTENSIONS)
583 : 4 : break;
584 : :
585 : : /*
586 : : * If the other object is the extension currently being
587 : : * created/altered, ignore this dependency and continue with
588 : : * the deletion. This allows dropping of an extension's
589 : : * objects within the extension's scripts, as well as corner
590 : : * cases such as dropping a transient object created within
591 : : * such a script.
592 : : */
3561 593 [ + + ]: 2877 : if (creating_extension &&
594 [ + - ]: 198 : otherObject.classId == ExtensionRelationId &&
595 [ + - ]: 198 : otherObject.objectId == CurrentExtensionObject)
596 : 198 : break;
597 : :
598 : : /* Otherwise, treat this like an internal dependency */
599 : : pg_fallthrough;
600 : :
601 : : case DEPENDENCY_INTERNAL:
602 : :
603 : : /*
604 : : * This object is part of the internal implementation of
605 : : * another object, or is part of the extension that is the
606 : : * other object. We have three cases:
607 : : *
608 : : * 1. At the outermost recursion level, we must disallow the
609 : : * DROP. However, if the owning object is listed in
610 : : * pendingObjects, just release the caller's lock and return;
611 : : * we'll eventually complete the DROP when we reach that entry
612 : : * in the pending list.
613 : : *
614 : : * Note: the above statement is true only if this pg_depend
615 : : * entry still exists by then; in principle, therefore, we
616 : : * could miss deleting an item the user told us to delete.
617 : : * However, no inconsistency can result: since we're at outer
618 : : * level, there is no object depending on this one.
619 : : */
6654 620 [ + + ]: 80660 : if (stack == NULL)
621 : : {
6183 622 [ + - - + ]: 52 : if (pendingObjects &&
623 : 26 : object_address_present(&otherObject, pendingObjects))
624 : : {
6654 tgl@sss.pgh.pa.us 625 :UBC 0 : systable_endscan(scan);
626 : : /* need to release caller's lock; see notes below */
627 : 0 : ReleaseDeletionLock(object);
628 : 0 : return;
629 : : }
630 : :
631 : : /*
632 : : * We postpone actually issuing the error message until
633 : : * after this loop, so that we can make the behavior
634 : : * independent of the ordering of pg_depend entries, at
635 : : * least if there's not more than one INTERNAL and one
636 : : * EXTENSION dependency. (If there's more, we'll complain
637 : : * about a random one of them.) Prefer to complain about
638 : : * EXTENSION, since that's generally a more important
639 : : * dependency.
640 : : */
2754 tgl@sss.pgh.pa.us 641 [ - + ]:CBC 26 : if (!OidIsValid(owningObject.classId) ||
2754 tgl@sss.pgh.pa.us 642 [ # # ]:UBC 0 : foundDep->deptype == DEPENDENCY_EXTENSION)
2754 tgl@sss.pgh.pa.us 643 :CBC 26 : owningObject = otherObject;
644 : 26 : break;
645 : : }
646 : :
647 : : /*
648 : : * 2. When recursing from the other end of this dependency,
649 : : * it's okay to continue with the deletion. This holds when
650 : : * recursing from a whole object that includes the nominal
651 : : * other end as a component, too. Since there can be more
652 : : * than one "owning" object, we have to allow matches that are
653 : : * more than one level down in the stack.
654 : : */
5482 655 [ + + ]: 80634 : if (stack_address_present_add_flags(&otherObject, 0, stack))
8808 656 : 79366 : break;
657 : :
658 : : /*
659 : : * 3. Not all the owning objects have been visited, so
660 : : * transform this deletion request into a delete of this
661 : : * owning object.
662 : : *
663 : : * First, release caller's lock on this object and get
664 : : * deletion lock on the owning object. (We must release
665 : : * caller's lock to avoid deadlock against a concurrent
666 : : * deletion of the owning object.)
667 : : */
6654 668 : 1268 : ReleaseDeletionLock(object);
5256 simon@2ndQuadrant.co 669 : 1268 : AcquireDeletionLock(&otherObject, 0);
670 : :
671 : : /*
672 : : * The owning object might have been deleted while we waited
673 : : * to lock it; if so, neither it nor the current object are
674 : : * interesting anymore. We test this by checking the
675 : : * pg_depend entry (see notes below).
676 : : */
6654 tgl@sss.pgh.pa.us 677 [ - + ]: 1268 : if (!systable_recheck_tuple(scan, tup))
678 : : {
6654 tgl@sss.pgh.pa.us 679 :UBC 0 : systable_endscan(scan);
680 : 0 : ReleaseDeletionLock(&otherObject);
681 : 0 : return;
682 : : }
683 : :
684 : : /*
685 : : * One way or the other, we're done with the scan; might as
686 : : * well close it down before recursing, to reduce peak
687 : : * resource consumption.
688 : : */
2754 tgl@sss.pgh.pa.us 689 :CBC 1268 : systable_endscan(scan);
690 : :
691 : : /*
692 : : * Okay, recurse to the owning object instead of proceeding.
693 : : *
694 : : * We do not need to stack the current object; we want the
695 : : * traversal order to be as if the original reference had
696 : : * linked to the owning object instead of this one.
697 : : *
698 : : * The dependency type is a "reverse" dependency: we need to
699 : : * delete the owning object if this one is to be deleted, but
700 : : * this linkage is never a reason for an automatic deletion.
701 : : */
6654 702 : 1268 : findDependentObjects(&otherObject,
703 : : DEPFLAG_REVERSE,
704 : : flags,
705 : : stack,
706 : : targetObjects,
707 : : pendingObjects,
708 : : depRel);
709 : :
710 : : /*
711 : : * The current target object should have been added to
712 : : * targetObjects while processing the owning object; but it
713 : : * probably got only the flag bits associated with the
714 : : * dependency we're looking at. We need to add the objflags
715 : : * that were passed to this recursion level, too, else we may
716 : : * get a bogus failure in reportDependentObjects (if, for
717 : : * example, we were called due to a partition dependency).
718 : : *
719 : : * If somehow the current object didn't get scheduled for
720 : : * deletion, bleat. (That would imply that somebody deleted
721 : : * this dependency record before the recursion got to it.)
722 : : * Another idea would be to reacquire lock on the current
723 : : * object and resume trying to delete it, but it seems not
724 : : * worth dealing with the race conditions inherent in that.
725 : : */
2754 726 [ - + ]: 1268 : if (!object_address_present_add_flags(object, objflags,
727 : : targetObjects))
2754 tgl@sss.pgh.pa.us 728 [ # # ]:UBC 0 : elog(ERROR, "deletion of owning object %s failed to delete %s",
729 : : getObjectDescription(&otherObject, false),
730 : : getObjectDescription(object, false));
731 : :
732 : : /* And we're done here. */
6654 tgl@sss.pgh.pa.us 733 :CBC 1268 : return;
734 : :
2754 735 : 3289 : case DEPENDENCY_PARTITION_PRI:
736 : :
737 : : /*
738 : : * Remember that this object has a partition-type dependency.
739 : : * After the dependency scan, we'll complain if we didn't find
740 : : * a reason to delete one of its partition dependencies.
741 : : */
742 : 3289 : objflags |= DEPFLAG_IS_PART;
743 : :
744 : : /*
745 : : * Also remember the primary partition owner, for error
746 : : * messages. If there are multiple primary owners (which
747 : : * there should not be), we'll report a random one of them.
748 : : */
749 : 3289 : partitionObject = otherObject;
750 : 3289 : break;
751 : :
752 : 3289 : case DEPENDENCY_PARTITION_SEC:
753 : :
754 : : /*
755 : : * Only use secondary partition owners in error messages if we
756 : : * find no primary owner (which probably shouldn't happen).
757 : : */
758 [ - + ]: 3289 : if (!(objflags & DEPFLAG_IS_PART))
2754 tgl@sss.pgh.pa.us 759 :UBC 0 : partitionObject = otherObject;
760 : :
761 : : /*
762 : : * Remember that this object has a partition-type dependency.
763 : : * After the dependency scan, we'll complain if we didn't find
764 : : * a reason to delete one of its partition dependencies.
765 : : */
2754 tgl@sss.pgh.pa.us 766 :CBC 3289 : objflags |= DEPFLAG_IS_PART;
767 : 3289 : break;
768 : :
8812 tgl@sss.pgh.pa.us 769 :UBC 0 : default:
8438 770 [ # # ]: 0 : elog(ERROR, "unrecognized dependency type '%c' for %s",
771 : : foundDep->deptype, getObjectDescription(object, false));
772 : : break;
773 : : }
774 : : }
775 : :
8812 tgl@sss.pgh.pa.us 776 :CBC 151394 : systable_endscan(scan);
777 : :
778 : : /*
779 : : * If we found an INTERNAL or EXTENSION dependency when we're at outer
780 : : * level, complain about it now. If we also found a PARTITION dependency,
781 : : * we prefer to report the PARTITION dependency. This is arbitrary but
782 : : * seems to be more useful in practice.
783 : : */
2754 784 [ + + ]: 151394 : if (OidIsValid(owningObject.classId))
785 : : {
786 : : char *otherObjDesc;
787 : :
788 [ + + ]: 26 : if (OidIsValid(partitionObject.classId))
2234 michael@paquier.xyz 789 : 8 : otherObjDesc = getObjectDescription(&partitionObject, false);
790 : : else
791 : 18 : otherObjDesc = getObjectDescription(&owningObject, false);
792 : :
2754 tgl@sss.pgh.pa.us 793 [ + - ]: 26 : ereport(ERROR,
794 : : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
795 : : errmsg("cannot drop %s because %s requires it",
796 : : getObjectDescription(object, false), otherObjDesc),
797 : : errhint("You can drop %s instead.", otherObjDesc)));
798 : : }
799 : :
800 : : /*
801 : : * Next, identify all objects that directly depend on the current object.
802 : : * To ensure predictable deletion order, we collect them up in
803 : : * dependentObjects and sort the list before actually recursing. (The
804 : : * deletion order would be valid in any case, but doing this ensures
805 : : * consistent output from DROP CASCADE commands, which is helpful for
806 : : * regression testing.)
807 : : */
2775 808 : 151368 : maxDependentObjects = 128; /* arbitrary initial allocation */
260 michael@paquier.xyz 809 : 151368 : dependentObjects = palloc_array(ObjectAddressAndFlags, maxDependentObjects);
2775 tgl@sss.pgh.pa.us 810 : 151368 : numDependentObjects = 0;
811 : :
8324 812 : 151368 : ScanKeyInit(&key[0],
813 : : Anum_pg_depend_refclassid,
814 : : BTEqualStrategyNumber, F_OIDEQ,
815 : 151368 : ObjectIdGetDatum(object->classId));
816 : 151368 : ScanKeyInit(&key[1],
817 : : Anum_pg_depend_refobjid,
818 : : BTEqualStrategyNumber, F_OIDEQ,
819 : 151368 : ObjectIdGetDatum(object->objectId));
8812 820 [ + + ]: 151368 : if (object->objectSubId != 0)
821 : : {
8324 822 : 1470 : ScanKeyInit(&key[2],
823 : : Anum_pg_depend_refobjsubid,
824 : : BTEqualStrategyNumber, F_INT4EQ,
825 : 1470 : Int32GetDatum(object->objectSubId));
8812 826 : 1470 : nkeys = 3;
827 : : }
828 : : else
829 : 149898 : nkeys = 2;
830 : :
5013 831 : 151368 : scan = systable_beginscan(*depRel, DependReferenceIndexId, true,
832 : : NULL, nkeys, key);
833 : :
8812 834 [ + + ]: 311223 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
835 : : {
8758 bruce@momjian.us 836 : 159859 : Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
837 : : int subflags;
838 : :
8812 tgl@sss.pgh.pa.us 839 : 159859 : otherObject.classId = foundDep->classid;
840 : 159859 : otherObject.objectId = foundDep->objid;
841 : 159859 : otherObject.objectSubId = foundDep->objsubid;
842 : :
843 : : /*
844 : : * If what we found is a sub-object of the current object, just ignore
845 : : * it. (Normally, such a dependency is implicit, but we must make
846 : : * explicit ones in some cases involving partitioning.)
847 : : */
2593 848 [ + + ]: 159859 : if (otherObject.classId == object->classId &&
849 [ + + ]: 66288 : otherObject.objectId == object->objectId &&
850 [ + - ]: 2885 : object->objectSubId == 0)
851 : 2885 : continue;
852 : :
853 : : /*
854 : : * Must lock the dependent object before recursing to it.
855 : : */
5256 simon@2ndQuadrant.co 856 : 156974 : AcquireDeletionLock(&otherObject, 0);
857 : :
858 : : /*
859 : : * The dependent object might have been deleted while we waited to
860 : : * lock it; if so, we don't need to do anything more with it. We can
861 : : * test this cheaply and independently of the object's type by seeing
862 : : * if the pg_depend tuple we are looking at is still live. (If the
863 : : * object got deleted, the tuple would have been deleted too.)
864 : : */
6654 tgl@sss.pgh.pa.us 865 [ - + ]: 156974 : if (!systable_recheck_tuple(scan, tup))
866 : : {
867 : : /* release the now-useless lock */
6654 tgl@sss.pgh.pa.us 868 :UBC 0 : ReleaseDeletionLock(&otherObject);
869 : : /* and continue scanning for dependencies */
870 : 0 : continue;
871 : : }
872 : :
873 : : /*
874 : : * Check that the dependent object is not in a shared catalog, which
875 : : * is not supported by doDeletion().
876 : : */
24 jdavis@postgresql.or 877 [ + + ]:CBC 156974 : if (IsSharedRelation(otherObject.classId))
878 : : {
879 : 4 : char *otherObjDesc = getObjectDescription(&otherObject,
880 : : false);
881 : :
882 [ + - ]: 4 : ereport(ERROR,
883 : : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
884 : : errmsg("cannot drop %s because %s depends on it",
885 : : getObjectDescription(object, false), otherObjDesc),
886 : : errhint("Drop %s first.", otherObjDesc)));
887 : : }
888 : :
889 : : /*
890 : : * We do need to delete it, so identify objflags to be passed down,
891 : : * which depend on the dependency type.
892 : : */
8812 tgl@sss.pgh.pa.us 893 [ + + + + : 156970 : switch (foundDep->deptype)
+ - ]
894 : : {
895 : 21395 : case DEPENDENCY_NORMAL:
6654 896 : 21395 : subflags = DEPFLAG_NORMAL;
8812 897 : 21395 : break;
898 : 50245 : case DEPENDENCY_AUTO:
899 : : case DEPENDENCY_AUTO_EXTENSION:
6654 900 : 50245 : subflags = DEPFLAG_AUTO;
901 : 50245 : break;
8812 902 : 76692 : case DEPENDENCY_INTERNAL:
6654 903 : 76692 : subflags = DEPFLAG_INTERNAL;
8812 904 : 76692 : break;
2754 905 : 6003 : case DEPENDENCY_PARTITION_PRI:
906 : : case DEPENDENCY_PARTITION_SEC:
907 : 6003 : subflags = DEPFLAG_PARTITION;
908 : 6003 : break;
5679 909 : 2635 : case DEPENDENCY_EXTENSION:
910 : 2635 : subflags = DEPFLAG_EXTENSION;
911 : 2635 : break;
8812 tgl@sss.pgh.pa.us 912 :UBC 0 : default:
8438 913 [ # # ]: 0 : elog(ERROR, "unrecognized dependency type '%c' for %s",
914 : : foundDep->deptype, getObjectDescription(object, false));
915 : : subflags = 0; /* keep compiler quiet */
916 : : break;
917 : : }
918 : :
919 : : /* And add it to the pending-objects list */
2775 tgl@sss.pgh.pa.us 920 [ + + ]:CBC 156970 : if (numDependentObjects >= maxDependentObjects)
921 : : {
922 : : /* enlarge array if needed */
923 : 22 : maxDependentObjects *= 2;
10 michael@paquier.xyz 924 :GNC 22 : dependentObjects = repalloc_array(dependentObjects,
925 : : ObjectAddressAndFlags,
926 : : maxDependentObjects);
927 : : }
928 : :
2775 tgl@sss.pgh.pa.us 929 :CBC 156970 : dependentObjects[numDependentObjects].obj = otherObject;
930 : 156970 : dependentObjects[numDependentObjects].subflags = subflags;
931 : 156970 : numDependentObjects++;
932 : : }
933 : :
934 : 151364 : systable_endscan(scan);
935 : :
936 : : /*
937 : : * Now we can sort the dependent objects into a stable visitation order.
938 : : * It's safe to use object_address_comparator here since the obj field is
939 : : * first within ObjectAddressAndFlags.
940 : : */
941 [ + + ]: 151364 : if (numDependentObjects > 1)
1297 peter@eisentraut.org 942 : 32713 : qsort(dependentObjects, numDependentObjects,
943 : : sizeof(ObjectAddressAndFlags),
944 : : object_address_comparator);
945 : :
946 : : /*
947 : : * Now recurse to the dependent objects. We must visit them first since
948 : : * they have to be deleted before the current object.
949 : : */
2775 tgl@sss.pgh.pa.us 950 : 151364 : mystack.object = object; /* set up a new stack level */
951 : 151364 : mystack.flags = objflags;
952 : 151364 : mystack.next = stack;
953 : :
954 [ + + ]: 308330 : for (int i = 0; i < numDependentObjects; i++)
955 : : {
956 : 156966 : ObjectAddressAndFlags *depObj = dependentObjects + i;
957 : :
958 : 156966 : findDependentObjects(&depObj->obj,
959 : : depObj->subflags,
960 : : flags,
961 : : &mystack,
962 : : targetObjects,
963 : : pendingObjects,
964 : : depRel);
965 : : }
966 : :
967 : 151364 : pfree(dependentObjects);
968 : :
969 : : /*
970 : : * Finally, we can add the target object to targetObjects. Be careful to
971 : : * include any flags that were passed back down to us from inner recursion
972 : : * levels. Record the "dependee" as being either the most important
973 : : * partition owner if there is one, else the object we recursed from, if
974 : : * any. (The logic in reportDependentObjects() is such that it can only
975 : : * need one of those objects.)
976 : : */
6654 977 : 151364 : extra.flags = mystack.flags;
2754 978 [ + + ]: 151364 : if (extra.flags & DEPFLAG_IS_PART)
979 : 3281 : extra.dependee = partitionObject;
980 [ + + ]: 148083 : else if (stack)
6654 981 : 121995 : extra.dependee = *stack->object;
982 : : else
983 : 26088 : memset(&extra.dependee, 0, sizeof(extra.dependee));
984 : 151364 : add_exact_object_address_extra(object, &extra, targetObjects);
985 : : }
986 : :
987 : : /*
988 : : * reportDependentObjects - report about dependencies, and fail if RESTRICT
989 : : *
990 : : * Tell the user about dependent objects that we are going to delete
991 : : * (or would need to delete, but are prevented by RESTRICT mode);
992 : : * then error out if there are any and it's not CASCADE mode.
993 : : *
994 : : * targetObjects: list of objects that are scheduled to be deleted
995 : : * behavior: RESTRICT or CASCADE
996 : : * flags: other flags for the deletion operation
997 : : * origObject: base object of deletion, or NULL if not available
998 : : * (the latter case occurs in DROP OWNED)
999 : : */
1000 : : static void
1001 : 22850 : reportDependentObjects(const ObjectAddresses *targetObjects,
1002 : : DropBehavior behavior,
1003 : : int flags,
1004 : : const ObjectAddress *origObject)
1005 : : {
3555 1006 [ + + ]: 22850 : int msglevel = (flags & PERFORM_DELETION_QUIETLY) ? DEBUG2 : NOTICE;
6654 1007 : 22850 : bool ok = true;
1008 : : StringInfoData clientdetail;
1009 : : StringInfoData logdetail;
6651 1010 : 22850 : int numReportedClient = 0;
1011 : 22850 : int numNotReportedClient = 0;
1012 : : int i;
1013 : :
1014 : : /*
1015 : : * If we need to delete any partition-dependent objects, make sure that
1016 : : * we're deleting at least one of their partition dependencies, too. That
1017 : : * can be detected by checking that we reached them by a PARTITION
1018 : : * dependency at some point.
1019 : : *
1020 : : * We just report the first such object, as in most cases the only way to
1021 : : * trigger this complaint is to explicitly try to delete one partition of
1022 : : * a partitioned object.
1023 : : */
2754 1024 [ + + ]: 174194 : for (i = 0; i < targetObjects->numrefs; i++)
1025 : : {
1026 : 151364 : const ObjectAddressExtra *extra = &targetObjects->extras[i];
1027 : :
1028 [ + + ]: 151364 : if ((extra->flags & DEPFLAG_IS_PART) &&
1029 [ + + ]: 3281 : !(extra->flags & DEPFLAG_PARTITION))
1030 : : {
1031 : 20 : const ObjectAddress *object = &targetObjects->refs[i];
2234 michael@paquier.xyz 1032 : 20 : char *otherObjDesc = getObjectDescription(&extra->dependee,
1033 : : false);
1034 : :
2754 tgl@sss.pgh.pa.us 1035 [ + - ]: 20 : ereport(ERROR,
1036 : : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1037 : : errmsg("cannot drop %s because %s requires it",
1038 : : getObjectDescription(object, false), otherObjDesc),
1039 : : errhint("You can drop %s instead.", otherObjDesc)));
1040 : : }
1041 : : }
1042 : :
1043 : : /*
1044 : : * If no error is to be thrown, and the msglevel is too low to be shown to
1045 : : * either client or server log, there's no need to do any of the rest of
1046 : : * the work.
1047 : : */
6651 1048 [ + + ]: 22830 : if (behavior == DROP_CASCADE &&
2103 1049 [ + + ]: 2381 : !message_level_is_interesting(msglevel))
6651 1050 : 661 : return;
1051 : :
1052 : : /*
1053 : : * We limit the number of dependencies reported to the client to
1054 : : * MAX_REPORTED_DEPS, since client software may not deal well with
1055 : : * enormous error strings. The server log always gets a full report.
1056 : : */
1057 : : #define MAX_REPORTED_DEPS 100
1058 : :
1059 : 22169 : initStringInfo(&clientdetail);
1060 : 22169 : initStringInfo(&logdetail);
1061 : :
1062 : : /*
1063 : : * We process the list back to front (ie, in dependency order not deletion
1064 : : * order), since this makes for a more understandable display.
1065 : : */
6654 1066 [ + + ]: 164834 : for (i = targetObjects->numrefs - 1; i >= 0; i--)
1067 : : {
1068 : 142665 : const ObjectAddress *obj = &targetObjects->refs[i];
1069 : 142665 : const ObjectAddressExtra *extra = &targetObjects->extras[i];
1070 : : char *objDesc;
1071 : :
1072 : : /* Ignore the original deletion target(s) */
1073 [ + + ]: 142665 : if (extra->flags & DEPFLAG_ORIGINAL)
1074 : 25960 : continue;
1075 : :
1076 : : /* Also ignore sub-objects; we'll report the whole object elsewhere */
2778 1077 [ - + ]: 116705 : if (extra->flags & DEPFLAG_SUBOBJECT)
2778 tgl@sss.pgh.pa.us 1078 :UBC 0 : continue;
1079 : :
2234 michael@paquier.xyz 1080 :CBC 116705 : objDesc = getObjectDescription(obj, false);
1081 : :
1082 : : /* An object being dropped concurrently doesn't need to be reported */
1756 alvherre@alvh.no-ip. 1083 [ - + ]: 116705 : if (objDesc == NULL)
1756 alvherre@alvh.no-ip. 1084 :UBC 0 : continue;
1085 : :
1086 : : /*
1087 : : * If, at any stage of the recursive search, we reached the object via
1088 : : * an AUTO, INTERNAL, PARTITION, or EXTENSION dependency, then it's
1089 : : * okay to delete it even in RESTRICT mode.
1090 : : */
5679 tgl@sss.pgh.pa.us 1091 [ + + ]:CBC 116705 : if (extra->flags & (DEPFLAG_AUTO |
1092 : : DEPFLAG_INTERNAL |
1093 : : DEPFLAG_PARTITION |
1094 : : DEPFLAG_EXTENSION))
1095 : : {
1096 : : /*
1097 : : * auto-cascades are reported at DEBUG2, not msglevel. We don't
1098 : : * try to combine them with the regular message because the
1099 : : * results are too confusing when client_min_messages and
1100 : : * log_min_messages are different.
1101 : : */
6654 1102 [ + + ]: 111130 : ereport(DEBUG2,
1103 : : (errmsg_internal("drop auto-cascades to %s",
1104 : : objDesc)));
1105 : : }
1106 [ + + ]: 5575 : else if (behavior == DROP_RESTRICT)
1107 : : {
2234 michael@paquier.xyz 1108 : 417 : char *otherDesc = getObjectDescription(&extra->dependee,
1109 : : false);
1110 : :
1756 alvherre@alvh.no-ip. 1111 [ + - ]: 417 : if (otherDesc)
1112 : : {
1113 [ + - ]: 417 : if (numReportedClient < MAX_REPORTED_DEPS)
1114 : : {
1115 : : /* separate entries with a newline */
1116 [ + + ]: 417 : if (clientdetail.len != 0)
1117 : 161 : appendStringInfoChar(&clientdetail, '\n');
1118 : 417 : appendStringInfo(&clientdetail, _("%s depends on %s"),
1119 : : objDesc, otherDesc);
1120 : 417 : numReportedClient++;
1121 : : }
1122 : : else
1756 alvherre@alvh.no-ip. 1123 :UBC 0 : numNotReportedClient++;
1124 : : /* separate entries with a newline */
1756 alvherre@alvh.no-ip. 1125 [ + + ]:CBC 417 : if (logdetail.len != 0)
1126 : 161 : appendStringInfoChar(&logdetail, '\n');
1127 : 417 : appendStringInfo(&logdetail, _("%s depends on %s"),
1128 : : objDesc, otherDesc);
1129 : 417 : pfree(otherDesc);
1130 : : }
1131 : : else
6651 tgl@sss.pgh.pa.us 1132 :UBC 0 : numNotReportedClient++;
6654 tgl@sss.pgh.pa.us 1133 :CBC 417 : ok = false;
1134 : : }
1135 : : else
1136 : : {
6651 1137 [ + + ]: 5158 : if (numReportedClient < MAX_REPORTED_DEPS)
1138 : : {
1139 : : /* separate entries with a newline */
1140 [ + + ]: 4239 : if (clientdetail.len != 0)
1141 : 3197 : appendStringInfoChar(&clientdetail, '\n');
1142 : 4239 : appendStringInfo(&clientdetail, _("drop cascades to %s"),
1143 : : objDesc);
1144 : 4239 : numReportedClient++;
1145 : : }
1146 : : else
1147 : 919 : numNotReportedClient++;
1148 : : /* separate entries with a newline */
1149 [ + + ]: 5158 : if (logdetail.len != 0)
1150 : 4116 : appendStringInfoChar(&logdetail, '\n');
1151 : 5158 : appendStringInfo(&logdetail, _("drop cascades to %s"),
1152 : : objDesc);
1153 : : }
1154 : :
1155 : 116705 : pfree(objDesc);
1156 : : }
1157 : :
1158 [ + + ]: 22169 : if (numNotReportedClient > 0)
6363 peter_e@gmx.net 1159 : 10 : appendStringInfo(&clientdetail, ngettext("\nand %d other object "
1160 : : "(see server log for list)",
1161 : : "\nand %d other objects "
1162 : : "(see server log for list)",
1163 : : numNotReportedClient),
1164 : : numNotReportedClient);
1165 : :
6654 tgl@sss.pgh.pa.us 1166 [ + + ]: 22169 : if (!ok)
1167 : : {
1168 [ + + ]: 256 : if (origObject)
1169 [ + - ]: 252 : ereport(ERROR,
1170 : : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1171 : : errmsg("cannot drop %s because other objects depend on it",
1172 : : getObjectDescription(origObject, false)),
1173 : : errdetail_internal("%s", clientdetail.data),
1174 : : errdetail_log("%s", logdetail.data),
1175 : : errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
1176 : : else
1177 [ + - ]: 4 : ereport(ERROR,
1178 : : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1179 : : errmsg("cannot drop desired object(s) because other objects depend on them"),
1180 : : errdetail_internal("%s", clientdetail.data),
1181 : : errdetail_log("%s", logdetail.data),
1182 : : errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
1183 : : }
6651 1184 [ + + ]: 21913 : else if (numReportedClient > 1)
1185 : : {
1186 [ + - ]: 475 : ereport(msglevel,
1187 : : (errmsg_plural("drop cascades to %d other object",
1188 : : "drop cascades to %d other objects",
1189 : : numReportedClient + numNotReportedClient,
1190 : : numReportedClient + numNotReportedClient),
1191 : : errdetail_internal("%s", clientdetail.data),
1192 : : errdetail_log("%s", logdetail.data)));
1193 : : }
1194 [ + + ]: 21438 : else if (numReportedClient == 1)
1195 : : {
1196 : : /* we just use the single item as-is */
1197 [ + - ]: 567 : ereport(msglevel,
1198 : : (errmsg_internal("%s", clientdetail.data)));
1199 : : }
1200 : :
1201 : 21913 : pfree(clientdetail.data);
1202 : 21913 : pfree(logdetail.data);
1203 : : }
1204 : :
1205 : : /*
1206 : : * Drop an object by OID. Works for most catalogs, if no special processing
1207 : : * is needed.
1208 : : */
1209 : : static void
2270 peter@eisentraut.org 1210 : 4644 : DropObjectById(const ObjectAddress *object)
1211 : : {
1212 : : SysCacheIdentifier cacheId;
1213 : : Relation rel;
1214 : : HeapTuple tup;
1215 : :
1216 : 4644 : cacheId = get_object_catcache_oid(object->classId);
1217 : :
1218 : 4644 : rel = table_open(object->classId, RowExclusiveLock);
1219 : :
1220 : : /*
1221 : : * Use the system cache for the oid column, if one exists.
1222 : : */
1223 [ + + ]: 4644 : if (cacheId >= 0)
1224 : : {
1225 : 1698 : tup = SearchSysCache1(cacheId, ObjectIdGetDatum(object->objectId));
1226 [ - + ]: 1698 : if (!HeapTupleIsValid(tup))
2270 peter@eisentraut.org 1227 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for %s %u",
1228 : : get_object_class_descr(object->classId), object->objectId);
1229 : :
2270 peter@eisentraut.org 1230 :CBC 1698 : CatalogTupleDelete(rel, &tup->t_self);
1231 : :
1232 : 1698 : ReleaseSysCache(tup);
1233 : : }
1234 : : else
1235 : : {
1236 : : ScanKeyData skey[1];
1237 : : SysScanDesc scan;
1238 : :
1239 : 2946 : ScanKeyInit(&skey[0],
1240 : 2946 : get_object_attnum_oid(object->classId),
1241 : : BTEqualStrategyNumber, F_OIDEQ,
1242 : 2946 : ObjectIdGetDatum(object->objectId));
1243 : :
1244 : 2946 : scan = systable_beginscan(rel, get_object_oid_index(object->classId), true,
1245 : : NULL, 1, skey);
1246 : :
1247 : : /* we expect exactly one match */
1248 : 2946 : tup = systable_getnext(scan);
1249 [ - + ]: 2946 : if (!HeapTupleIsValid(tup))
2270 peter@eisentraut.org 1250 [ # # ]:UBC 0 : elog(ERROR, "could not find tuple for %s %u",
1251 : : get_object_class_descr(object->classId), object->objectId);
1252 : :
2270 peter@eisentraut.org 1253 :CBC 2946 : CatalogTupleDelete(rel, &tup->t_self);
1254 : :
1255 : 2946 : systable_endscan(scan);
1256 : : }
1257 : :
1258 : 4644 : table_close(rel, RowExclusiveLock);
1259 : 4644 : }
1260 : :
1261 : : /*
1262 : : * deleteOneObject: delete a single object for performDeletion.
1263 : : *
1264 : : * *depRel is the already-open pg_depend relation.
1265 : : */
1266 : : static void
5013 tgl@sss.pgh.pa.us 1267 : 147769 : deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
1268 : : {
1269 : : ScanKeyData key[3];
1270 : : int nkeys;
1271 : : SysScanDesc scan;
1272 : : HeapTuple tup;
1273 : :
1274 : : /* DROP hook of the objects being removed */
4922 rhaas@postgresql.org 1275 [ + + ]: 147769 : InvokeObjectDropHookArg(object->classId, object->objectId,
1276 : : object->objectSubId, flags);
1277 : :
1278 : : /*
1279 : : * Close depRel if we are doing a drop concurrently. The object deletion
1280 : : * subroutine will commit the current transaction, so we can't keep the
1281 : : * relation open across doDeletion().
1282 : : */
5060 simon@2ndQuadrant.co 1283 [ + + ]: 147769 : if (flags & PERFORM_DELETION_CONCURRENTLY)
2775 andres@anarazel.de 1284 : 54 : table_close(*depRel, RowExclusiveLock);
1285 : :
1286 : : /*
1287 : : * Delete the object itself, in an object-type-dependent way.
1288 : : *
1289 : : * We used to do this after removing the outgoing dependency links, but it
1290 : : * seems just as reasonable to do it beforehand. In the concurrent case
1291 : : * we *must* do it in this order, because we can't make any transactional
1292 : : * updates before calling doDeletion() --- they'd get committed right
1293 : : * away, which is not cool if the deletion then fails.
1294 : : */
5060 simon@2ndQuadrant.co 1295 : 147769 : doDeletion(object, flags);
1296 : :
1297 : : /*
1298 : : * Reopen depRel if we closed it above
1299 : : */
1300 [ + + ]: 147763 : if (flags & PERFORM_DELETION_CONCURRENTLY)
2775 andres@anarazel.de 1301 : 54 : *depRel = table_open(DependRelationId, RowExclusiveLock);
1302 : :
1303 : : /*
1304 : : * Now remove any pg_depend records that link from this object to others.
1305 : : * (Any records linking to this object should be gone already.)
1306 : : *
1307 : : * When dropping a whole object (subId = 0), remove all pg_depend records
1308 : : * for its sub-objects too.
1309 : : */
6654 tgl@sss.pgh.pa.us 1310 : 147763 : ScanKeyInit(&key[0],
1311 : : Anum_pg_depend_classid,
1312 : : BTEqualStrategyNumber, F_OIDEQ,
1313 : 147763 : ObjectIdGetDatum(object->classId));
1314 : 147763 : ScanKeyInit(&key[1],
1315 : : Anum_pg_depend_objid,
1316 : : BTEqualStrategyNumber, F_OIDEQ,
1317 : 147763 : ObjectIdGetDatum(object->objectId));
1318 [ + + ]: 147763 : if (object->objectSubId != 0)
1319 : : {
1320 : 1398 : ScanKeyInit(&key[2],
1321 : : Anum_pg_depend_objsubid,
1322 : : BTEqualStrategyNumber, F_INT4EQ,
1323 : 1398 : Int32GetDatum(object->objectSubId));
1324 : 1398 : nkeys = 3;
1325 : : }
1326 : : else
1327 : 146365 : nkeys = 2;
1328 : :
5013 1329 : 147763 : scan = systable_beginscan(*depRel, DependDependerIndexId, true,
1330 : : NULL, nkeys, key);
1331 : :
6654 1332 [ + + ]: 352652 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
1333 : : {
3494 1334 : 204889 : CatalogTupleDelete(*depRel, &tup->t_self);
1335 : : }
1336 : :
6654 1337 : 147763 : systable_endscan(scan);
1338 : :
1339 : : /*
1340 : : * Delete shared dependency references related to this object. Again, if
1341 : : * subId = 0, remove records for sub-objects too.
1342 : : */
6426 1343 : 147763 : deleteSharedDependencyRecordsFor(object->classId, object->objectId,
1344 : 147763 : object->objectSubId);
1345 : :
1346 : :
1347 : : /*
1348 : : * Delete any comments, security labels, or initial privileges associated
1349 : : * with this object. (This is a convenient place to do these things,
1350 : : * rather than having every object type know to do it.) As above, all
1351 : : * these functions must remove records for sub-objects too if the subid is
1352 : : * zero.
1353 : : */
6654 1354 : 147763 : DeleteComments(object->objectId, object->classId, object->objectSubId);
5813 rhaas@postgresql.org 1355 : 147763 : DeleteSecurityLabel(object);
3795 sfrost@snowman.net 1356 : 147763 : DeleteInitPrivs(object);
1357 : :
1358 : : /*
1359 : : * CommandCounterIncrement here to ensure that preceding changes are all
1360 : : * visible to the next deletion step.
1361 : : */
6654 tgl@sss.pgh.pa.us 1362 : 147763 : CommandCounterIncrement();
1363 : :
1364 : : /*
1365 : : * And we're done!
1366 : : */
1367 : 147763 : }
1368 : :
1369 : : /*
1370 : : * doDeletion: actually delete a single object
1371 : : */
1372 : : static void
5256 simon@2ndQuadrant.co 1373 : 147769 : doDeletion(const ObjectAddress *object, int flags)
1374 : : {
884 peter@eisentraut.org 1375 [ + + + + : 147769 : switch (object->classId)
+ + + + +
+ + + + +
+ + + -
- ]
1376 : : {
1377 : 49987 : case RelationRelationId:
1378 : : {
8743 tgl@sss.pgh.pa.us 1379 : 49987 : char relKind = get_rel_relkind(object->objectId);
1380 : :
3142 alvherre@alvh.no-ip. 1381 [ + + + + ]: 49987 : if (relKind == RELKIND_INDEX ||
1382 : : relKind == RELKIND_PARTITIONED_INDEX)
8758 bruce@momjian.us 1383 : 15934 : {
3555 tgl@sss.pgh.pa.us 1384 : 15934 : bool concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0);
2708 peter@eisentraut.org 1385 : 15934 : bool concurrent_lock_mode = ((flags & PERFORM_DELETION_CONCURRENT_LOCK) != 0);
1386 : :
8758 bruce@momjian.us 1387 [ - + ]: 15934 : Assert(object->objectSubId == 0);
2708 peter@eisentraut.org 1388 : 15934 : index_drop(object->objectId, concurrent, concurrent_lock_mode);
1389 : : }
1390 : : else
1391 : : {
8758 bruce@momjian.us 1392 [ + + ]: 34053 : if (object->objectSubId != 0)
1393 : 1398 : RemoveAttributeById(object->objectId,
1394 : 1398 : object->objectSubId);
1395 : : else
1396 : 32655 : heap_drop_with_catalog(object->objectId);
1397 : : }
1398 : :
1399 : : /*
1400 : : * for a sequence, in addition to dropping the heap, also
1401 : : * delete pg_sequence tuple
1402 : : */
3537 peter_e@gmx.net 1403 [ + + ]: 49983 : if (relKind == RELKIND_SEQUENCE)
1404 : 659 : DeleteSequenceTuple(object->objectId);
8758 bruce@momjian.us 1405 : 49983 : break;
1406 : : }
1407 : :
884 peter@eisentraut.org 1408 : 5400 : case ProcedureRelationId:
8812 tgl@sss.pgh.pa.us 1409 : 5400 : RemoveFunctionById(object->objectId);
1410 : 5400 : break;
1411 : :
884 peter@eisentraut.org 1412 : 52050 : case TypeRelationId:
8812 tgl@sss.pgh.pa.us 1413 : 52050 : RemoveTypeById(object->objectId);
1414 : 52050 : break;
1415 : :
884 peter@eisentraut.org 1416 : 18448 : case ConstraintRelationId:
8812 tgl@sss.pgh.pa.us 1417 : 18448 : RemoveConstraintById(object->objectId);
1418 : 18447 : break;
1419 : :
884 peter@eisentraut.org 1420 : 2415 : case AttrDefaultRelationId:
8809 tgl@sss.pgh.pa.us 1421 : 2415 : RemoveAttrDefaultById(object->objectId);
1422 : 2415 : break;
1423 : :
884 peter@eisentraut.org 1424 : 61 : case LargeObjectRelationId:
6103 itagaki.takahiro@gma 1425 : 61 : LargeObjectDrop(object->objectId);
1426 : 61 : break;
1427 : :
884 peter@eisentraut.org 1428 : 427 : case OperatorRelationId:
8812 tgl@sss.pgh.pa.us 1429 : 427 : RemoveOperatorById(object->objectId);
1430 : 427 : break;
1431 : :
884 peter@eisentraut.org 1432 : 2110 : case RewriteRelationId:
8812 tgl@sss.pgh.pa.us 1433 : 2110 : RemoveRewriteRuleById(object->objectId);
1434 : 2109 : break;
1435 : :
884 peter@eisentraut.org 1436 : 9860 : case TriggerRelationId:
8812 tgl@sss.pgh.pa.us 1437 : 9860 : RemoveTriggerById(object->objectId);
1438 : 9860 : break;
1439 : :
884 peter@eisentraut.org 1440 : 523 : case StatisticExtRelationId:
3392 tgl@sss.pgh.pa.us 1441 : 523 : RemoveStatisticsById(object->objectId);
1442 : 523 : break;
1443 : :
884 peter@eisentraut.org 1444 : 36 : case TSConfigRelationId:
6946 tgl@sss.pgh.pa.us 1445 : 36 : RemoveTSConfigurationById(object->objectId);
1446 : 36 : break;
1447 : :
884 peter@eisentraut.org 1448 : 103 : case ExtensionRelationId:
5679 tgl@sss.pgh.pa.us 1449 : 103 : RemoveExtensionById(object->objectId);
1450 : 103 : break;
1451 : :
884 peter@eisentraut.org 1452 : 534 : case PolicyRelationId:
4360 sfrost@snowman.net 1453 : 534 : RemovePolicyById(object->objectId);
1454 : 534 : break;
1455 : :
884 peter@eisentraut.org 1456 : 132 : case PublicationNamespaceRelationId:
1765 akapila@postgresql.o 1457 : 132 : RemovePublicationSchemaById(object->objectId);
1458 : 132 : break;
1459 : :
884 peter@eisentraut.org 1460 : 643 : case PublicationRelRelationId:
3507 peter_e@gmx.net 1461 : 643 : RemovePublicationRelById(object->objectId);
1462 : 643 : break;
1463 : :
884 peter@eisentraut.org 1464 : 396 : case PublicationRelationId:
1814 akapila@postgresql.o 1465 : 396 : RemovePublicationById(object->objectId);
1466 : 396 : break;
1467 : :
884 peter@eisentraut.org 1468 : 4644 : case CastRelationId:
1469 : : case CollationRelationId:
1470 : : case ConversionRelationId:
1471 : : case LanguageRelationId:
1472 : : case OperatorClassRelationId:
1473 : : case OperatorFamilyRelationId:
1474 : : case AccessMethodRelationId:
1475 : : case AccessMethodOperatorRelationId:
1476 : : case AccessMethodProcedureRelationId:
1477 : : case PropgraphElementRelationId:
1478 : : case PropgraphElementLabelRelationId:
1479 : : case PropgraphLabelRelationId:
1480 : : case PropgraphLabelPropertyRelationId:
1481 : : case PropgraphPropertyRelationId:
1482 : : case NamespaceRelationId:
1483 : : case TSParserRelationId:
1484 : : case TSDictionaryRelationId:
1485 : : case TSTemplateRelationId:
1486 : : case ForeignDataWrapperRelationId:
1487 : : case ForeignServerRelationId:
1488 : : case UserMappingRelationId:
1489 : : case DefaultAclRelationId:
1490 : : case EventTriggerRelationId:
1491 : : case TransformRelationId:
1492 : : case AuthMemRelationId:
2270 1493 : 4644 : DropObjectById(object);
4141 peter_e@gmx.net 1494 : 4644 : break;
1495 : :
1496 : : /*
1497 : : * These global object types are not supported here.
1498 : : */
884 peter@eisentraut.org 1499 :UBC 0 : case AuthIdRelationId:
1500 : : case DatabaseRelationId:
1501 : : case TableSpaceRelationId:
1502 : : case SubscriptionRelationId:
1503 : : case ParameterAclRelationId:
3392 tgl@sss.pgh.pa.us 1504 [ # # ]: 0 : elog(ERROR, "global objects cannot be deleted by doDeletion");
1505 : : break;
1506 : :
884 peter@eisentraut.org 1507 : 0 : default:
1508 [ # # ]: 0 : elog(ERROR, "unsupported object class: %u", object->classId);
1509 : : }
8812 tgl@sss.pgh.pa.us 1510 :CBC 147763 : }
1511 : :
1512 : : /*
1513 : : * AcquireDeletionLock - acquire a suitable lock for deleting an object
1514 : : *
1515 : : * Accepts the same flags as performDeletion (though currently only
1516 : : * PERFORM_DELETION_CONCURRENTLY does anything).
1517 : : *
1518 : : * We use LockRelation for relations, and otherwise LockSharedObject or
1519 : : * LockDatabaseObject as appropriate for the object type.
1520 : : */
1521 : : void
5256 simon@2ndQuadrant.co 1522 : 185157 : AcquireDeletionLock(const ObjectAddress *object, int flags)
1523 : : {
6654 tgl@sss.pgh.pa.us 1524 [ + + ]: 185157 : if (object->classId == RelationRelationId)
1525 : : {
1526 : : /*
1527 : : * In DROP INDEX CONCURRENTLY, take only ShareUpdateExclusiveLock on
1528 : : * the index for the moment. index_drop() will promote the lock once
1529 : : * it's safe to do so. In all other cases we need full exclusive
1530 : : * lock.
1531 : : */
5060 simon@2ndQuadrant.co 1532 [ + + ]: 63040 : if (flags & PERFORM_DELETION_CONCURRENTLY)
5256 1533 : 54 : LockRelationOid(object->objectId, ShareUpdateExclusiveLock);
1534 : : else
1535 : 62986 : LockRelationOid(object->objectId, AccessExclusiveLock);
1536 : : }
24 jdavis@postgresql.or 1537 [ + + ]: 122117 : else if (IsSharedRelation(object->classId))
1470 rhaas@postgresql.org 1538 : 28 : LockSharedObject(object->classId, object->objectId, 0,
1539 : : AccessExclusiveLock);
1540 : : else
1541 : : {
1542 : : /* assume we should lock the whole object not a sub-object */
6654 tgl@sss.pgh.pa.us 1543 : 122089 : LockDatabaseObject(object->classId, object->objectId, 0,
1544 : : AccessExclusiveLock);
1545 : : }
1546 : 185157 : }
1547 : :
1548 : : /*
1549 : : * ReleaseDeletionLock - release an object deletion lock
1550 : : *
1551 : : * Companion to AcquireDeletionLock.
1552 : : */
1553 : : void
1554 : 1269 : ReleaseDeletionLock(const ObjectAddress *object)
1555 : : {
1556 [ + + ]: 1269 : if (object->classId == RelationRelationId)
1557 : 37 : UnlockRelationOid(object->objectId, AccessExclusiveLock);
24 jdavis@postgresql.or 1558 [ + + ]: 1232 : else if (IsSharedRelation(object->classId))
1559 : 1 : UnlockSharedObject(object->classId, object->objectId, 0,
1560 : : AccessExclusiveLock);
1561 : : else
1562 : : /* assume we should lock the whole object not a sub-object */
6654 tgl@sss.pgh.pa.us 1563 : 1231 : UnlockDatabaseObject(object->classId, object->objectId, 0,
1564 : : AccessExclusiveLock);
1565 : 1269 : }
1566 : :
1567 : : /*
1568 : : * recordDependencyOnExpr - find expression dependencies
1569 : : *
1570 : : * This is used to find the dependencies of rules, constraint expressions,
1571 : : * etc.
1572 : : *
1573 : : * Given an expression or query in node-tree form, find all the objects
1574 : : * it refers to (tables, columns, operators, functions, etc). Record
1575 : : * a dependency of the specified type from the given depender object
1576 : : * to each object mentioned in the expression.
1577 : : *
1578 : : * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
1579 : : * It can be NIL if no such variables are expected.
1580 : : */
1581 : : void
8808 1582 : 13306 : recordDependencyOnExpr(const ObjectAddress *depender,
1583 : : Node *expr, List *rtable,
1584 : : DependencyType behavior)
1585 : : {
1586 : : ObjectAddresses *addrs;
1587 : :
277 1588 : 13306 : addrs = new_object_addresses();
1589 : :
1590 : : /* Collect all dependencies from the expression */
1591 : 13306 : collectDependenciesOfExpr(addrs, expr, rtable);
1592 : :
1593 : : /* Remove duplicates */
1594 : 13306 : eliminate_duplicate_dependencies(addrs);
1595 : :
1596 : : /* And record 'em */
8492 1597 : 13306 : recordMultipleDependencies(depender,
277 1598 : 13306 : addrs->refs, addrs->numrefs,
1599 : : behavior);
1600 : :
1601 : 13306 : free_object_addresses(addrs);
1602 : 13306 : }
1603 : :
1604 : : /*
1605 : : * collectDependenciesOfExpr - collect expression dependencies
1606 : : *
1607 : : * This function analyzes an expression or query in node-tree form to
1608 : : * find all the objects it refers to (tables, columns, operators,
1609 : : * functions, etc.) and adds them to the provided ObjectAddresses
1610 : : * structure. Unlike recordDependencyOnExpr, this function does not
1611 : : * immediately record the dependencies, allowing the caller to add to,
1612 : : * filter, or modify the collected dependencies before recording them.
1613 : : *
1614 : : * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
1615 : : * It can be NIL if no such variables are expected.
1616 : : *
1617 : : * Note: the returned list may well contain duplicates. The caller should
1618 : : * de-duplicate before recording the dependencies. Within this file, callers
1619 : : * must call eliminate_duplicate_dependencies(). External callers typically
1620 : : * go through record_object_address_dependencies() which will see to that.
1621 : : * This choice allows collecting dependencies from multiple sources without
1622 : : * redundant de-duplication work.
1623 : : */
1624 : : void
1625 : 45052 : collectDependenciesOfExpr(ObjectAddresses *addrs,
1626 : : Node *expr, List *rtable)
1627 : : {
1628 : : find_expr_references_context context;
1629 : :
1630 : 45052 : context.addrs = addrs;
1631 : :
1632 : : /* Set up interpretation for Vars at varlevelsup = 0 */
1633 : 45052 : context.rtables = list_make1(rtable);
1634 : :
1635 : : /* Scan the expression tree for referenceable objects */
1636 : 45052 : find_expr_references_walker(expr, &context);
8492 1637 : 45048 : }
1638 : :
1639 : : /*
1640 : : * recordDependencyOnSingleRelExpr - find expression dependencies
1641 : : *
1642 : : * As above, but only one relation is expected to be referenced (with
1643 : : * varno = 1 and varlevelsup = 0). Pass the relation OID instead of a
1644 : : * range table. An additional frammish is that dependencies on that
1645 : : * relation's component columns will be marked with 'self_behavior',
1646 : : * whereas 'behavior' is used for everything else; also, if 'reverse_self'
1647 : : * is true, those dependencies are reversed so that the columns are made
1648 : : * to depend on the table not vice versa.
1649 : : *
1650 : : * NOTE: the caller should ensure that a whole-table dependency on the
1651 : : * specified relation is created separately, if one is needed. In particular,
1652 : : * a whole-row Var "relation.*" will not cause this routine to emit any
1653 : : * dependency item. This is appropriate behavior for subexpressions of an
1654 : : * ordinary query, so other cases need to cope as necessary.
1655 : : */
1656 : : void
1657 : 8935 : recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
1658 : : Node *expr, Oid relId,
1659 : : DependencyType behavior,
1660 : : DependencyType self_behavior,
1661 : : bool reverse_self)
1662 : : {
1663 : : find_expr_references_context context;
1503 peter@eisentraut.org 1664 : 8935 : RangeTblEntry rte = {0};
1665 : :
7312 alvherre@alvh.no-ip. 1666 : 8935 : context.addrs = new_object_addresses();
1667 : :
1668 : : /* We gin up a rather bogus rangetable list to handle Vars */
8492 tgl@sss.pgh.pa.us 1669 : 8935 : rte.type = T_RangeTblEntry;
1670 : 8935 : rte.rtekind = RTE_RELATION;
1671 : 8935 : rte.relid = relId;
3354 1672 : 8935 : rte.relkind = RELKIND_RELATION; /* no need for exactness here */
2888 1673 : 8935 : rte.rellockmode = AccessShareLock;
1674 : :
8128 neilc@samurai.com 1675 : 8935 : context.rtables = list_make1(list_make1(&rte));
1676 : :
1677 : : /* Scan the expression tree for referenceable objects */
8492 tgl@sss.pgh.pa.us 1678 : 8935 : find_expr_references_walker(expr, &context);
1679 : :
1680 : : /* Remove any duplicates */
7312 alvherre@alvh.no-ip. 1681 : 8935 : eliminate_duplicate_dependencies(context.addrs);
1682 : :
1683 : : /* Separate self-dependencies if necessary */
2593 tgl@sss.pgh.pa.us 1684 [ + + - + ]: 8935 : if ((behavior != self_behavior || reverse_self) &&
1685 [ + + ]: 1439 : context.addrs->numrefs > 0)
1686 : : {
1687 : : ObjectAddresses *self_addrs;
1688 : : ObjectAddress *outobj;
1689 : : int oldref,
1690 : : outrefs;
1691 : :
7312 alvherre@alvh.no-ip. 1692 : 1430 : self_addrs = new_object_addresses();
1693 : :
1694 : 1430 : outobj = context.addrs->refs;
8492 tgl@sss.pgh.pa.us 1695 : 1430 : outrefs = 0;
7312 alvherre@alvh.no-ip. 1696 [ + + ]: 5828 : for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
1697 : : {
1698 : 4398 : ObjectAddress *thisobj = context.addrs->refs + oldref;
1699 : :
7805 tgl@sss.pgh.pa.us 1700 [ + + ]: 4398 : if (thisobj->classId == RelationRelationId &&
8492 1701 [ + + ]: 1796 : thisobj->objectId == relId)
1702 : : {
1703 : : /* Move this ref into self_addrs */
6654 1704 : 1732 : add_exact_object_address(thisobj, self_addrs);
1705 : : }
1706 : : else
1707 : : {
1708 : : /* Keep it in context.addrs */
1709 : 2666 : *outobj = *thisobj;
8492 1710 : 2666 : outobj++;
1711 : 2666 : outrefs++;
1712 : : }
1713 : : }
7312 alvherre@alvh.no-ip. 1714 : 1430 : context.addrs->numrefs = outrefs;
1715 : :
1716 : : /* Record the self-dependencies with the appropriate direction */
2593 tgl@sss.pgh.pa.us 1717 [ + + ]: 1430 : if (!reverse_self)
3550 rhaas@postgresql.org 1718 : 1290 : recordMultipleDependencies(depender,
1938 tmunro@postgresql.or 1719 : 1290 : self_addrs->refs, self_addrs->numrefs,
1720 : : self_behavior);
1721 : : else
1722 : : {
1723 : : /* Can't use recordMultipleDependencies, so do it the hard way */
1724 : : int selfref;
1725 : :
2593 tgl@sss.pgh.pa.us 1726 [ + + ]: 333 : for (selfref = 0; selfref < self_addrs->numrefs; selfref++)
1727 : : {
1728 : 193 : ObjectAddress *thisobj = self_addrs->refs + selfref;
1729 : :
1730 : 193 : recordDependencyOn(thisobj, depender, self_behavior);
1731 : : }
1732 : : }
1733 : :
7312 alvherre@alvh.no-ip. 1734 : 1430 : free_object_addresses(self_addrs);
1735 : : }
1736 : :
1737 : : /* Record the external dependencies */
8808 tgl@sss.pgh.pa.us 1738 : 8935 : recordMultipleDependencies(depender,
1938 tmunro@postgresql.or 1739 : 8935 : context.addrs->refs, context.addrs->numrefs,
1740 : : behavior);
1741 : :
7312 alvherre@alvh.no-ip. 1742 : 8935 : free_object_addresses(context.addrs);
8808 tgl@sss.pgh.pa.us 1743 : 8935 : }
1744 : :
1745 : : /*
1746 : : * We require USAGE on a type to store a dependency on it. This helper
1747 : : * function does the appropriate privilege checks.
1748 : : *
1749 : : * NB: Other objects have privileges of their own, but recording those
1750 : : * dependencies doesn't require holding them. For example, an expression may
1751 : : * reference a function for which the user lacks EXECUTE. Instead, EXECUTE is
1752 : : * checked when the function is executed.
1753 : : */
1754 : : static void
17 nathan@postgresql.or 1755 : 24944 : check_usage_on_types(ObjectAddresses *addrs, Oid roleid)
1756 : : {
1757 [ + + ]: 240529 : for (int i = 0; i < addrs->numrefs; i++)
1758 : : {
1759 : 215633 : ObjectAddress *ref = &addrs->refs[i];
1760 : : AclResult aclresult;
1761 : :
1762 [ + + ]: 215633 : if (ref->classId != TypeRelationId)
1763 : 172129 : continue;
1764 : :
1765 : : /* we don't record dependencies on pinned types */
1766 [ + + ]: 43504 : if (IsPinnedObject(ref->classId, ref->objectId))
1767 : 35936 : continue;
1768 : :
1769 : 7568 : aclresult = object_aclcheck(ref->classId, ref->objectId,
1770 : : roleid, ACL_USAGE);
1771 [ + + ]: 7568 : if (aclresult != ACLCHECK_OK)
1772 : 48 : aclcheck_error_type(aclresult, ref->objectId);
1773 : : }
1774 : 24896 : }
1775 : :
1776 : : /*
1777 : : * CheckUsageOnTypesInExpr - require USAGE on all types named by an expression
1778 : : *
1779 : : * rtable is the rangetable for interpreting Vars (or NIL if none are
1780 : : * expected). roleid is the role whose USAGE is required.
1781 : : */
1782 : : void
1783 : 17325 : CheckUsageOnTypesInExpr(Node *expr, List *rtable, Oid roleid)
1784 : : {
1785 : 17325 : ObjectAddresses *addrs = new_object_addresses();
1786 : :
1787 : 17325 : collectDependenciesOfExpr(addrs, expr, rtable);
1788 : 17325 : eliminate_duplicate_dependencies(addrs);
1789 : 17325 : check_usage_on_types(addrs, roleid);
1790 : 17305 : free_object_addresses(addrs);
1791 : 17305 : }
1792 : :
1793 : : /*
1794 : : * CheckUsageOnTypesInSingleRelExpr - as above, for a single-rel expression
1795 : : *
1796 : : * Like recordDependencyOnSingleRelExpr(), this handles expressions whose Vars
1797 : : * all refer to one relation. roleid is the role whose USAGE is required.
1798 : : */
1799 : : void
1800 : 7627 : CheckUsageOnTypesInSingleRelExpr(Node *expr, Oid relId, Oid roleid)
1801 : : {
1802 : : find_expr_references_context context;
1803 : 7627 : RangeTblEntry rte = {0};
1804 : :
1805 : 7627 : context.addrs = new_object_addresses();
1806 : :
1807 : : /* We gin up a rather bogus rangetable list to handle Vars */
1808 : 7627 : rte.type = T_RangeTblEntry;
1809 : 7627 : rte.rtekind = RTE_RELATION;
1810 : 7627 : rte.relid = relId;
1811 : 7627 : rte.relkind = RELKIND_RELATION;
1812 : 7627 : rte.rellockmode = AccessShareLock;
1813 : 7627 : context.rtables = list_make1(list_make1(&rte));
1814 : :
1815 : 7627 : find_expr_references_walker(expr, &context);
1816 : 7619 : eliminate_duplicate_dependencies(context.addrs);
1817 : 7619 : check_usage_on_types(context.addrs, roleid);
1818 : 7591 : free_object_addresses(context.addrs);
1819 : 7591 : }
1820 : :
1821 : : /*
1822 : : * Recursively search an expression tree for object references.
1823 : : *
1824 : : * Note: in many cases we do not need to create dependencies on the datatypes
1825 : : * involved in an expression, because we'll have an indirect dependency via
1826 : : * some other object. For instance Var nodes depend on a column which depends
1827 : : * on the datatype, and OpExpr nodes depend on the operator which depends on
1828 : : * the datatype. However we do need a type dependency if there is no such
1829 : : * indirect dependency, as for example in Const and CoerceToDomain nodes.
1830 : : *
1831 : : * Similarly, we don't need to create dependencies on collations except where
1832 : : * the collation is being freshly introduced to the expression.
1833 : : */
1834 : : static bool
8808 tgl@sss.pgh.pa.us 1835 : 3726576 : find_expr_references_walker(Node *node,
1836 : : find_expr_references_context *context)
1837 : : {
1838 [ + + ]: 3726576 : if (node == NULL)
1839 : 1289390 : return false;
1840 [ + + ]: 2437186 : if (IsA(node, Var))
1841 : : {
1842 : 633407 : Var *var = (Var *) node;
1843 : : List *rtable;
1844 : : RangeTblEntry *rte;
1845 : :
1846 : : /* Find matching rtable entry, or complain if not found */
8128 neilc@samurai.com 1847 [ - + ]: 633407 : if (var->varlevelsup >= list_length(context->rtables))
8438 tgl@sss.pgh.pa.us 1848 [ # # ]:UBC 0 : elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
8128 neilc@samurai.com 1849 :CBC 633407 : rtable = (List *) list_nth(context->rtables, var->varlevelsup);
1850 [ + - - + ]: 633407 : if (var->varno <= 0 || var->varno > list_length(rtable))
8438 tgl@sss.pgh.pa.us 1851 [ # # ]:UBC 0 : elog(ERROR, "invalid varno %d", var->varno);
8808 tgl@sss.pgh.pa.us 1852 :CBC 633407 : rte = rt_fetch(var->varno, rtable);
1853 : :
1854 : : /*
1855 : : * A whole-row Var references no specific columns, so adds no new
1856 : : * dependency. (We assume that there is a whole-table dependency
1857 : : * arising from each underlying rangetable entry. While we could
1858 : : * record such a dependency when finding a whole-row Var that
1859 : : * references a relation directly, it's quite unclear how to extend
1860 : : * that to whole-row Vars for JOINs, so it seems better to leave the
1861 : : * responsibility with the range table. Note that this poses some
1862 : : * risks for identifying dependencies of stand-alone expressions:
1863 : : * whole-table references may need to be created separately.)
1864 : : */
8043 1865 [ + + ]: 633407 : if (var->varattno == InvalidAttrNumber)
1866 : 9460 : return false;
8808 1867 [ + + ]: 623947 : if (rte->rtekind == RTE_RELATION)
1868 : : {
1869 : : /* If it's a plain relation, reference this column */
912 michael@paquier.xyz 1870 : 447603 : add_object_address(RelationRelationId, rte->relid, var->varattno,
1871 : : context->addrs);
1872 : : }
1497 tgl@sss.pgh.pa.us 1873 [ + + ]: 176344 : else if (rte->rtekind == RTE_FUNCTION)
1874 : : {
1875 : : /* Might need to add a dependency on a composite type's column */
1876 : : /* (done out of line, because it's a bit bulky) */
1877 : 85844 : process_function_rte_ref(rte, var->varattno, context);
1878 : : }
1879 : :
1880 : : /*
1881 : : * Vars referencing other RTE types require no additional work. In
1882 : : * particular, a join alias Var can be ignored, because it must
1883 : : * reference a merged USING column. The relevant join input columns
1884 : : * will also be referenced in the join qual, and any type coercion
1885 : : * functions involved in the alias expression will be dealt with when
1886 : : * we scan the RTE itself.
1887 : : */
8808 1888 : 623947 : return false;
1889 : : }
6599 1890 [ + + ]: 1803779 : else if (IsA(node, Const))
1891 : : {
7634 1892 : 286640 : Const *con = (Const *) node;
1893 : : Oid objoid;
1894 : :
1895 : : /* A constant must depend on the constant's datatype */
912 michael@paquier.xyz 1896 : 286640 : add_object_address(TypeRelationId, con->consttype, 0,
1897 : : context->addrs);
1898 : :
1899 : : /*
1900 : : * We must also depend on the constant's collation: it could be
1901 : : * different from the datatype's, if a CollateExpr was const-folded to
1902 : : * a simple constant. However we can save work in the most common
1903 : : * case where the collation is "default", since we know that's pinned.
1904 : : */
1938 tmunro@postgresql.or 1905 [ + + ]: 286640 : if (OidIsValid(con->constcollid) &&
1906 [ + + ]: 116102 : con->constcollid != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 1907 : 28005 : add_object_address(CollationRelationId, con->constcollid, 0,
1908 : : context->addrs);
1909 : :
1910 : : /*
1911 : : * If it's a regclass or similar literal referring to an existing
1912 : : * object, add a reference to that object. (Currently, only the
1913 : : * regclass and regconfig cases have any likely use, but we may as
1914 : : * well handle all the OID-alias datatypes consistently.)
1915 : : */
7634 tgl@sss.pgh.pa.us 1916 [ + + ]: 286640 : if (!con->constisnull)
1917 : : {
1918 [ - - + - : 239592 : switch (con->consttype)
- - - + +
+ + ]
1919 : : {
7634 tgl@sss.pgh.pa.us 1920 :UBC 0 : case REGPROCOID:
1921 : : case REGPROCEDUREOID:
1922 : 0 : objoid = DatumGetObjectId(con->constvalue);
6038 rhaas@postgresql.org 1923 [ # # ]: 0 : if (SearchSysCacheExists1(PROCOID,
1924 : : ObjectIdGetDatum(objoid)))
912 michael@paquier.xyz 1925 : 0 : add_object_address(ProcedureRelationId, objoid, 0,
1926 : : context->addrs);
7634 tgl@sss.pgh.pa.us 1927 : 0 : break;
1928 : 0 : case REGOPEROID:
1929 : : case REGOPERATOROID:
1930 : 0 : objoid = DatumGetObjectId(con->constvalue);
6038 rhaas@postgresql.org 1931 [ # # ]: 0 : if (SearchSysCacheExists1(OPEROID,
1932 : : ObjectIdGetDatum(objoid)))
912 michael@paquier.xyz 1933 : 0 : add_object_address(OperatorRelationId, objoid, 0,
1934 : : context->addrs);
7634 tgl@sss.pgh.pa.us 1935 : 0 : break;
7634 tgl@sss.pgh.pa.us 1936 :CBC 6839 : case REGCLASSOID:
1937 : 6839 : objoid = DatumGetObjectId(con->constvalue);
6038 rhaas@postgresql.org 1938 [ + - ]: 6839 : if (SearchSysCacheExists1(RELOID,
1939 : : ObjectIdGetDatum(objoid)))
912 michael@paquier.xyz 1940 : 6839 : add_object_address(RelationRelationId, objoid, 0,
1941 : : context->addrs);
7634 tgl@sss.pgh.pa.us 1942 : 6839 : break;
7634 tgl@sss.pgh.pa.us 1943 :UBC 0 : case REGTYPEOID:
1944 : 0 : objoid = DatumGetObjectId(con->constvalue);
6038 rhaas@postgresql.org 1945 [ # # ]: 0 : if (SearchSysCacheExists1(TYPEOID,
1946 : : ObjectIdGetDatum(objoid)))
912 michael@paquier.xyz 1947 : 0 : add_object_address(TypeRelationId, objoid, 0,
1948 : : context->addrs);
7634 tgl@sss.pgh.pa.us 1949 : 0 : break;
1502 1950 : 0 : case REGCOLLATIONOID:
1951 : 0 : objoid = DatumGetObjectId(con->constvalue);
1952 [ # # ]: 0 : if (SearchSysCacheExists1(COLLOID,
1953 : : ObjectIdGetDatum(objoid)))
912 michael@paquier.xyz 1954 : 0 : add_object_address(CollationRelationId, objoid, 0,
1955 : : context->addrs);
1502 tgl@sss.pgh.pa.us 1956 : 0 : break;
6946 1957 : 0 : case REGCONFIGOID:
1958 : 0 : objoid = DatumGetObjectId(con->constvalue);
6038 rhaas@postgresql.org 1959 [ # # ]: 0 : if (SearchSysCacheExists1(TSCONFIGOID,
1960 : : ObjectIdGetDatum(objoid)))
912 michael@paquier.xyz 1961 : 0 : add_object_address(TSConfigRelationId, objoid, 0,
1962 : : context->addrs);
6946 tgl@sss.pgh.pa.us 1963 : 0 : break;
1964 : 0 : case REGDICTIONARYOID:
1965 : 0 : objoid = DatumGetObjectId(con->constvalue);
6038 rhaas@postgresql.org 1966 [ # # ]: 0 : if (SearchSysCacheExists1(TSDICTOID,
1967 : : ObjectIdGetDatum(objoid)))
912 michael@paquier.xyz 1968 : 0 : add_object_address(TSDictionaryRelationId, objoid, 0,
1969 : : context->addrs);
6946 tgl@sss.pgh.pa.us 1970 : 0 : break;
1971 : :
4128 andrew@dunslane.net 1972 :CBC 220 : case REGNAMESPACEOID:
1973 : 220 : objoid = DatumGetObjectId(con->constvalue);
1974 [ + - ]: 220 : if (SearchSysCacheExists1(NAMESPACEOID,
1975 : : ObjectIdGetDatum(objoid)))
912 michael@paquier.xyz 1976 : 220 : add_object_address(NamespaceRelationId, objoid, 0,
1977 : : context->addrs);
4128 andrew@dunslane.net 1978 : 220 : break;
1979 : :
1980 : : /*
1981 : : * Dependencies for regrole should be shared among all
1982 : : * databases, so explicitly inhibit to have dependencies.
1983 : : */
1984 : 4 : case REGROLEOID:
1985 [ + - ]: 4 : ereport(ERROR,
1986 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1987 : : errmsg("constant of the type %s cannot be used here",
1988 : : "regrole")));
1989 : : break;
1990 : :
1991 : : /*
1992 : : * Dependencies for regdatabase should be shared among all
1993 : : * databases, so explicitly inhibit to have dependencies.
1994 : : */
423 nathan@postgresql.or 1995 : 4 : case REGDATABASEOID:
1996 [ + - ]: 4 : ereport(ERROR,
1997 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1998 : : errmsg("constant of the type %s cannot be used here",
1999 : : "regdatabase")));
2000 : : break;
2001 : : }
2002 : : }
7634 tgl@sss.pgh.pa.us 2003 : 286632 : return false;
2004 : : }
6599 2005 [ + + ]: 1517139 : else if (IsA(node, Param))
2006 : : {
7469 2007 : 18734 : Param *param = (Param *) node;
2008 : :
2009 : : /* A parameter must depend on the parameter's datatype */
912 michael@paquier.xyz 2010 : 18734 : add_object_address(TypeRelationId, param->paramtype, 0,
2011 : : context->addrs);
2012 : : /* and its collation, just as for Consts */
1938 tmunro@postgresql.or 2013 [ + + ]: 18734 : if (OidIsValid(param->paramcollid) &&
2014 [ + + ]: 4016 : param->paramcollid != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 2015 : 2438 : add_object_address(CollationRelationId, param->paramcollid, 0,
2016 : : context->addrs);
2017 : : }
6599 tgl@sss.pgh.pa.us 2018 [ + + ]: 1498405 : else if (IsA(node, FuncExpr))
2019 : : {
8659 2020 : 141296 : FuncExpr *funcexpr = (FuncExpr *) node;
2021 : :
912 michael@paquier.xyz 2022 : 141296 : add_object_address(ProcedureRelationId, funcexpr->funcid, 0,
2023 : : context->addrs);
2024 : : /* fall through to examine arguments */
2025 : : }
6599 tgl@sss.pgh.pa.us 2026 [ + + ]: 1357109 : else if (IsA(node, OpExpr))
2027 : : {
8424 bruce@momjian.us 2028 : 167019 : OpExpr *opexpr = (OpExpr *) node;
2029 : :
912 michael@paquier.xyz 2030 : 167019 : add_object_address(OperatorRelationId, opexpr->opno, 0,
2031 : : context->addrs);
2032 : : /* fall through to examine arguments */
2033 : : }
6599 tgl@sss.pgh.pa.us 2034 [ + + ]: 1190090 : else if (IsA(node, DistinctExpr))
2035 : : {
8424 bruce@momjian.us 2036 : 16 : DistinctExpr *distinctexpr = (DistinctExpr *) node;
2037 : :
912 michael@paquier.xyz 2038 : 16 : add_object_address(OperatorRelationId, distinctexpr->opno, 0,
2039 : : context->addrs);
2040 : : /* fall through to examine arguments */
2041 : : }
5640 tgl@sss.pgh.pa.us 2042 [ + + ]: 1190074 : else if (IsA(node, NullIfExpr))
2043 : : {
2044 : 759 : NullIfExpr *nullifexpr = (NullIfExpr *) node;
2045 : :
912 michael@paquier.xyz 2046 : 759 : add_object_address(OperatorRelationId, nullifexpr->opno, 0,
2047 : : context->addrs);
2048 : : /* fall through to examine arguments */
2049 : : }
5640 tgl@sss.pgh.pa.us 2050 [ + + ]: 1189315 : else if (IsA(node, ScalarArrayOpExpr))
2051 : : {
2052 : 10917 : ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
2053 : :
912 michael@paquier.xyz 2054 : 10917 : add_object_address(OperatorRelationId, opexpr->opno, 0,
2055 : : context->addrs);
2056 : : /* fall through to examine arguments */
2057 : : }
6599 tgl@sss.pgh.pa.us 2058 [ + + ]: 1178398 : else if (IsA(node, Aggref))
2059 : : {
8808 2060 : 3110 : Aggref *aggref = (Aggref *) node;
2061 : :
912 michael@paquier.xyz 2062 : 3110 : add_object_address(ProcedureRelationId, aggref->aggfnoid, 0,
2063 : : context->addrs);
2064 : : /* fall through to examine arguments */
2065 : : }
6451 tgl@sss.pgh.pa.us 2066 [ + + ]: 1175288 : else if (IsA(node, WindowFunc))
2067 : : {
2068 : 279 : WindowFunc *wfunc = (WindowFunc *) node;
2069 : :
912 michael@paquier.xyz 2070 : 279 : add_object_address(ProcedureRelationId, wfunc->winfnoid, 0,
2071 : : context->addrs);
2072 : : /* fall through to examine arguments */
2073 : : }
2087 tgl@sss.pgh.pa.us 2074 [ + + ]: 1175009 : else if (IsA(node, SubscriptingRef))
2075 : : {
2076 : 5086 : SubscriptingRef *sbsref = (SubscriptingRef *) node;
2077 : :
2078 : : /*
2079 : : * The refexpr should provide adequate dependency on refcontainertype,
2080 : : * and that type in turn depends on refelemtype. However, a custom
2081 : : * subscripting handler might set refrestype to something different
2082 : : * from either of those, in which case we'd better record it.
2083 : : */
2084 [ + + ]: 5086 : if (sbsref->refrestype != sbsref->refcontainertype &&
2085 [ - + ]: 4918 : sbsref->refrestype != sbsref->refelemtype)
912 michael@paquier.xyz 2086 :UBC 0 : add_object_address(TypeRelationId, sbsref->refrestype, 0,
2087 : : context->addrs);
2088 : : /* fall through to examine arguments */
2089 : : }
6579 tgl@sss.pgh.pa.us 2090 [ - + ]:CBC 1169923 : else if (IsA(node, SubPlan))
2091 : : {
2092 : : /* Extra work needed here if we ever need this case */
7547 tgl@sss.pgh.pa.us 2093 [ # # ]:UBC 0 : elog(ERROR, "already-planned subqueries not supported");
2094 : : }
3230 tgl@sss.pgh.pa.us 2095 [ + + ]:CBC 1169923 : else if (IsA(node, FieldSelect))
2096 : : {
2097 : 28904 : FieldSelect *fselect = (FieldSelect *) node;
3226 2098 : 28904 : Oid argtype = getBaseType(exprType((Node *) fselect->arg));
2099 : 28904 : Oid reltype = get_typ_typrelid(argtype);
2100 : :
2101 : : /*
2102 : : * We need a dependency on the specific column named in FieldSelect,
2103 : : * assuming we can identify the pg_class OID for it. (Probably we
2104 : : * always can at the moment, but in future it might be possible for
2105 : : * argtype to be RECORDOID.) If we can make a column dependency then
2106 : : * we shouldn't need a dependency on the column's type; but if we
2107 : : * can't, make a dependency on the type, as it might not appear
2108 : : * anywhere else in the expression.
2109 : : */
2110 [ + + ]: 28904 : if (OidIsValid(reltype))
912 michael@paquier.xyz 2111 : 17490 : add_object_address(RelationRelationId, reltype, fselect->fieldnum,
2112 : : context->addrs);
2113 : : else
2114 : 11414 : add_object_address(TypeRelationId, fselect->resulttype, 0,
2115 : : context->addrs);
2116 : : /* the collation might not be referenced anywhere else, either */
1938 tmunro@postgresql.or 2117 [ + + ]: 28904 : if (OidIsValid(fselect->resultcollid) &&
2118 [ - + ]: 2966 : fselect->resultcollid != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 2119 :UBC 0 : add_object_address(CollationRelationId, fselect->resultcollid, 0,
2120 : : context->addrs);
2121 : : }
3230 tgl@sss.pgh.pa.us 2122 [ + + ]:CBC 1141019 : else if (IsA(node, FieldStore))
2123 : : {
2124 : 128 : FieldStore *fstore = (FieldStore *) node;
3226 2125 : 128 : Oid reltype = get_typ_typrelid(fstore->resulttype);
2126 : :
2127 : : /* similar considerations to FieldSelect, but multiple column(s) */
2128 [ + - ]: 128 : if (OidIsValid(reltype))
2129 : : {
2130 : : ListCell *l;
2131 : :
2132 [ + - + + : 256 : foreach(l, fstore->fieldnums)
+ + ]
912 michael@paquier.xyz 2133 : 128 : add_object_address(RelationRelationId, reltype, lfirst_int(l),
2134 : : context->addrs);
2135 : : }
2136 : : else
912 michael@paquier.xyz 2137 :UBC 0 : add_object_address(TypeRelationId, fstore->resulttype, 0,
2138 : : context->addrs);
2139 : : }
6599 tgl@sss.pgh.pa.us 2140 [ + + ]:CBC 1140891 : else if (IsA(node, RelabelType))
2141 : : {
7267 bruce@momjian.us 2142 : 21614 : RelabelType *relab = (RelabelType *) node;
2143 : :
2144 : : /* since there is no function dependency, need to depend on type */
912 michael@paquier.xyz 2145 : 21614 : add_object_address(TypeRelationId, relab->resulttype, 0,
2146 : : context->addrs);
2147 : : /* the collation might not be referenced anywhere else, either */
1938 tmunro@postgresql.or 2148 [ + + ]: 21614 : if (OidIsValid(relab->resultcollid) &&
2149 [ + + ]: 5266 : relab->resultcollid != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 2150 : 4621 : add_object_address(CollationRelationId, relab->resultcollid, 0,
2151 : : context->addrs);
2152 : : }
6599 tgl@sss.pgh.pa.us 2153 [ + + ]: 1119277 : else if (IsA(node, CoerceViaIO))
2154 : : {
7023 2155 : 4481 : CoerceViaIO *iocoerce = (CoerceViaIO *) node;
2156 : :
2157 : : /* since there is no exposed function, need to depend on type */
912 michael@paquier.xyz 2158 : 4481 : add_object_address(TypeRelationId, iocoerce->resulttype, 0,
2159 : : context->addrs);
2160 : : /* the collation might not be referenced anywhere else, either */
1938 tmunro@postgresql.or 2161 [ + + ]: 4481 : if (OidIsValid(iocoerce->resultcollid) &&
2162 [ + + ]: 3243 : iocoerce->resultcollid != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 2163 : 1113 : add_object_address(CollationRelationId, iocoerce->resultcollid, 0,
2164 : : context->addrs);
2165 : : }
6599 tgl@sss.pgh.pa.us 2166 [ + + ]: 1114796 : else if (IsA(node, ArrayCoerceExpr))
2167 : : {
7093 2168 : 750 : ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
2169 : :
2170 : : /* as above, depend on type */
912 michael@paquier.xyz 2171 : 750 : add_object_address(TypeRelationId, acoerce->resulttype, 0,
2172 : : context->addrs);
2173 : : /* the collation might not be referenced anywhere else, either */
1938 tmunro@postgresql.or 2174 [ + + ]: 750 : if (OidIsValid(acoerce->resultcollid) &&
2175 [ + + ]: 273 : acoerce->resultcollid != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 2176 : 159 : add_object_address(CollationRelationId, acoerce->resultcollid, 0,
2177 : : context->addrs);
2178 : : /* fall through to examine arguments */
2179 : : }
6599 tgl@sss.pgh.pa.us 2180 [ - + ]: 1114046 : else if (IsA(node, ConvertRowtypeExpr))
2181 : : {
7469 tgl@sss.pgh.pa.us 2182 :UBC 0 : ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
2183 : :
2184 : : /* since there is no function dependency, need to depend on type */
912 michael@paquier.xyz 2185 : 0 : add_object_address(TypeRelationId, cvt->resulttype, 0,
2186 : : context->addrs);
2187 : : }
5648 tgl@sss.pgh.pa.us 2188 [ + + ]:CBC 1114046 : else if (IsA(node, CollateExpr))
2189 : : {
2190 : 268 : CollateExpr *coll = (CollateExpr *) node;
2191 : :
912 michael@paquier.xyz 2192 : 268 : add_object_address(CollationRelationId, coll->collOid, 0,
2193 : : context->addrs);
2194 : : }
6599 tgl@sss.pgh.pa.us 2195 [ + + ]: 1113778 : else if (IsA(node, RowExpr))
2196 : : {
7267 bruce@momjian.us 2197 : 204 : RowExpr *rowexpr = (RowExpr *) node;
2198 : :
912 michael@paquier.xyz 2199 : 204 : add_object_address(TypeRelationId, rowexpr->row_typeid, 0,
2200 : : context->addrs);
2201 : : }
79 peter@eisentraut.org 2202 [ + + ]: 1113574 : else if (IsA(node, GraphLabelRef))
2203 : : {
2204 : 213 : GraphLabelRef *glr = (GraphLabelRef *) node;
2205 : :
2206 : : /* GRAPH_TABLE label reference depends on the property graph label */
2207 : 213 : add_object_address(PropgraphLabelRelationId, glr->labelid, 0,
2208 : : context->addrs);
2209 : : }
2210 [ + + ]: 1113361 : else if (IsA(node, GraphPropertyRef))
2211 : : {
2212 : 163 : GraphPropertyRef *gpr = (GraphPropertyRef *) node;
2213 : :
2214 : : /*
2215 : : * GRAPH_TABLE property reference depends on the property graph
2216 : : * property
2217 : : */
2218 : 163 : add_object_address(PropgraphPropertyRelationId, gpr->propid, 0,
2219 : : context->addrs);
2220 : : }
6599 tgl@sss.pgh.pa.us 2221 [ + + ]: 1113198 : else if (IsA(node, RowCompareExpr))
2222 : : {
7547 2223 : 28 : RowCompareExpr *rcexpr = (RowCompareExpr *) node;
2224 : : ListCell *l;
2225 : :
2226 [ + - + + : 84 : foreach(l, rcexpr->opnos)
+ + ]
2227 : : {
912 michael@paquier.xyz 2228 : 56 : add_object_address(OperatorRelationId, lfirst_oid(l), 0,
2229 : : context->addrs);
2230 : : }
7187 tgl@sss.pgh.pa.us 2231 [ + - + + : 84 : foreach(l, rcexpr->opfamilies)
+ + ]
2232 : : {
912 michael@paquier.xyz 2233 : 56 : add_object_address(OperatorFamilyRelationId, lfirst_oid(l), 0,
2234 : : context->addrs);
2235 : : }
2236 : : /* fall through to examine arguments */
2237 : : }
6599 tgl@sss.pgh.pa.us 2238 [ + + ]: 1113170 : else if (IsA(node, CoerceToDomain))
2239 : : {
7469 2240 : 113477 : CoerceToDomain *cd = (CoerceToDomain *) node;
2241 : :
912 michael@paquier.xyz 2242 : 113477 : add_object_address(TypeRelationId, cd->resulttype, 0,
2243 : : context->addrs);
2244 : : }
3331 tgl@sss.pgh.pa.us 2245 [ - + ]: 999693 : else if (IsA(node, NextValueExpr))
2246 : : {
3331 tgl@sss.pgh.pa.us 2247 :UBC 0 : NextValueExpr *nve = (NextValueExpr *) node;
2248 : :
912 michael@paquier.xyz 2249 : 0 : add_object_address(RelationRelationId, nve->seqid, 0,
2250 : : context->addrs);
2251 : : }
3760 tgl@sss.pgh.pa.us 2252 [ + + ]:CBC 999693 : else if (IsA(node, OnConflictExpr))
2253 : : {
2254 : 32 : OnConflictExpr *onconflict = (OnConflictExpr *) node;
2255 : :
2256 [ - + ]: 32 : if (OidIsValid(onconflict->constraint))
912 michael@paquier.xyz 2257 :UBC 0 : add_object_address(ConstraintRelationId, onconflict->constraint, 0,
2258 : : context->addrs);
2259 : : /* fall through to examine arguments */
2260 : : }
6599 tgl@sss.pgh.pa.us 2261 [ + + ]:CBC 999661 : else if (IsA(node, SortGroupClause))
2262 : : {
2263 : 23239 : SortGroupClause *sgc = (SortGroupClause *) node;
2264 : :
912 michael@paquier.xyz 2265 : 23239 : add_object_address(OperatorRelationId, sgc->eqop, 0,
2266 : : context->addrs);
6599 tgl@sss.pgh.pa.us 2267 [ + - ]: 23239 : if (OidIsValid(sgc->sortop))
912 michael@paquier.xyz 2268 : 23239 : add_object_address(OperatorRelationId, sgc->sortop, 0,
2269 : : context->addrs);
6599 tgl@sss.pgh.pa.us 2270 : 23239 : return false;
2271 : : }
3123 2272 [ + + ]: 976422 : else if (IsA(node, WindowClause))
2273 : : {
2274 : 255 : WindowClause *wc = (WindowClause *) node;
2275 : :
2276 [ + + ]: 255 : if (OidIsValid(wc->startInRangeFunc))
912 michael@paquier.xyz 2277 : 8 : add_object_address(ProcedureRelationId, wc->startInRangeFunc, 0,
2278 : : context->addrs);
3123 tgl@sss.pgh.pa.us 2279 [ + + ]: 255 : if (OidIsValid(wc->endInRangeFunc))
912 michael@paquier.xyz 2280 : 8 : add_object_address(ProcedureRelationId, wc->endInRangeFunc, 0,
2281 : : context->addrs);
1938 tmunro@postgresql.or 2282 [ - + ]: 255 : if (OidIsValid(wc->inRangeColl) &&
1938 tmunro@postgresql.or 2283 [ # # ]:UBC 0 : wc->inRangeColl != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 2284 : 0 : add_object_address(CollationRelationId, wc->inRangeColl, 0,
2285 : : context->addrs);
2286 : : /* fall through to examine substructure */
2287 : : }
2033 peter@eisentraut.org 2288 [ + + ]:CBC 976167 : else if (IsA(node, CTECycleClause))
2289 : : {
2290 : 16 : CTECycleClause *cc = (CTECycleClause *) node;
2291 : :
2292 [ + - ]: 16 : if (OidIsValid(cc->cycle_mark_type))
912 michael@paquier.xyz 2293 : 16 : add_object_address(TypeRelationId, cc->cycle_mark_type, 0,
2294 : : context->addrs);
2033 peter@eisentraut.org 2295 [ + + ]: 16 : if (OidIsValid(cc->cycle_mark_collation))
912 michael@paquier.xyz 2296 : 8 : add_object_address(CollationRelationId, cc->cycle_mark_collation, 0,
2297 : : context->addrs);
2033 peter@eisentraut.org 2298 [ + - ]: 16 : if (OidIsValid(cc->cycle_mark_neop))
912 michael@paquier.xyz 2299 : 16 : add_object_address(OperatorRelationId, cc->cycle_mark_neop, 0,
2300 : : context->addrs);
2301 : : /* fall through to examine substructure */
2302 : : }
6599 tgl@sss.pgh.pa.us 2303 [ + + ]: 976151 : else if (IsA(node, Query))
2304 : : {
2305 : : /* Recurse into RTE subquery or not-yet-planned sublink subquery */
8808 2306 : 65143 : Query *query = (Query *) node;
2307 : : ListCell *lc;
2308 : : bool result;
2309 : :
2310 : : /*
2311 : : * Add whole-relation refs for each plain relation mentioned in the
2312 : : * subquery's rtable, and ensure we add refs for any type-coercion
2313 : : * functions used in join alias lists.
2314 : : *
2315 : : * Note: query_tree_walker takes care of recursing into RTE_FUNCTION
2316 : : * RTEs, subqueries, etc, so no need to do that here. But we must
2317 : : * tell it not to visit join alias lists, or we'll add refs for join
2318 : : * input columns whether or not they are actually used in our query.
2319 : : *
2320 : : * Note: we don't need to worry about collations mentioned in
2321 : : * RTE_VALUES or RTE_CTE RTEs, because those must just duplicate
2322 : : * collations referenced in other parts of the Query. We do have to
2323 : : * worry about collations mentioned in RTE_FUNCTION, but we take care
2324 : : * of those when we recurse to the RangeTblFunction node(s).
2325 : : */
5864 2326 [ + + + + : 214630 : foreach(lc, query->rtable)
+ + ]
2327 : : {
2328 : 149491 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2329 : :
7469 2330 [ + + + + ]: 149491 : switch (rte->rtekind)
2331 : : {
2332 : 92484 : case RTE_RELATION:
2333 : : case RTE_GRAPH_TABLE:
912 michael@paquier.xyz 2334 : 92484 : add_object_address(RelationRelationId, rte->relid, 0,
2335 : : context->addrs);
7469 tgl@sss.pgh.pa.us 2336 : 92484 : break;
2422 2337 : 27428 : case RTE_JOIN:
2338 : :
2339 : : /*
2340 : : * Examine joinaliasvars entries only for merged JOIN
2341 : : * USING columns. Only those entries could contain
2342 : : * type-coercion functions. Also, their join input
2343 : : * columns must be referenced in the join quals, so this
2344 : : * won't accidentally add refs to otherwise-unused join
2345 : : * input columns. (We want to ref the type coercion
2346 : : * functions even if the merged column isn't explicitly
2347 : : * used anywhere, to protect possible expansion of the
2348 : : * join RTE as a whole-row var, and because it seems like
2349 : : * a bad idea to allow dropping a function that's present
2350 : : * in our query tree, whether or not it could get called.)
2351 : : */
2352 : 27428 : context->rtables = lcons(query->rtable, context->rtables);
2353 [ + + ]: 27832 : for (int i = 0; i < rte->joinmergedcols; i++)
2354 : : {
2355 : 404 : Node *aliasvar = list_nth(rte->joinaliasvars, i);
2356 : :
2357 [ + + ]: 404 : if (!IsA(aliasvar, Var))
2358 : 104 : find_expr_references_walker(aliasvar, context);
2359 : : }
2360 : 27428 : context->rtables = list_delete_first(context->rtables);
2361 : 27428 : break;
596 2362 : 4 : case RTE_NAMEDTUPLESTORE:
2363 : :
2364 : : /*
2365 : : * Cataloged objects cannot depend on tuplestores, because
2366 : : * those have no cataloged representation. For now we can
2367 : : * call the tuplestore a "transition table" because that's
2368 : : * the only kind exposed to SQL, but someday we might have
2369 : : * to work harder.
2370 : : */
2371 [ + - ]: 4 : ereport(ERROR,
2372 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2373 : : errmsg("transition table \"%s\" cannot be referenced in a persistent object",
2374 : : rte->eref->aliasname)));
2375 : : break;
7469 2376 : 29575 : default:
2377 : : /* Other RTE types can be ignored here */
2378 : 29575 : break;
2379 : : }
2380 : : }
2381 : :
2382 : : /*
2383 : : * If the query is an INSERT or UPDATE, we should create a dependency
2384 : : * on each target column, to prevent the specific target column from
2385 : : * being dropped. Although we will visit the TargetEntry nodes again
2386 : : * during query_tree_walker, we won't have enough context to do this
2387 : : * conveniently, so do it here.
2388 : : */
5282 2389 [ + + ]: 65139 : if (query->commandType == CMD_INSERT ||
2390 [ + + ]: 64491 : query->commandType == CMD_UPDATE)
2391 : : {
2392 : : RangeTblEntry *rte;
2393 : :
2394 [ + - - + ]: 2008 : if (query->resultRelation <= 0 ||
2395 : 1004 : query->resultRelation > list_length(query->rtable))
5282 tgl@sss.pgh.pa.us 2396 [ # # ]:UBC 0 : elog(ERROR, "invalid resultRelation %d",
2397 : : query->resultRelation);
5282 tgl@sss.pgh.pa.us 2398 :CBC 1004 : rte = rt_fetch(query->resultRelation, query->rtable);
2399 [ + - ]: 1004 : if (rte->rtekind == RTE_RELATION)
2400 : : {
2401 [ + + + + : 2976 : foreach(lc, query->targetList)
+ + ]
2402 : : {
2403 : 1972 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
2404 : :
2405 [ + + ]: 1972 : if (tle->resjunk)
3354 2406 : 8 : continue; /* ignore junk tlist items */
912 michael@paquier.xyz 2407 : 1964 : add_object_address(RelationRelationId, rte->relid, tle->resno,
2408 : : context->addrs);
2409 : : }
2410 : : }
2411 : : }
2412 : :
2413 : : /*
2414 : : * Add dependencies on constraints listed in query's constraintDeps
2415 : : */
5864 tgl@sss.pgh.pa.us 2416 [ + + + + : 65222 : foreach(lc, query->constraintDeps)
+ + ]
2417 : : {
912 michael@paquier.xyz 2418 : 83 : add_object_address(ConstraintRelationId, lfirst_oid(lc), 0,
2419 : : context->addrs);
2420 : : }
2421 : :
2422 : : /* Examine substructure of query */
8808 tgl@sss.pgh.pa.us 2423 : 65139 : context->rtables = lcons(query->rtable, context->rtables);
2424 : 65139 : result = query_tree_walker(query,
2425 : : find_expr_references_walker,
2426 : : context,
2427 : : QTW_IGNORE_JOINALIASES |
2428 : : QTW_EXAMINE_SORTGROUP);
8128 neilc@samurai.com 2429 : 65139 : context->rtables = list_delete_first(context->rtables);
8808 tgl@sss.pgh.pa.us 2430 : 65139 : return result;
2431 : : }
6594 2432 [ + + ]: 911008 : else if (IsA(node, SetOperationStmt))
2433 : : {
2434 : 6792 : SetOperationStmt *setop = (SetOperationStmt *) node;
2435 : :
2436 : : /* we need to look at the groupClauses for operator references */
2437 : 6792 : find_expr_references_walker((Node *) setop->groupClauses, context);
2438 : : /* fall through to examine child nodes */
2439 : : }
4662 2440 [ + + ]: 904216 : else if (IsA(node, RangeTblFunction))
2441 : : {
2442 : 9815 : RangeTblFunction *rtfunc = (RangeTblFunction *) node;
2443 : : ListCell *ct;
2444 : :
2445 : : /*
2446 : : * Add refs for any datatypes and collations used in a column
2447 : : * definition list for a RECORD function. (For other cases, it should
2448 : : * be enough to depend on the function itself.)
2449 : : */
2450 [ + + + + : 10019 : foreach(ct, rtfunc->funccoltypes)
+ + ]
2451 : : {
912 michael@paquier.xyz 2452 : 204 : add_object_address(TypeRelationId, lfirst_oid(ct), 0,
2453 : : context->addrs);
2454 : : }
4662 tgl@sss.pgh.pa.us 2455 [ + + + + : 10019 : foreach(ct, rtfunc->funccolcollations)
+ + ]
2456 : : {
2457 : 204 : Oid collid = lfirst_oid(ct);
2458 : :
1938 tmunro@postgresql.or 2459 [ + + - + ]: 204 : if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 2460 :UBC 0 : add_object_address(CollationRelationId, collid, 0,
2461 : : context->addrs);
2462 : : }
2463 : : }
2479 tgl@sss.pgh.pa.us 2464 [ + + ]:CBC 894401 : else if (IsA(node, TableFunc))
2465 : : {
2466 : 198 : TableFunc *tf = (TableFunc *) node;
2467 : : ListCell *ct;
2468 : :
2469 : : /*
2470 : : * Add refs for the datatypes and collations used in the TableFunc.
2471 : : */
2472 [ + - + + : 1185 : foreach(ct, tf->coltypes)
+ + ]
2473 : : {
912 michael@paquier.xyz 2474 : 987 : add_object_address(TypeRelationId, lfirst_oid(ct), 0,
2475 : : context->addrs);
2476 : : }
2479 tgl@sss.pgh.pa.us 2477 [ + - + + : 1185 : foreach(ct, tf->colcollations)
+ + ]
2478 : : {
2479 : 987 : Oid collid = lfirst_oid(ct);
2480 : :
1938 tmunro@postgresql.or 2481 [ + + - + ]: 987 : if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
912 michael@paquier.xyz 2482 :UBC 0 : add_object_address(CollationRelationId, collid, 0,
2483 : : context->addrs);
2484 : : }
2485 : : }
4051 tgl@sss.pgh.pa.us 2486 [ + + ]:CBC 894203 : else if (IsA(node, TableSampleClause))
2487 : : {
2488 : 36 : TableSampleClause *tsc = (TableSampleClause *) node;
2489 : :
912 michael@paquier.xyz 2490 : 36 : add_object_address(ProcedureRelationId, tsc->tsmhandler, 0,
2491 : : context->addrs);
2492 : : /* fall through to examine arguments */
2493 : : }
2494 : :
8808 tgl@sss.pgh.pa.us 2495 : 1428757 : return expression_tree_walker(node, find_expr_references_walker,
2496 : : context);
2497 : : }
2498 : :
2499 : : /*
2500 : : * find_expr_references_walker subroutine: handle a Var reference
2501 : : * to an RTE_FUNCTION RTE
2502 : : */
2503 : : static void
1497 2504 : 85844 : process_function_rte_ref(RangeTblEntry *rte, AttrNumber attnum,
2505 : : find_expr_references_context *context)
2506 : : {
2507 : 85844 : int atts_done = 0;
2508 : : ListCell *lc;
2509 : :
2510 : : /*
2511 : : * Identify which RangeTblFunction produces this attnum, and see if it
2512 : : * returns a composite type. If so, we'd better make a dependency on the
2513 : : * referenced column of the composite type (or actually, of its associated
2514 : : * relation).
2515 : : */
2516 [ + - + + : 86176 : foreach(lc, rte->functions)
+ + ]
2517 : : {
2518 : 86020 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
2519 : :
2520 [ + - ]: 86020 : if (attnum > atts_done &&
2521 [ + + ]: 86020 : attnum <= atts_done + rtfunc->funccolcount)
2522 : : {
2523 : : TupleDesc tupdesc;
2524 : :
2525 : : /* If it has a coldeflist, it certainly returns RECORD */
864 2526 [ + + ]: 85688 : if (rtfunc->funccolnames != NIL)
2527 : 204 : tupdesc = NULL; /* no need to work hard */
2528 : : else
2529 : 85484 : tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr, true);
1497 2530 [ + + + + ]: 85688 : if (tupdesc && tupdesc->tdtypeid != RECORDOID)
2531 : : {
2532 : : /*
2533 : : * Named composite type, so individual columns could get
2534 : : * dropped. Make a dependency on this specific column.
2535 : : */
2536 : 1194 : Oid reltype = get_typ_typrelid(tupdesc->tdtypeid);
2537 : :
2538 [ - + ]: 1194 : Assert(attnum - atts_done <= tupdesc->natts);
2539 [ + - ]: 1194 : if (OidIsValid(reltype)) /* can this fail? */
912 michael@paquier.xyz 2540 : 1194 : add_object_address(RelationRelationId, reltype,
2541 : : attnum - atts_done,
2542 : : context->addrs);
1497 tgl@sss.pgh.pa.us 2543 : 85688 : return;
2544 : : }
2545 : : /* Nothing to do; function's result type is handled elsewhere */
2546 : 84494 : return;
2547 : : }
2548 : 332 : atts_done += rtfunc->funccolcount;
2549 : : }
2550 : :
2551 : : /* If we get here, must be looking for the ordinality column */
2552 [ + - + - ]: 156 : if (rte->funcordinality && attnum == atts_done + 1)
2553 : 156 : return;
2554 : :
2555 : : /* this probably can't happen ... */
1497 tgl@sss.pgh.pa.us 2556 [ # # ]:UBC 0 : ereport(ERROR,
2557 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
2558 : : errmsg("column %d of relation \"%s\" does not exist",
2559 : : attnum, rte->eref->aliasname)));
2560 : : }
2561 : :
2562 : : /*
2563 : : * find_temp_object - search an array of dependency references for temp objects
2564 : : *
2565 : : * Scan an ObjectAddresses array for references to temporary objects (objects
2566 : : * in temporary namespaces), ignoring those in our own temp namespace if
2567 : : * local_temp_okay is true. If one is found, return true after storing its
2568 : : * address in *foundobj.
2569 : : *
2570 : : * Current callers only use this to deliver helpful notices, so reporting
2571 : : * one such object seems sufficient. We return the first one, which should
2572 : : * be a stable result for a given query since it depends only on the order
2573 : : * in which this module searches query trees. (However, it's important to
2574 : : * call this before de-duplicating the objects, else OID order would affect
2575 : : * the result.)
2576 : : */
2577 : : bool
277 tgl@sss.pgh.pa.us 2578 :CBC 24827 : find_temp_object(const ObjectAddresses *addrs, bool local_temp_okay,
2579 : : ObjectAddress *foundobj)
2580 : : {
2581 [ + + ]: 557485 : for (int i = 0; i < addrs->numrefs; i++)
2582 : : {
2583 : 532781 : const ObjectAddress *thisobj = addrs->refs + i;
2584 : : Oid objnamespace;
2585 : :
2586 : : /*
2587 : : * Use get_object_namespace() to see if this object belongs to a
2588 : : * schema. If not, we can skip it.
2589 : : */
2590 : 532781 : objnamespace = get_object_namespace(thisobj);
2591 : :
2592 : : /*
2593 : : * If the object is in a temporary namespace, complain, except if
2594 : : * local_temp_okay and it's our own temp namespace.
2595 : : */
2596 [ + + + + ]: 532781 : if (OidIsValid(objnamespace) && isAnyTempNamespace(objnamespace) &&
2597 [ + + - + ]: 124 : !(local_temp_okay && isTempNamespace(objnamespace)))
2598 : : {
2599 : 123 : *foundobj = *thisobj;
2600 : 123 : return true;
2601 : : }
2602 : : }
2603 : 24704 : return false;
2604 : : }
2605 : :
2606 : : /*
2607 : : * query_uses_temp_object - convenience wrapper for find_temp_object
2608 : : *
2609 : : * If the Query includes any use of a temporary object, fill *temp_object
2610 : : * with the address of one such object and return true.
2611 : : */
2612 : : bool
276 2613 : 10857 : query_uses_temp_object(Query *query, ObjectAddress *temp_object)
2614 : : {
2615 : : bool result;
2616 : : ObjectAddresses *addrs;
2617 : :
2618 : 10857 : addrs = new_object_addresses();
2619 : :
2620 : : /* Collect all dependencies from the Query */
2621 : 10857 : collectDependenciesOfExpr(addrs, (Node *) query, NIL);
2622 : :
2623 : : /* Look for one that is temp */
2624 : 10853 : result = find_temp_object(addrs, false, temp_object);
2625 : :
2626 : 10853 : free_object_addresses(addrs);
2627 : :
2628 : 10853 : return result;
2629 : : }
2630 : :
2631 : : /*
2632 : : * Given an array of dependency references, eliminate any duplicates.
2633 : : */
2634 : : static void
8808 2635 : 306576 : eliminate_duplicate_dependencies(ObjectAddresses *addrs)
2636 : : {
2637 : : ObjectAddress *priorobj;
2638 : : int oldref,
2639 : : newrefs;
2640 : :
2641 : : /*
2642 : : * We can't sort if the array has "extra" data, because there's no way to
2643 : : * keep it in sync. Fortunately that combination of features is not
2644 : : * needed.
2645 : : */
6654 2646 [ - + ]: 306576 : Assert(!addrs->extras);
2647 : :
8808 2648 [ + + ]: 306576 : if (addrs->numrefs <= 1)
2649 : 104076 : return; /* nothing to do */
2650 : :
2651 : : /* Sort the refs so that duplicates are adjacent */
1297 peter@eisentraut.org 2652 : 202500 : qsort(addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
2653 : : object_address_comparator);
2654 : :
2655 : : /* Remove dups */
8808 tgl@sss.pgh.pa.us 2656 : 202500 : priorobj = addrs->refs;
2657 : 202500 : newrefs = 1;
2658 [ + + ]: 1722199 : for (oldref = 1; oldref < addrs->numrefs; oldref++)
2659 : : {
8758 bruce@momjian.us 2660 : 1519699 : ObjectAddress *thisobj = addrs->refs + oldref;
2661 : :
8808 tgl@sss.pgh.pa.us 2662 [ + + ]: 1519699 : if (priorobj->classId == thisobj->classId &&
2663 [ + + ]: 1312024 : priorobj->objectId == thisobj->objectId)
2664 : : {
2665 [ + + ]: 825602 : if (priorobj->objectSubId == thisobj->objectSubId)
2666 : 614966 : continue; /* identical, so drop thisobj */
2667 : :
2668 : : /*
2669 : : * If we have a whole-object reference and a reference to a part
2670 : : * of the same object, we don't need the whole-object reference
2671 : : * (for example, we don't need to reference both table foo and
2672 : : * column foo.bar). The whole-object reference will always appear
2673 : : * first in the sorted list.
2674 : : */
2675 [ + + ]: 210636 : if (priorobj->objectSubId == 0)
2676 : : {
2677 : : /* replace whole ref with partial */
2678 : 47847 : priorobj->objectSubId = thisobj->objectSubId;
2679 : 47847 : continue;
2680 : : }
2681 : : }
2682 : : /* Not identical, so add thisobj to output set */
2683 : 856886 : priorobj++;
6654 2684 : 856886 : *priorobj = *thisobj;
8808 2685 : 856886 : newrefs++;
2686 : : }
2687 : :
2688 : 202500 : addrs->numrefs = newrefs;
2689 : : }
2690 : :
2691 : : /*
2692 : : * qsort comparator for ObjectAddress items
2693 : : */
2694 : : static int
2695 : 5818033 : object_address_comparator(const void *a, const void *b)
2696 : : {
2697 : 5818033 : const ObjectAddress *obja = (const ObjectAddress *) a;
2698 : 5818033 : const ObjectAddress *objb = (const ObjectAddress *) b;
2699 : :
2700 : : /*
2701 : : * Primary sort key is OID descending. Most of the time, this will result
2702 : : * in putting newer objects before older ones, which is likely to be the
2703 : : * right order to delete in.
2704 : : */
2775 2705 [ + + ]: 5818033 : if (obja->objectId > objb->objectId)
8808 2706 : 1522343 : return -1;
2707 [ + + ]: 4295690 : if (obja->objectId < objb->objectId)
2775 2708 : 2705410 : return 1;
2709 : :
2710 : : /*
2711 : : * Next sort on catalog ID, in case identical OIDs appear in different
2712 : : * catalogs. Sort direction is pretty arbitrary here.
2713 : : */
2714 [ - + ]: 1590280 : if (obja->classId < objb->classId)
8808 tgl@sss.pgh.pa.us 2715 :UBC 0 : return -1;
2775 tgl@sss.pgh.pa.us 2716 [ - + ]:CBC 1590280 : if (obja->classId > objb->classId)
8808 tgl@sss.pgh.pa.us 2717 :UBC 0 : return 1;
2718 : :
2719 : : /*
2720 : : * Last, sort on object subId.
2721 : : *
2722 : : * We sort the subId as an unsigned int so that 0 (the whole object) will
2723 : : * come first. This is essential for eliminate_duplicate_dependencies,
2724 : : * and is also the best order for findDependentObjects.
2725 : : */
8808 tgl@sss.pgh.pa.us 2726 [ + + ]:CBC 1590280 : if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
2727 : 417324 : return -1;
2728 [ + + ]: 1172956 : if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
2729 : 413491 : return 1;
2730 : 759465 : return 0;
2731 : : }
2732 : :
2733 : : /*
2734 : : * Routines for handling an expansible array of ObjectAddress items.
2735 : : *
2736 : : * new_object_addresses: create a new ObjectAddresses array.
2737 : : */
2738 : : ObjectAddresses *
7312 alvherre@alvh.no-ip. 2739 : 362501 : new_object_addresses(void)
2740 : : {
2741 : : ObjectAddresses *addrs;
2742 : :
260 michael@paquier.xyz 2743 : 362501 : addrs = palloc_object(ObjectAddresses);
2744 : :
8808 tgl@sss.pgh.pa.us 2745 : 362501 : addrs->numrefs = 0;
7312 alvherre@alvh.no-ip. 2746 : 362501 : addrs->maxrefs = 32;
260 michael@paquier.xyz 2747 : 362501 : addrs->refs = palloc_array(ObjectAddress, addrs->maxrefs);
6654 tgl@sss.pgh.pa.us 2748 : 362501 : addrs->extras = NULL; /* until/unless needed */
2749 : :
7312 alvherre@alvh.no-ip. 2750 : 362501 : return addrs;
2751 : : }
2752 : :
2753 : : /*
2754 : : * Add an entry to an ObjectAddresses array.
2755 : : */
2756 : : static void
912 michael@paquier.xyz 2757 : 1433568 : add_object_address(Oid classId, Oid objectId, int32 subId,
2758 : : ObjectAddresses *addrs)
2759 : : {
2760 : : ObjectAddress *item;
2761 : :
2762 : : /* enlarge array if needed */
8808 tgl@sss.pgh.pa.us 2763 [ + + ]: 1433568 : if (addrs->numrefs >= addrs->maxrefs)
2764 : : {
2765 : 20577 : addrs->maxrefs *= 2;
10 michael@paquier.xyz 2766 :GNC 20577 : addrs->refs = repalloc_array(addrs->refs, ObjectAddress, addrs->maxrefs);
6654 tgl@sss.pgh.pa.us 2767 [ - + ]:CBC 20577 : Assert(!addrs->extras);
2768 : : }
2769 : : /* record this item */
8808 2770 : 1433568 : item = addrs->refs + addrs->numrefs;
912 michael@paquier.xyz 2771 : 1433568 : item->classId = classId;
8808 tgl@sss.pgh.pa.us 2772 : 1433568 : item->objectId = objectId;
2773 : 1433568 : item->objectSubId = subId;
2774 : 1433568 : addrs->numrefs++;
2775 : 1433568 : }
2776 : :
2777 : : /*
2778 : : * Add an entry to an ObjectAddresses array.
2779 : : *
2780 : : * As above, but specify entry exactly.
2781 : : */
2782 : : void
2783 : 816925 : add_exact_object_address(const ObjectAddress *object,
2784 : : ObjectAddresses *addrs)
2785 : : {
2786 : : ObjectAddress *item;
2787 : :
2788 : : /* enlarge array if needed */
2789 [ + + ]: 816925 : if (addrs->numrefs >= addrs->maxrefs)
2790 : : {
2791 : 37 : addrs->maxrefs *= 2;
10 michael@paquier.xyz 2792 :GNC 37 : addrs->refs = repalloc_array(addrs->refs, ObjectAddress, addrs->maxrefs);
6654 tgl@sss.pgh.pa.us 2793 [ - + ]:CBC 37 : Assert(!addrs->extras);
2794 : : }
2795 : : /* record this item */
8808 2796 : 816925 : item = addrs->refs + addrs->numrefs;
2797 : 816925 : *item = *object;
2798 : 816925 : addrs->numrefs++;
2799 : 816925 : }
2800 : :
2801 : : /*
2802 : : * Add an entry to an ObjectAddresses array.
2803 : : *
2804 : : * As above, but specify entry exactly and provide some "extra" data too.
2805 : : */
2806 : : static void
6654 2807 : 151364 : add_exact_object_address_extra(const ObjectAddress *object,
2808 : : const ObjectAddressExtra *extra,
2809 : : ObjectAddresses *addrs)
2810 : : {
2811 : : ObjectAddress *item;
2812 : : ObjectAddressExtra *itemextra;
2813 : :
2814 : : /* allocate extra space if first time */
2815 [ + + ]: 151364 : if (!addrs->extras)
10 michael@paquier.xyz 2816 :GNC 22850 : addrs->extras = palloc_array(ObjectAddressExtra, addrs->maxrefs);
2817 : :
2818 : : /* enlarge array if needed */
6654 tgl@sss.pgh.pa.us 2819 [ + + ]:CBC 151364 : if (addrs->numrefs >= addrs->maxrefs)
2820 : : {
2821 : 596 : addrs->maxrefs *= 2;
10 michael@paquier.xyz 2822 :GNC 596 : addrs->refs = repalloc_array(addrs->refs, ObjectAddress, addrs->maxrefs);
2823 : 596 : addrs->extras = repalloc_array(addrs->extras, ObjectAddressExtra, addrs->maxrefs);
2824 : : }
2825 : : /* record this item */
6654 tgl@sss.pgh.pa.us 2826 :CBC 151364 : item = addrs->refs + addrs->numrefs;
2827 : 151364 : *item = *object;
2828 : 151364 : itemextra = addrs->extras + addrs->numrefs;
2829 : 151364 : *itemextra = *extra;
2830 : 151364 : addrs->numrefs++;
2831 : 151364 : }
2832 : :
2833 : : /*
2834 : : * Test whether an object is present in an ObjectAddresses array.
2835 : : *
2836 : : * We return "true" if object is a subobject of something in the array, too.
2837 : : */
2838 : : bool
8740 2839 : 466 : object_address_present(const ObjectAddress *object,
2840 : : const ObjectAddresses *addrs)
2841 : : {
2842 : : int i;
2843 : :
2844 [ + + ]: 1685 : for (i = addrs->numrefs - 1; i >= 0; i--)
2845 : : {
6654 2846 : 1219 : const ObjectAddress *thisobj = addrs->refs + i;
2847 : :
8740 2848 [ + + ]: 1219 : if (object->classId == thisobj->classId &&
2849 [ - + ]: 338 : object->objectId == thisobj->objectId)
2850 : : {
8740 tgl@sss.pgh.pa.us 2851 [ # # ]:UBC 0 : if (object->objectSubId == thisobj->objectSubId ||
2852 [ # # ]: 0 : thisobj->objectSubId == 0)
2853 : 0 : return true;
2854 : : }
2855 : : }
2856 : :
8740 tgl@sss.pgh.pa.us 2857 :CBC 466 : return false;
2858 : : }
2859 : :
2860 : : /*
2861 : : * As above, except that if the object is present then also OR the given
2862 : : * flags into its associated extra data (which must exist).
2863 : : */
2864 : : static bool
6654 2865 : 185952 : object_address_present_add_flags(const ObjectAddress *object,
2866 : : int flags,
2867 : : ObjectAddresses *addrs)
2868 : : {
4307 2869 : 185952 : bool result = false;
2870 : : int i;
2871 : :
6654 2872 [ + + ]: 6869496 : for (i = addrs->numrefs - 1; i >= 0; i--)
2873 : : {
2874 : 6683544 : ObjectAddress *thisobj = addrs->refs + i;
2875 : :
2876 [ + + ]: 6683544 : if (object->classId == thisobj->classId &&
2877 [ + + ]: 2603225 : object->objectId == thisobj->objectId)
2878 : : {
2879 [ + + ]: 33321 : if (object->objectSubId == thisobj->objectSubId)
2880 : : {
2881 : 33021 : ObjectAddressExtra *thisextra = addrs->extras + i;
2882 : :
2883 : 33021 : thisextra->flags |= flags;
4307 2884 : 33021 : result = true;
2885 : : }
2886 [ + + ]: 300 : else if (thisobj->objectSubId == 0)
2887 : : {
2888 : : /*
2889 : : * We get here if we find a need to delete a column after
2890 : : * having already decided to drop its whole table. Obviously
2891 : : * we no longer need to drop the subobject, so report that we
2892 : : * found the subobject in the array. But don't plaster its
2893 : : * flags on the whole object.
2894 : : */
2895 : 268 : result = true;
2896 : : }
2897 [ + + ]: 32 : else if (object->objectSubId == 0)
2898 : : {
2899 : : /*
2900 : : * We get here if we find a need to delete a whole table after
2901 : : * having already decided to drop one of its columns. We
2902 : : * can't report that the whole object is in the array, but we
2903 : : * should mark the subobject with the whole object's flags.
2904 : : *
2905 : : * It might seem attractive to physically delete the column's
2906 : : * array entry, or at least mark it as no longer needing
2907 : : * separate deletion. But that could lead to, e.g., dropping
2908 : : * the column's datatype before we drop the table, which does
2909 : : * not seem like a good idea. This is a very rare situation
2910 : : * in practice, so we just take the hit of doing a separate
2911 : : * DROP COLUMN action even though we know we're gonna delete
2912 : : * the table later.
2913 : : *
2914 : : * What we can do, though, is mark this as a subobject so that
2915 : : * we don't report it separately, which is confusing because
2916 : : * it's unpredictable whether it happens or not. But do so
2917 : : * only if flags != 0 (flags == 0 is a read-only probe).
2918 : : *
2919 : : * Because there could be other subobjects of this object in
2920 : : * the array, this case means we always have to loop through
2921 : : * the whole array; we cannot exit early on a match.
2922 : : */
2923 : 24 : ObjectAddressExtra *thisextra = addrs->extras + i;
2924 : :
2778 2925 [ + - ]: 24 : if (flags)
2926 : 24 : thisextra->flags |= (flags | DEPFLAG_SUBOBJECT);
2927 : : }
2928 : : }
2929 : : }
2930 : :
4307 2931 : 185952 : return result;
2932 : : }
2933 : :
2934 : : /*
2935 : : * Similar to above, except we search an ObjectAddressStack.
2936 : : */
2937 : : static bool
5482 2938 : 265528 : stack_address_present_add_flags(const ObjectAddress *object,
2939 : : int flags,
2940 : : ObjectAddressStack *stack)
2941 : : {
4307 2942 : 265528 : bool result = false;
2943 : : ObjectAddressStack *stackptr;
2944 : :
5482 2945 [ + + ]: 705681 : for (stackptr = stack; stackptr; stackptr = stackptr->next)
2946 : : {
2947 : 440153 : const ObjectAddress *thisobj = stackptr->object;
2948 : :
2949 [ + + ]: 440153 : if (object->classId == thisobj->classId &&
2950 [ + + ]: 192065 : object->objectId == thisobj->objectId)
2951 : : {
2952 [ + + ]: 79648 : if (object->objectSubId == thisobj->objectSubId)
2953 : : {
2954 : 78906 : stackptr->flags |= flags;
4307 2955 : 78906 : result = true;
2956 : : }
2957 [ + + ]: 742 : else if (thisobj->objectSubId == 0)
2958 : : {
2959 : : /*
2960 : : * We're visiting a column with whole table already on stack.
2961 : : * As in object_address_present_add_flags(), we can skip
2962 : : * further processing of the subobject, but we don't want to
2963 : : * propagate flags for the subobject to the whole object.
2964 : : */
2965 : 670 : result = true;
2966 : : }
2967 [ - + ]: 72 : else if (object->objectSubId == 0)
2968 : : {
2969 : : /*
2970 : : * We're visiting a table with column already on stack. As in
2971 : : * object_address_present_add_flags(), we should propagate
2972 : : * flags for the whole object to each of its subobjects.
2973 : : */
2778 tgl@sss.pgh.pa.us 2974 [ # # ]:UBC 0 : if (flags)
2975 : 0 : stackptr->flags |= (flags | DEPFLAG_SUBOBJECT);
2976 : : }
2977 : : }
2978 : : }
2979 : :
4307 tgl@sss.pgh.pa.us 2980 :CBC 265528 : return result;
2981 : : }
2982 : :
2983 : : /*
2984 : : * Record multiple dependencies from an ObjectAddresses array, after first
2985 : : * removing any duplicates.
2986 : : */
2987 : : void
6946 2988 : 259391 : record_object_address_dependencies(const ObjectAddress *depender,
2989 : : ObjectAddresses *referenced,
2990 : : DependencyType behavior)
2991 : : {
2992 : 259391 : eliminate_duplicate_dependencies(referenced);
2993 : 259391 : recordMultipleDependencies(depender,
2124 tmunro@postgresql.or 2994 : 259391 : referenced->refs, referenced->numrefs,
2995 : : behavior);
6946 tgl@sss.pgh.pa.us 2996 : 259386 : }
2997 : :
2998 : : /*
2999 : : * Sort the items in an ObjectAddresses array.
3000 : : *
3001 : : * The major sort key is OID-descending, so that newer objects will be listed
3002 : : * first in most cases. This is primarily useful for ensuring stable outputs
3003 : : * from regression tests; it's not recommended if the order of the objects is
3004 : : * determined by user input, such as the order of targets in a DROP command.
3005 : : */
3006 : : void
2717 3007 : 88 : sort_object_addresses(ObjectAddresses *addrs)
3008 : : {
3009 [ + + ]: 88 : if (addrs->numrefs > 1)
1297 peter@eisentraut.org 3010 : 49 : qsort(addrs->refs, addrs->numrefs,
3011 : : sizeof(ObjectAddress),
3012 : : object_address_comparator);
2717 tgl@sss.pgh.pa.us 3013 : 88 : }
3014 : :
3015 : : /*
3016 : : * Clean up when done with an ObjectAddresses array.
3017 : : */
3018 : : void
7312 alvherre@alvh.no-ip. 3019 : 360428 : free_object_addresses(ObjectAddresses *addrs)
3020 : : {
8808 tgl@sss.pgh.pa.us 3021 : 360428 : pfree(addrs->refs);
6654 3022 [ + + ]: 360428 : if (addrs->extras)
3023 : 22568 : pfree(addrs->extras);
7312 alvherre@alvh.no-ip. 3024 : 360428 : pfree(addrs);
8808 tgl@sss.pgh.pa.us 3025 : 360428 : }
3026 : :
3027 : : /*
3028 : : * delete initial ACL for extension objects
3029 : : */
3030 : : static void
3795 sfrost@snowman.net 3031 : 147763 : DeleteInitPrivs(const ObjectAddress *object)
3032 : : {
3033 : : Relation relation;
3034 : : ScanKeyData key[3];
3035 : : int nkeys;
3036 : : SysScanDesc scan;
3037 : : HeapTuple oldtuple;
3038 : :
2775 andres@anarazel.de 3039 : 147763 : relation = table_open(InitPrivsRelationId, RowExclusiveLock);
3040 : :
3795 sfrost@snowman.net 3041 : 147763 : ScanKeyInit(&key[0],
3042 : : Anum_pg_init_privs_objoid,
3043 : : BTEqualStrategyNumber, F_OIDEQ,
3044 : 147763 : ObjectIdGetDatum(object->objectId));
3045 : 147763 : ScanKeyInit(&key[1],
3046 : : Anum_pg_init_privs_classoid,
3047 : : BTEqualStrategyNumber, F_OIDEQ,
3048 : 147763 : ObjectIdGetDatum(object->classId));
804 tgl@sss.pgh.pa.us 3049 [ + + ]: 147763 : if (object->objectSubId != 0)
3050 : : {
3051 : 1398 : ScanKeyInit(&key[2],
3052 : : Anum_pg_init_privs_objsubid,
3053 : : BTEqualStrategyNumber, F_INT4EQ,
3054 : 1398 : Int32GetDatum(object->objectSubId));
3055 : 1398 : nkeys = 3;
3056 : : }
3057 : : else
3058 : 146365 : nkeys = 2;
3059 : :
3795 sfrost@snowman.net 3060 : 147763 : scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
3061 : : NULL, nkeys, key);
3062 : :
3063 [ + + ]: 147844 : while (HeapTupleIsValid(oldtuple = systable_getnext(scan)))
3494 tgl@sss.pgh.pa.us 3064 : 81 : CatalogTupleDelete(relation, &oldtuple->t_self);
3065 : :
3795 sfrost@snowman.net 3066 : 147763 : systable_endscan(scan);
3067 : :
2775 andres@anarazel.de 3068 : 147763 : table_close(relation, RowExclusiveLock);
3795 sfrost@snowman.net 3069 : 147763 : }
|