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