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