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