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