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