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