Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / catalog / dependency.c
blob5403433a7cc49435b8deab5a8e26e3487b01ed25
1 /*-------------------------------------------------------------------------
3 * dependency.c
4 * Routines to support inter-object dependencies.
7 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "access/sysattr.h"
20 #include "access/xact.h"
21 #include "catalog/dependency.h"
22 #include "catalog/heap.h"
23 #include "catalog/index.h"
24 #include "catalog/indexing.h"
25 #include "catalog/namespace.h"
26 #include "catalog/pg_amop.h"
27 #include "catalog/pg_amproc.h"
28 #include "catalog/pg_attrdef.h"
29 #include "catalog/pg_authid.h"
30 #include "catalog/pg_cast.h"
31 #include "catalog/pg_constraint.h"
32 #include "catalog/pg_conversion.h"
33 #include "catalog/pg_conversion_fn.h"
34 #include "catalog/pg_database.h"
35 #include "catalog/pg_depend.h"
36 #include "catalog/pg_language.h"
37 #include "catalog/pg_namespace.h"
38 #include "catalog/pg_opclass.h"
39 #include "catalog/pg_operator.h"
40 #include "catalog/pg_opfamily.h"
41 #include "catalog/pg_proc.h"
42 #include "catalog/pg_rewrite.h"
43 #include "catalog/pg_tablespace.h"
44 #include "catalog/pg_trigger.h"
45 #include "catalog/pg_ts_config.h"
46 #include "catalog/pg_ts_dict.h"
47 #include "catalog/pg_ts_parser.h"
48 #include "catalog/pg_ts_template.h"
49 #include "catalog/pg_type.h"
50 #include "commands/comment.h"
51 #include "commands/dbcommands.h"
52 #include "commands/defrem.h"
53 #include "commands/proclang.h"
54 #include "commands/schemacmds.h"
55 #include "commands/tablespace.h"
56 #include "commands/trigger.h"
57 #include "commands/typecmds.h"
58 #include "miscadmin.h"
59 #include "nodes/nodeFuncs.h"
60 #include "parser/parsetree.h"
61 #include "rewrite/rewriteRemove.h"
62 #include "storage/lmgr.h"
63 #include "utils/builtins.h"
64 #include "utils/fmgroids.h"
65 #include "utils/guc.h"
66 #include "utils/lsyscache.h"
67 #include "utils/syscache.h"
68 #include "utils/tqual.h"
72 * Deletion processing requires additional state for each ObjectAddress that
73 * it's planning to delete. For simplicity and code-sharing we make the
74 * ObjectAddresses code support arrays with or without this extra state.
76 typedef struct
78 int flags; /* bitmask, see bit definitions below */
79 ObjectAddress dependee; /* object whose deletion forced this one */
80 } ObjectAddressExtra;
82 /* ObjectAddressExtra flag bits */
83 #define DEPFLAG_ORIGINAL 0x0001 /* an original deletion target */
84 #define DEPFLAG_NORMAL 0x0002 /* reached via normal dependency */
85 #define DEPFLAG_AUTO 0x0004 /* reached via auto dependency */
86 #define DEPFLAG_INTERNAL 0x0008 /* reached via internal dependency */
89 /* expansible list of ObjectAddresses */
90 struct ObjectAddresses
92 ObjectAddress *refs; /* => palloc'd array */
93 ObjectAddressExtra *extras; /* => palloc'd array, or NULL if not used */
94 int numrefs; /* current number of references */
95 int maxrefs; /* current size of palloc'd array(s) */
98 /* typedef ObjectAddresses appears in dependency.h */
100 /* threaded list of ObjectAddresses, for recursion detection */
101 typedef struct ObjectAddressStack
103 const ObjectAddress *object; /* object being visited */
104 int flags; /* its current flag bits */
105 struct ObjectAddressStack *next; /* next outer stack level */
106 } ObjectAddressStack;
108 /* for find_expr_references_walker */
109 typedef struct
111 ObjectAddresses *addrs; /* addresses being accumulated */
112 List *rtables; /* list of rangetables to resolve Vars */
113 } find_expr_references_context;
116 * This constant table maps ObjectClasses to the corresponding catalog OIDs.
117 * See also getObjectClass().
119 static const Oid object_classes[MAX_OCLASS] = {
120 RelationRelationId, /* OCLASS_CLASS */
121 ProcedureRelationId, /* OCLASS_PROC */
122 TypeRelationId, /* OCLASS_TYPE */
123 CastRelationId, /* OCLASS_CAST */
124 ConstraintRelationId, /* OCLASS_CONSTRAINT */
125 ConversionRelationId, /* OCLASS_CONVERSION */
126 AttrDefaultRelationId, /* OCLASS_DEFAULT */
127 LanguageRelationId, /* OCLASS_LANGUAGE */
128 OperatorRelationId, /* OCLASS_OPERATOR */
129 OperatorClassRelationId, /* OCLASS_OPCLASS */
130 OperatorFamilyRelationId, /* OCLASS_OPFAMILY */
131 AccessMethodOperatorRelationId, /* OCLASS_AMOP */
132 AccessMethodProcedureRelationId, /* OCLASS_AMPROC */
133 RewriteRelationId, /* OCLASS_REWRITE */
134 TriggerRelationId, /* OCLASS_TRIGGER */
135 NamespaceRelationId, /* OCLASS_SCHEMA */
136 TSParserRelationId, /* OCLASS_TSPARSER */
137 TSDictionaryRelationId, /* OCLASS_TSDICT */
138 TSTemplateRelationId, /* OCLASS_TSTEMPLATE */
139 TSConfigRelationId, /* OCLASS_TSCONFIG */
140 AuthIdRelationId, /* OCLASS_ROLE */
141 DatabaseRelationId, /* OCLASS_DATABASE */
142 TableSpaceRelationId /* OCLASS_TBLSPACE */
146 static void findDependentObjects(const ObjectAddress *object,
147 int flags,
148 ObjectAddressStack *stack,
149 ObjectAddresses *targetObjects,
150 const ObjectAddresses *pendingObjects,
151 Relation depRel);
152 static void reportDependentObjects(const ObjectAddresses *targetObjects,
153 DropBehavior behavior,
154 int msglevel,
155 const ObjectAddress *origObject);
156 static void deleteOneObject(const ObjectAddress *object, Relation depRel);
157 static void doDeletion(const ObjectAddress *object);
158 static void AcquireDeletionLock(const ObjectAddress *object);
159 static void ReleaseDeletionLock(const ObjectAddress *object);
160 static bool find_expr_references_walker(Node *node,
161 find_expr_references_context *context);
162 static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
163 static int object_address_comparator(const void *a, const void *b);
164 static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
165 ObjectAddresses *addrs);
166 static void add_exact_object_address_extra(const ObjectAddress *object,
167 const ObjectAddressExtra *extra,
168 ObjectAddresses *addrs);
169 static bool object_address_present_add_flags(const ObjectAddress *object,
170 int flags,
171 ObjectAddresses *addrs);
172 static void getRelationDescription(StringInfo buffer, Oid relid);
173 static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
177 * performDeletion: attempt to drop the specified object. If CASCADE
178 * behavior is specified, also drop any dependent objects (recursively).
179 * If RESTRICT behavior is specified, error out if there are any dependent
180 * objects, except for those that should be implicitly dropped anyway
181 * according to the dependency type.
183 * This is the outer control routine for all forms of DROP that drop objects
184 * that can participate in dependencies. Note that the next two routines
185 * are variants on the same theme; if you change anything here you'll likely
186 * need to fix them too.
188 void
189 performDeletion(const ObjectAddress *object,
190 DropBehavior behavior)
192 Relation depRel;
193 ObjectAddresses *targetObjects;
194 int i;
197 * We save some cycles by opening pg_depend just once and passing the
198 * Relation pointer down to all the recursive deletion steps.
200 depRel = heap_open(DependRelationId, RowExclusiveLock);
203 * Acquire deletion lock on the target object. (Ideally the caller has
204 * done this already, but many places are sloppy about it.)
206 AcquireDeletionLock(object);
209 * Construct a list of objects to delete (ie, the given object plus
210 * everything directly or indirectly dependent on it).
212 targetObjects = new_object_addresses();
214 findDependentObjects(object,
215 DEPFLAG_ORIGINAL,
216 NULL, /* empty stack */
217 targetObjects,
218 NULL, /* no pendingObjects */
219 depRel);
222 * Check if deletion is allowed, and report about cascaded deletes.
224 reportDependentObjects(targetObjects,
225 behavior,
226 NOTICE,
227 object);
230 * Delete all the objects in the proper order.
232 for (i = 0; i < targetObjects->numrefs; i++)
234 ObjectAddress *thisobj = targetObjects->refs + i;
236 deleteOneObject(thisobj, depRel);
239 /* And clean up */
240 free_object_addresses(targetObjects);
242 heap_close(depRel, RowExclusiveLock);
246 * performMultipleDeletions: Similar to performDeletion, but act on multiple
247 * objects at once.
249 * The main difference from issuing multiple performDeletion calls is that the
250 * list of objects that would be implicitly dropped, for each object to be
251 * dropped, is the union of the implicit-object list for all objects. This
252 * makes each check be more relaxed.
254 void
255 performMultipleDeletions(const ObjectAddresses *objects,
256 DropBehavior behavior)
258 Relation depRel;
259 ObjectAddresses *targetObjects;
260 int i;
262 /* No work if no objects... */
263 if (objects->numrefs <= 0)
264 return;
267 * We save some cycles by opening pg_depend just once and passing the
268 * Relation pointer down to all the recursive deletion steps.
270 depRel = heap_open(DependRelationId, RowExclusiveLock);
273 * Construct a list of objects to delete (ie, the given objects plus
274 * everything directly or indirectly dependent on them). Note that
275 * because we pass the whole objects list as pendingObjects context,
276 * we won't get a failure from trying to delete an object that is
277 * internally dependent on another one in the list; we'll just skip
278 * that object and delete it when we reach its owner.
280 targetObjects = new_object_addresses();
282 for (i = 0; i < objects->numrefs; i++)
284 const ObjectAddress *thisobj = objects->refs + i;
287 * Acquire deletion lock on each target object. (Ideally the caller
288 * has done this already, but many places are sloppy about it.)
290 AcquireDeletionLock(thisobj);
292 findDependentObjects(thisobj,
293 DEPFLAG_ORIGINAL,
294 NULL, /* empty stack */
295 targetObjects,
296 objects,
297 depRel);
301 * Check if deletion is allowed, and report about cascaded deletes.
303 * If there's exactly one object being deleted, report it the same
304 * way as in performDeletion(), else we have to be vaguer.
306 reportDependentObjects(targetObjects,
307 behavior,
308 NOTICE,
309 (objects->numrefs == 1 ? objects->refs : NULL));
312 * Delete all the objects in the proper order.
314 for (i = 0; i < targetObjects->numrefs; i++)
316 ObjectAddress *thisobj = targetObjects->refs + i;
318 deleteOneObject(thisobj, depRel);
321 /* And clean up */
322 free_object_addresses(targetObjects);
324 heap_close(depRel, RowExclusiveLock);
328 * deleteWhatDependsOn: attempt to drop everything that depends on the
329 * specified object, though not the object itself. Behavior is always
330 * CASCADE.
332 * This is currently used only to clean out the contents of a schema
333 * (namespace): the passed object is a namespace. We normally want this
334 * to be done silently, so there's an option to suppress NOTICE messages.
336 void
337 deleteWhatDependsOn(const ObjectAddress *object,
338 bool showNotices)
340 Relation depRel;
341 ObjectAddresses *targetObjects;
342 int i;
345 * We save some cycles by opening pg_depend just once and passing the
346 * Relation pointer down to all the recursive deletion steps.
348 depRel = heap_open(DependRelationId, RowExclusiveLock);
351 * Acquire deletion lock on the target object. (Ideally the caller has
352 * done this already, but many places are sloppy about it.)
354 AcquireDeletionLock(object);
357 * Construct a list of objects to delete (ie, the given object plus
358 * everything directly or indirectly dependent on it).
360 targetObjects = new_object_addresses();
362 findDependentObjects(object,
363 DEPFLAG_ORIGINAL,
364 NULL, /* empty stack */
365 targetObjects,
366 NULL, /* no pendingObjects */
367 depRel);
370 * Check if deletion is allowed, and report about cascaded deletes.
372 reportDependentObjects(targetObjects,
373 DROP_CASCADE,
374 showNotices ? NOTICE : DEBUG2,
375 object);
378 * Delete all the objects in the proper order, except we skip the original
379 * object.
381 for (i = 0; i < targetObjects->numrefs; i++)
383 ObjectAddress *thisobj = targetObjects->refs + i;
384 ObjectAddressExtra *thisextra = targetObjects->extras + i;
386 if (thisextra->flags & DEPFLAG_ORIGINAL)
387 continue;
389 deleteOneObject(thisobj, depRel);
392 /* And clean up */
393 free_object_addresses(targetObjects);
395 heap_close(depRel, RowExclusiveLock);
399 * findDependentObjects - find all objects that depend on 'object'
401 * For every object that depends on the starting object, acquire a deletion
402 * lock on the object, add it to targetObjects (if not already there),
403 * and recursively find objects that depend on it. An object's dependencies
404 * will be placed into targetObjects before the object itself; this means
405 * that the finished list's order represents a safe deletion order.
407 * The caller must already have a deletion lock on 'object' itself,
408 * but must not have added it to targetObjects. (Note: there are corner
409 * cases where we won't add the object either, and will also release the
410 * caller-taken lock. This is a bit ugly, but the API is set up this way
411 * to allow easy rechecking of an object's liveness after we lock it. See
412 * notes within the function.)
414 * When dropping a whole object (subId = 0), we find dependencies for
415 * its sub-objects too.
417 * object: the object to add to targetObjects and find dependencies on
418 * flags: flags to be ORed into the object's targetObjects entry
419 * stack: list of objects being visited in current recursion; topmost item
420 * is the object that we recursed from (NULL for external callers)
421 * targetObjects: list of objects that are scheduled to be deleted
422 * pendingObjects: list of other objects slated for destruction, but
423 * not necessarily in targetObjects yet (can be NULL if none)
424 * depRel: already opened pg_depend relation
426 static void
427 findDependentObjects(const ObjectAddress *object,
428 int flags,
429 ObjectAddressStack *stack,
430 ObjectAddresses *targetObjects,
431 const ObjectAddresses *pendingObjects,
432 Relation depRel)
434 ScanKeyData key[3];
435 int nkeys;
436 SysScanDesc scan;
437 HeapTuple tup;
438 ObjectAddress otherObject;
439 ObjectAddressStack mystack;
440 ObjectAddressExtra extra;
441 ObjectAddressStack *stackptr;
444 * If the target object is already being visited in an outer recursion
445 * level, just report the current flags back to that level and exit.
446 * This is needed to avoid infinite recursion in the face of circular
447 * dependencies.
449 * The stack check alone would result in dependency loops being broken at
450 * an arbitrary point, ie, the first member object of the loop to be
451 * visited is the last one to be deleted. This is obviously unworkable.
452 * However, the check for internal dependency below guarantees that we
453 * will not break a loop at an internal dependency: if we enter the loop
454 * at an "owned" object we will switch and start at the "owning" object
455 * instead. We could probably hack something up to avoid breaking at an
456 * auto dependency, too, if we had to. However there are no known cases
457 * where that would be necessary.
459 for (stackptr = stack; stackptr; stackptr = stackptr->next)
461 if (object->classId == stackptr->object->classId &&
462 object->objectId == stackptr->object->objectId)
464 if (object->objectSubId == stackptr->object->objectSubId)
466 stackptr->flags |= flags;
467 return;
470 * Could visit column with whole table already on stack; this is
471 * the same case noted in object_address_present_add_flags().
472 * (It's not clear this can really happen, but we might as well
473 * check.)
475 if (stackptr->object->objectSubId == 0)
476 return;
481 * It's also possible that the target object has already been completely
482 * processed and put into targetObjects. If so, again we just add the
483 * specified flags to its entry and return.
485 * (Note: in these early-exit cases we could release the caller-taken
486 * lock, since the object is presumably now locked multiple times;
487 * but it seems not worth the cycles.)
489 if (object_address_present_add_flags(object, flags, targetObjects))
490 return;
493 * The target object might be internally dependent on some other object
494 * (its "owner"). If so, and if we aren't recursing from the owning
495 * object, we have to transform this deletion request into a deletion
496 * request of the owning object. (We'll eventually recurse back to this
497 * object, but the owning object has to be visited first so it will be
498 * deleted after.) The way to find out about this is to scan the
499 * pg_depend entries that show what this object depends on.
501 ScanKeyInit(&key[0],
502 Anum_pg_depend_classid,
503 BTEqualStrategyNumber, F_OIDEQ,
504 ObjectIdGetDatum(object->classId));
505 ScanKeyInit(&key[1],
506 Anum_pg_depend_objid,
507 BTEqualStrategyNumber, F_OIDEQ,
508 ObjectIdGetDatum(object->objectId));
509 if (object->objectSubId != 0)
511 ScanKeyInit(&key[2],
512 Anum_pg_depend_objsubid,
513 BTEqualStrategyNumber, F_INT4EQ,
514 Int32GetDatum(object->objectSubId));
515 nkeys = 3;
517 else
518 nkeys = 2;
520 scan = systable_beginscan(depRel, DependDependerIndexId, true,
521 SnapshotNow, nkeys, key);
523 while (HeapTupleIsValid(tup = systable_getnext(scan)))
525 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
527 otherObject.classId = foundDep->refclassid;
528 otherObject.objectId = foundDep->refobjid;
529 otherObject.objectSubId = foundDep->refobjsubid;
531 switch (foundDep->deptype)
533 case DEPENDENCY_NORMAL:
534 case DEPENDENCY_AUTO:
535 /* no problem */
536 break;
537 case DEPENDENCY_INTERNAL:
540 * This object is part of the internal implementation of
541 * another object. We have three cases:
543 * 1. At the outermost recursion level, disallow the DROP. (We
544 * just ereport here, rather than proceeding, since no other
545 * dependencies are likely to be interesting.) However, if
546 * the other object is listed in pendingObjects, just release
547 * the caller's lock and return; we'll eventually complete
548 * the DROP when we reach that entry in the pending list.
550 if (stack == NULL)
552 char *otherObjDesc;
554 if (object_address_present(&otherObject, pendingObjects))
556 systable_endscan(scan);
557 /* need to release caller's lock; see notes below */
558 ReleaseDeletionLock(object);
559 return;
561 otherObjDesc = getObjectDescription(&otherObject);
562 ereport(ERROR,
563 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
564 errmsg("cannot drop %s because %s requires it",
565 getObjectDescription(object),
566 otherObjDesc),
567 errhint("You can drop %s instead.",
568 otherObjDesc)));
572 * 2. When recursing from the other end of this dependency,
573 * it's okay to continue with the deletion. This holds when
574 * recursing from a whole object that includes the nominal
575 * other end as a component, too.
577 if (stack->object->classId == otherObject.classId &&
578 stack->object->objectId == otherObject.objectId &&
579 (stack->object->objectSubId == otherObject.objectSubId ||
580 stack->object->objectSubId == 0))
581 break;
584 * 3. When recursing from anyplace else, transform this
585 * deletion request into a delete of the other object.
587 * First, release caller's lock on this object and get
588 * deletion lock on the other object. (We must release
589 * caller's lock to avoid deadlock against a concurrent
590 * deletion of the other object.)
592 ReleaseDeletionLock(object);
593 AcquireDeletionLock(&otherObject);
596 * The other object might have been deleted while we waited
597 * to lock it; if so, neither it nor the current object are
598 * interesting anymore. We test this by checking the
599 * pg_depend entry (see notes below).
601 if (!systable_recheck_tuple(scan, tup))
603 systable_endscan(scan);
604 ReleaseDeletionLock(&otherObject);
605 return;
609 * Okay, recurse to the other object instead of proceeding.
610 * We treat this exactly as if the original reference had
611 * linked to that object instead of this one; hence, pass
612 * through the same flags and stack.
614 findDependentObjects(&otherObject,
615 flags,
616 stack,
617 targetObjects,
618 pendingObjects,
619 depRel);
620 /* And we're done here. */
621 systable_endscan(scan);
622 return;
623 case DEPENDENCY_PIN:
626 * Should not happen; PIN dependencies should have zeroes in
627 * the depender fields...
629 elog(ERROR, "incorrect use of PIN dependency with %s",
630 getObjectDescription(object));
631 break;
632 default:
633 elog(ERROR, "unrecognized dependency type '%c' for %s",
634 foundDep->deptype, getObjectDescription(object));
635 break;
639 systable_endscan(scan);
642 * Now recurse to any dependent objects. We must visit them first
643 * since they have to be deleted before the current object.
645 mystack.object = object; /* set up a new stack level */
646 mystack.flags = flags;
647 mystack.next = stack;
649 ScanKeyInit(&key[0],
650 Anum_pg_depend_refclassid,
651 BTEqualStrategyNumber, F_OIDEQ,
652 ObjectIdGetDatum(object->classId));
653 ScanKeyInit(&key[1],
654 Anum_pg_depend_refobjid,
655 BTEqualStrategyNumber, F_OIDEQ,
656 ObjectIdGetDatum(object->objectId));
657 if (object->objectSubId != 0)
659 ScanKeyInit(&key[2],
660 Anum_pg_depend_refobjsubid,
661 BTEqualStrategyNumber, F_INT4EQ,
662 Int32GetDatum(object->objectSubId));
663 nkeys = 3;
665 else
666 nkeys = 2;
668 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
669 SnapshotNow, nkeys, key);
671 while (HeapTupleIsValid(tup = systable_getnext(scan)))
673 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
674 int subflags;
676 otherObject.classId = foundDep->classid;
677 otherObject.objectId = foundDep->objid;
678 otherObject.objectSubId = foundDep->objsubid;
681 * Must lock the dependent object before recursing to it.
683 AcquireDeletionLock(&otherObject);
686 * The dependent object might have been deleted while we waited
687 * to lock it; if so, we don't need to do anything more with it.
688 * We can test this cheaply and independently of the object's type
689 * by seeing if the pg_depend tuple we are looking at is still live.
690 * (If the object got deleted, the tuple would have been deleted too.)
692 if (!systable_recheck_tuple(scan, tup))
694 /* release the now-useless lock */
695 ReleaseDeletionLock(&otherObject);
696 /* and continue scanning for dependencies */
697 continue;
700 /* Recurse, passing flags indicating the dependency type */
701 switch (foundDep->deptype)
703 case DEPENDENCY_NORMAL:
704 subflags = DEPFLAG_NORMAL;
705 break;
706 case DEPENDENCY_AUTO:
707 subflags = DEPFLAG_AUTO;
708 break;
709 case DEPENDENCY_INTERNAL:
710 subflags = DEPFLAG_INTERNAL;
711 break;
712 case DEPENDENCY_PIN:
715 * For a PIN dependency we just ereport immediately; there
716 * won't be any others to report.
718 ereport(ERROR,
719 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
720 errmsg("cannot drop %s because it is required by the database system",
721 getObjectDescription(object))));
722 subflags = 0; /* keep compiler quiet */
723 break;
724 default:
725 elog(ERROR, "unrecognized dependency type '%c' for %s",
726 foundDep->deptype, getObjectDescription(object));
727 subflags = 0; /* keep compiler quiet */
728 break;
731 findDependentObjects(&otherObject,
732 subflags,
733 &mystack,
734 targetObjects,
735 pendingObjects,
736 depRel);
739 systable_endscan(scan);
742 * Finally, we can add the target object to targetObjects. Be careful
743 * to include any flags that were passed back down to us from inner
744 * recursion levels.
746 extra.flags = mystack.flags;
747 if (stack)
748 extra.dependee = *stack->object;
749 else
750 memset(&extra.dependee, 0, sizeof(extra.dependee));
751 add_exact_object_address_extra(object, &extra, targetObjects);
755 * reportDependentObjects - report about dependencies, and fail if RESTRICT
757 * Tell the user about dependent objects that we are going to delete
758 * (or would need to delete, but are prevented by RESTRICT mode);
759 * then error out if there are any and it's not CASCADE mode.
761 * targetObjects: list of objects that are scheduled to be deleted
762 * behavior: RESTRICT or CASCADE
763 * msglevel: elog level for non-error report messages
764 * origObject: base object of deletion, or NULL if not available
765 * (the latter case occurs in DROP OWNED)
767 static void
768 reportDependentObjects(const ObjectAddresses *targetObjects,
769 DropBehavior behavior,
770 int msglevel,
771 const ObjectAddress *origObject)
773 bool ok = true;
774 StringInfoData clientdetail;
775 StringInfoData logdetail;
776 int numReportedClient = 0;
777 int numNotReportedClient = 0;
778 int i;
781 * If no error is to be thrown, and the msglevel is too low to be shown
782 * to either client or server log, there's no need to do any of the work.
784 * Note: this code doesn't know all there is to be known about elog
785 * levels, but it works for NOTICE and DEBUG2, which are the only values
786 * msglevel can currently have. We also assume we are running in a normal
787 * operating environment.
789 if (behavior == DROP_CASCADE &&
790 msglevel < client_min_messages &&
791 (msglevel < log_min_messages || log_min_messages == LOG))
792 return;
795 * We limit the number of dependencies reported to the client to
796 * MAX_REPORTED_DEPS, since client software may not deal well with
797 * enormous error strings. The server log always gets a full report.
799 #define MAX_REPORTED_DEPS 100
801 initStringInfo(&clientdetail);
802 initStringInfo(&logdetail);
805 * We process the list back to front (ie, in dependency order not deletion
806 * order), since this makes for a more understandable display.
808 for (i = targetObjects->numrefs - 1; i >= 0; i--)
810 const ObjectAddress *obj = &targetObjects->refs[i];
811 const ObjectAddressExtra *extra = &targetObjects->extras[i];
812 char *objDesc;
814 /* Ignore the original deletion target(s) */
815 if (extra->flags & DEPFLAG_ORIGINAL)
816 continue;
818 objDesc = getObjectDescription(obj);
821 * If, at any stage of the recursive search, we reached the object
822 * via an AUTO or INTERNAL dependency, then it's okay to delete it
823 * even in RESTRICT mode.
825 if (extra->flags & (DEPFLAG_AUTO | DEPFLAG_INTERNAL))
828 * auto-cascades are reported at DEBUG2, not msglevel. We
829 * don't try to combine them with the regular message because
830 * the results are too confusing when client_min_messages and
831 * log_min_messages are different.
833 ereport(DEBUG2,
834 (errmsg("drop auto-cascades to %s",
835 objDesc)));
837 else if (behavior == DROP_RESTRICT)
839 char *otherDesc = getObjectDescription(&extra->dependee);
841 if (numReportedClient < MAX_REPORTED_DEPS)
843 /* separate entries with a newline */
844 if (clientdetail.len != 0)
845 appendStringInfoChar(&clientdetail, '\n');
846 appendStringInfo(&clientdetail, _("%s depends on %s"),
847 objDesc, otherDesc);
848 numReportedClient++;
850 else
851 numNotReportedClient++;
852 /* separate entries with a newline */
853 if (logdetail.len != 0)
854 appendStringInfoChar(&logdetail, '\n');
855 appendStringInfo(&logdetail, _("%s depends on %s"),
856 objDesc, otherDesc);
857 pfree(otherDesc);
858 ok = false;
860 else
862 if (numReportedClient < MAX_REPORTED_DEPS)
864 /* separate entries with a newline */
865 if (clientdetail.len != 0)
866 appendStringInfoChar(&clientdetail, '\n');
867 appendStringInfo(&clientdetail, _("drop cascades to %s"),
868 objDesc);
869 numReportedClient++;
871 else
872 numNotReportedClient++;
873 /* separate entries with a newline */
874 if (logdetail.len != 0)
875 appendStringInfoChar(&logdetail, '\n');
876 appendStringInfo(&logdetail, _("drop cascades to %s"),
877 objDesc);
880 pfree(objDesc);
883 if (numNotReportedClient > 0)
884 appendStringInfo(&clientdetail, _("\nand %d other objects "
885 "(see server log for list)"),
886 numNotReportedClient);
888 if (!ok)
890 if (origObject)
891 ereport(ERROR,
892 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
893 errmsg("cannot drop %s because other objects depend on it",
894 getObjectDescription(origObject)),
895 errdetail("%s", clientdetail.data),
896 errdetail_log("%s", logdetail.data),
897 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
898 else
899 ereport(ERROR,
900 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
901 errmsg("cannot drop desired object(s) because other objects depend on them"),
902 errdetail("%s", clientdetail.data),
903 errdetail_log("%s", logdetail.data),
904 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
906 else if (numReportedClient > 1)
908 ereport(msglevel,
909 /* translator: %d always has a value larger than 1 */
910 (errmsg("drop cascades to %d other objects",
911 numReportedClient + numNotReportedClient),
912 errdetail("%s", clientdetail.data),
913 errdetail_log("%s", logdetail.data)));
915 else if (numReportedClient == 1)
917 /* we just use the single item as-is */
918 ereport(msglevel,
919 (errmsg_internal("%s", clientdetail.data)));
922 pfree(clientdetail.data);
923 pfree(logdetail.data);
927 * deleteOneObject: delete a single object for performDeletion.
929 * depRel is the already-open pg_depend relation.
931 static void
932 deleteOneObject(const ObjectAddress *object, Relation depRel)
934 ScanKeyData key[3];
935 int nkeys;
936 SysScanDesc scan;
937 HeapTuple tup;
940 * First remove any pg_depend records that link from this object to
941 * others. (Any records linking to this object should be gone already.)
943 * When dropping a whole object (subId = 0), remove all pg_depend records
944 * for its sub-objects too.
946 ScanKeyInit(&key[0],
947 Anum_pg_depend_classid,
948 BTEqualStrategyNumber, F_OIDEQ,
949 ObjectIdGetDatum(object->classId));
950 ScanKeyInit(&key[1],
951 Anum_pg_depend_objid,
952 BTEqualStrategyNumber, F_OIDEQ,
953 ObjectIdGetDatum(object->objectId));
954 if (object->objectSubId != 0)
956 ScanKeyInit(&key[2],
957 Anum_pg_depend_objsubid,
958 BTEqualStrategyNumber, F_INT4EQ,
959 Int32GetDatum(object->objectSubId));
960 nkeys = 3;
962 else
963 nkeys = 2;
965 scan = systable_beginscan(depRel, DependDependerIndexId, true,
966 SnapshotNow, nkeys, key);
968 while (HeapTupleIsValid(tup = systable_getnext(scan)))
970 simple_heap_delete(depRel, &tup->t_self);
973 systable_endscan(scan);
976 * Now delete the object itself, in an object-type-dependent way.
978 doDeletion(object);
981 * Delete any comments associated with this object. (This is a convenient
982 * place to do it instead of having every object type know to do it.)
984 DeleteComments(object->objectId, object->classId, object->objectSubId);
987 * Delete shared dependency references related to this object. Sub-objects
988 * (columns) don't have dependencies on global objects, so skip them.
990 if (object->objectSubId == 0)
991 deleteSharedDependencyRecordsFor(object->classId, object->objectId);
994 * CommandCounterIncrement here to ensure that preceding changes are all
995 * visible to the next deletion step.
997 CommandCounterIncrement();
1000 * And we're done!
1005 * doDeletion: actually delete a single object
1007 static void
1008 doDeletion(const ObjectAddress *object)
1010 switch (getObjectClass(object))
1012 case OCLASS_CLASS:
1014 char relKind = get_rel_relkind(object->objectId);
1016 if (relKind == RELKIND_INDEX)
1018 Assert(object->objectSubId == 0);
1019 index_drop(object->objectId);
1021 else
1023 if (object->objectSubId != 0)
1024 RemoveAttributeById(object->objectId,
1025 object->objectSubId);
1026 else
1027 heap_drop_with_catalog(object->objectId);
1029 break;
1032 case OCLASS_PROC:
1033 RemoveFunctionById(object->objectId);
1034 break;
1036 case OCLASS_TYPE:
1037 RemoveTypeById(object->objectId);
1038 break;
1040 case OCLASS_CAST:
1041 DropCastById(object->objectId);
1042 break;
1044 case OCLASS_CONSTRAINT:
1045 RemoveConstraintById(object->objectId);
1046 break;
1048 case OCLASS_CONVERSION:
1049 RemoveConversionById(object->objectId);
1050 break;
1052 case OCLASS_DEFAULT:
1053 RemoveAttrDefaultById(object->objectId);
1054 break;
1056 case OCLASS_LANGUAGE:
1057 DropProceduralLanguageById(object->objectId);
1058 break;
1060 case OCLASS_OPERATOR:
1061 RemoveOperatorById(object->objectId);
1062 break;
1064 case OCLASS_OPCLASS:
1065 RemoveOpClassById(object->objectId);
1066 break;
1068 case OCLASS_OPFAMILY:
1069 RemoveOpFamilyById(object->objectId);
1070 break;
1072 case OCLASS_AMOP:
1073 RemoveAmOpEntryById(object->objectId);
1074 break;
1076 case OCLASS_AMPROC:
1077 RemoveAmProcEntryById(object->objectId);
1078 break;
1080 case OCLASS_REWRITE:
1081 RemoveRewriteRuleById(object->objectId);
1082 break;
1084 case OCLASS_TRIGGER:
1085 RemoveTriggerById(object->objectId);
1086 break;
1088 case OCLASS_SCHEMA:
1089 RemoveSchemaById(object->objectId);
1090 break;
1092 case OCLASS_TSPARSER:
1093 RemoveTSParserById(object->objectId);
1094 break;
1096 case OCLASS_TSDICT:
1097 RemoveTSDictionaryById(object->objectId);
1098 break;
1100 case OCLASS_TSTEMPLATE:
1101 RemoveTSTemplateById(object->objectId);
1102 break;
1104 case OCLASS_TSCONFIG:
1105 RemoveTSConfigurationById(object->objectId);
1106 break;
1108 /* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
1110 default:
1111 elog(ERROR, "unrecognized object class: %u",
1112 object->classId);
1117 * AcquireDeletionLock - acquire a suitable lock for deleting an object
1119 * We use LockRelation for relations, LockDatabaseObject for everything
1120 * else. Note that dependency.c is not concerned with deleting any kind of
1121 * shared-across-databases object, so we have no need for LockSharedObject.
1123 static void
1124 AcquireDeletionLock(const ObjectAddress *object)
1126 if (object->classId == RelationRelationId)
1127 LockRelationOid(object->objectId, AccessExclusiveLock);
1128 else
1129 /* assume we should lock the whole object not a sub-object */
1130 LockDatabaseObject(object->classId, object->objectId, 0,
1131 AccessExclusiveLock);
1135 * ReleaseDeletionLock - release an object deletion lock
1137 static void
1138 ReleaseDeletionLock(const ObjectAddress *object)
1140 if (object->classId == RelationRelationId)
1141 UnlockRelationOid(object->objectId, AccessExclusiveLock);
1142 else
1143 /* assume we should lock the whole object not a sub-object */
1144 UnlockDatabaseObject(object->classId, object->objectId, 0,
1145 AccessExclusiveLock);
1149 * recordDependencyOnExpr - find expression dependencies
1151 * This is used to find the dependencies of rules, constraint expressions,
1152 * etc.
1154 * Given an expression or query in node-tree form, find all the objects
1155 * it refers to (tables, columns, operators, functions, etc). Record
1156 * a dependency of the specified type from the given depender object
1157 * to each object mentioned in the expression.
1159 * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
1160 * It can be NIL if no such variables are expected.
1162 void
1163 recordDependencyOnExpr(const ObjectAddress *depender,
1164 Node *expr, List *rtable,
1165 DependencyType behavior)
1167 find_expr_references_context context;
1169 context.addrs = new_object_addresses();
1171 /* Set up interpretation for Vars at varlevelsup = 0 */
1172 context.rtables = list_make1(rtable);
1174 /* Scan the expression tree for referenceable objects */
1175 find_expr_references_walker(expr, &context);
1177 /* Remove any duplicates */
1178 eliminate_duplicate_dependencies(context.addrs);
1180 /* And record 'em */
1181 recordMultipleDependencies(depender,
1182 context.addrs->refs, context.addrs->numrefs,
1183 behavior);
1185 free_object_addresses(context.addrs);
1189 * recordDependencyOnSingleRelExpr - find expression dependencies
1191 * As above, but only one relation is expected to be referenced (with
1192 * varno = 1 and varlevelsup = 0). Pass the relation OID instead of a
1193 * range table. An additional frammish is that dependencies on that
1194 * relation (or its component columns) will be marked with 'self_behavior',
1195 * whereas 'behavior' is used for everything else.
1197 void
1198 recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
1199 Node *expr, Oid relId,
1200 DependencyType behavior,
1201 DependencyType self_behavior)
1203 find_expr_references_context context;
1204 RangeTblEntry rte;
1206 context.addrs = new_object_addresses();
1208 /* We gin up a rather bogus rangetable list to handle Vars */
1209 MemSet(&rte, 0, sizeof(rte));
1210 rte.type = T_RangeTblEntry;
1211 rte.rtekind = RTE_RELATION;
1212 rte.relid = relId;
1214 context.rtables = list_make1(list_make1(&rte));
1216 /* Scan the expression tree for referenceable objects */
1217 find_expr_references_walker(expr, &context);
1219 /* Remove any duplicates */
1220 eliminate_duplicate_dependencies(context.addrs);
1222 /* Separate self-dependencies if necessary */
1223 if (behavior != self_behavior && context.addrs->numrefs > 0)
1225 ObjectAddresses *self_addrs;
1226 ObjectAddress *outobj;
1227 int oldref,
1228 outrefs;
1230 self_addrs = new_object_addresses();
1232 outobj = context.addrs->refs;
1233 outrefs = 0;
1234 for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
1236 ObjectAddress *thisobj = context.addrs->refs + oldref;
1238 if (thisobj->classId == RelationRelationId &&
1239 thisobj->objectId == relId)
1241 /* Move this ref into self_addrs */
1242 add_exact_object_address(thisobj, self_addrs);
1244 else
1246 /* Keep it in context.addrs */
1247 *outobj = *thisobj;
1248 outobj++;
1249 outrefs++;
1252 context.addrs->numrefs = outrefs;
1254 /* Record the self-dependencies */
1255 recordMultipleDependencies(depender,
1256 self_addrs->refs, self_addrs->numrefs,
1257 self_behavior);
1259 free_object_addresses(self_addrs);
1262 /* Record the external dependencies */
1263 recordMultipleDependencies(depender,
1264 context.addrs->refs, context.addrs->numrefs,
1265 behavior);
1267 free_object_addresses(context.addrs);
1271 * Recursively search an expression tree for object references.
1273 * Note: we avoid creating references to columns of tables that participate
1274 * in an SQL JOIN construct, but are not actually used anywhere in the query.
1275 * To do so, we do not scan the joinaliasvars list of a join RTE while
1276 * scanning the query rangetable, but instead scan each individual entry
1277 * of the alias list when we find a reference to it.
1279 * Note: in many cases we do not need to create dependencies on the datatypes
1280 * involved in an expression, because we'll have an indirect dependency via
1281 * some other object. For instance Var nodes depend on a column which depends
1282 * on the datatype, and OpExpr nodes depend on the operator which depends on
1283 * the datatype. However we do need a type dependency if there is no such
1284 * indirect dependency, as for example in Const and CoerceToDomain nodes.
1286 static bool
1287 find_expr_references_walker(Node *node,
1288 find_expr_references_context *context)
1290 if (node == NULL)
1291 return false;
1292 if (IsA(node, Var))
1294 Var *var = (Var *) node;
1295 List *rtable;
1296 RangeTblEntry *rte;
1298 /* Find matching rtable entry, or complain if not found */
1299 if (var->varlevelsup >= list_length(context->rtables))
1300 elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
1301 rtable = (List *) list_nth(context->rtables, var->varlevelsup);
1302 if (var->varno <= 0 || var->varno > list_length(rtable))
1303 elog(ERROR, "invalid varno %d", var->varno);
1304 rte = rt_fetch(var->varno, rtable);
1307 * A whole-row Var references no specific columns, so adds no new
1308 * dependency.
1310 if (var->varattno == InvalidAttrNumber)
1311 return false;
1312 if (rte->rtekind == RTE_RELATION)
1314 /* If it's a plain relation, reference this column */
1315 add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
1316 context->addrs);
1318 else if (rte->rtekind == RTE_JOIN)
1320 /* Scan join output column to add references to join inputs */
1321 List *save_rtables;
1323 /* We must make the context appropriate for join's level */
1324 save_rtables = context->rtables;
1325 context->rtables = list_copy_tail(context->rtables,
1326 var->varlevelsup);
1327 if (var->varattno <= 0 ||
1328 var->varattno > list_length(rte->joinaliasvars))
1329 elog(ERROR, "invalid varattno %d", var->varattno);
1330 find_expr_references_walker((Node *) list_nth(rte->joinaliasvars,
1331 var->varattno - 1),
1332 context);
1333 list_free(context->rtables);
1334 context->rtables = save_rtables;
1336 return false;
1338 else if (IsA(node, Const))
1340 Const *con = (Const *) node;
1341 Oid objoid;
1343 /* A constant must depend on the constant's datatype */
1344 add_object_address(OCLASS_TYPE, con->consttype, 0,
1345 context->addrs);
1348 * If it's a regclass or similar literal referring to an existing
1349 * object, add a reference to that object. (Currently, only the
1350 * regclass and regconfig cases have any likely use, but we may as
1351 * well handle all the OID-alias datatypes consistently.)
1353 if (!con->constisnull)
1355 switch (con->consttype)
1357 case REGPROCOID:
1358 case REGPROCEDUREOID:
1359 objoid = DatumGetObjectId(con->constvalue);
1360 if (SearchSysCacheExists(PROCOID,
1361 ObjectIdGetDatum(objoid),
1362 0, 0, 0))
1363 add_object_address(OCLASS_PROC, objoid, 0,
1364 context->addrs);
1365 break;
1366 case REGOPEROID:
1367 case REGOPERATOROID:
1368 objoid = DatumGetObjectId(con->constvalue);
1369 if (SearchSysCacheExists(OPEROID,
1370 ObjectIdGetDatum(objoid),
1371 0, 0, 0))
1372 add_object_address(OCLASS_OPERATOR, objoid, 0,
1373 context->addrs);
1374 break;
1375 case REGCLASSOID:
1376 objoid = DatumGetObjectId(con->constvalue);
1377 if (SearchSysCacheExists(RELOID,
1378 ObjectIdGetDatum(objoid),
1379 0, 0, 0))
1380 add_object_address(OCLASS_CLASS, objoid, 0,
1381 context->addrs);
1382 break;
1383 case REGTYPEOID:
1384 objoid = DatumGetObjectId(con->constvalue);
1385 if (SearchSysCacheExists(TYPEOID,
1386 ObjectIdGetDatum(objoid),
1387 0, 0, 0))
1388 add_object_address(OCLASS_TYPE, objoid, 0,
1389 context->addrs);
1390 break;
1391 case REGCONFIGOID:
1392 objoid = DatumGetObjectId(con->constvalue);
1393 if (SearchSysCacheExists(TSCONFIGOID,
1394 ObjectIdGetDatum(objoid),
1395 0, 0, 0))
1396 add_object_address(OCLASS_TSCONFIG, objoid, 0,
1397 context->addrs);
1398 break;
1399 case REGDICTIONARYOID:
1400 objoid = DatumGetObjectId(con->constvalue);
1401 if (SearchSysCacheExists(TSDICTOID,
1402 ObjectIdGetDatum(objoid),
1403 0, 0, 0))
1404 add_object_address(OCLASS_TSDICT, objoid, 0,
1405 context->addrs);
1406 break;
1409 return false;
1411 else if (IsA(node, Param))
1413 Param *param = (Param *) node;
1415 /* A parameter must depend on the parameter's datatype */
1416 add_object_address(OCLASS_TYPE, param->paramtype, 0,
1417 context->addrs);
1419 else if (IsA(node, FuncExpr))
1421 FuncExpr *funcexpr = (FuncExpr *) node;
1423 add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
1424 context->addrs);
1425 /* fall through to examine arguments */
1427 else if (IsA(node, OpExpr))
1429 OpExpr *opexpr = (OpExpr *) node;
1431 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1432 context->addrs);
1433 /* fall through to examine arguments */
1435 else if (IsA(node, DistinctExpr))
1437 DistinctExpr *distinctexpr = (DistinctExpr *) node;
1439 add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
1440 context->addrs);
1441 /* fall through to examine arguments */
1443 else if (IsA(node, ScalarArrayOpExpr))
1445 ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1447 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1448 context->addrs);
1449 /* fall through to examine arguments */
1451 else if (IsA(node, NullIfExpr))
1453 NullIfExpr *nullifexpr = (NullIfExpr *) node;
1455 add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
1456 context->addrs);
1457 /* fall through to examine arguments */
1459 else if (IsA(node, Aggref))
1461 Aggref *aggref = (Aggref *) node;
1463 add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
1464 context->addrs);
1465 /* fall through to examine arguments */
1467 else if (IsA(node, SubPlan))
1469 /* Extra work needed here if we ever need this case */
1470 elog(ERROR, "already-planned subqueries not supported");
1472 else if (IsA(node, RelabelType))
1474 RelabelType *relab = (RelabelType *) node;
1476 /* since there is no function dependency, need to depend on type */
1477 add_object_address(OCLASS_TYPE, relab->resulttype, 0,
1478 context->addrs);
1480 else if (IsA(node, CoerceViaIO))
1482 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1484 /* since there is no exposed function, need to depend on type */
1485 add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0,
1486 context->addrs);
1488 else if (IsA(node, ArrayCoerceExpr))
1490 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1492 if (OidIsValid(acoerce->elemfuncid))
1493 add_object_address(OCLASS_PROC, acoerce->elemfuncid, 0,
1494 context->addrs);
1495 add_object_address(OCLASS_TYPE, acoerce->resulttype, 0,
1496 context->addrs);
1497 /* fall through to examine arguments */
1499 else if (IsA(node, ConvertRowtypeExpr))
1501 ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
1503 /* since there is no function dependency, need to depend on type */
1504 add_object_address(OCLASS_TYPE, cvt->resulttype, 0,
1505 context->addrs);
1507 else if (IsA(node, RowExpr))
1509 RowExpr *rowexpr = (RowExpr *) node;
1511 add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
1512 context->addrs);
1514 else if (IsA(node, RowCompareExpr))
1516 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1517 ListCell *l;
1519 foreach(l, rcexpr->opnos)
1521 add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
1522 context->addrs);
1524 foreach(l, rcexpr->opfamilies)
1526 add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
1527 context->addrs);
1529 /* fall through to examine arguments */
1531 else if (IsA(node, CoerceToDomain))
1533 CoerceToDomain *cd = (CoerceToDomain *) node;
1535 add_object_address(OCLASS_TYPE, cd->resulttype, 0,
1536 context->addrs);
1538 else if (IsA(node, SortGroupClause))
1540 SortGroupClause *sgc = (SortGroupClause *) node;
1542 add_object_address(OCLASS_OPERATOR, sgc->eqop, 0,
1543 context->addrs);
1544 if (OidIsValid(sgc->sortop))
1545 add_object_address(OCLASS_OPERATOR, sgc->sortop, 0,
1546 context->addrs);
1547 return false;
1549 else if (IsA(node, Query))
1551 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1552 Query *query = (Query *) node;
1553 ListCell *rtable;
1554 bool result;
1557 * Add whole-relation refs for each plain relation mentioned in the
1558 * subquery's rtable, as well as datatype refs for any datatypes used
1559 * as a RECORD function's output. (Note: query_tree_walker takes care
1560 * of recursing into RTE_FUNCTION RTEs, subqueries, etc, so no need to
1561 * do that here. But keep it from looking at join alias lists.)
1563 foreach(rtable, query->rtable)
1565 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtable);
1566 ListCell *ct;
1568 switch (rte->rtekind)
1570 case RTE_RELATION:
1571 add_object_address(OCLASS_CLASS, rte->relid, 0,
1572 context->addrs);
1573 break;
1574 case RTE_FUNCTION:
1575 foreach(ct, rte->funccoltypes)
1577 add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0,
1578 context->addrs);
1580 break;
1581 default:
1582 break;
1586 /* query_tree_walker ignores ORDER BY etc, but we need those opers */
1587 find_expr_references_walker((Node *) query->sortClause, context);
1588 find_expr_references_walker((Node *) query->groupClause, context);
1589 find_expr_references_walker((Node *) query->distinctClause, context);
1591 /* Examine substructure of query */
1592 context->rtables = lcons(query->rtable, context->rtables);
1593 result = query_tree_walker(query,
1594 find_expr_references_walker,
1595 (void *) context,
1596 QTW_IGNORE_JOINALIASES);
1597 context->rtables = list_delete_first(context->rtables);
1598 return result;
1600 else if (IsA(node, SetOperationStmt))
1602 SetOperationStmt *setop = (SetOperationStmt *) node;
1604 /* we need to look at the groupClauses for operator references */
1605 find_expr_references_walker((Node *) setop->groupClauses, context);
1606 /* fall through to examine child nodes */
1609 return expression_tree_walker(node, find_expr_references_walker,
1610 (void *) context);
1614 * Given an array of dependency references, eliminate any duplicates.
1616 static void
1617 eliminate_duplicate_dependencies(ObjectAddresses *addrs)
1619 ObjectAddress *priorobj;
1620 int oldref,
1621 newrefs;
1624 * We can't sort if the array has "extra" data, because there's no way
1625 * to keep it in sync. Fortunately that combination of features is
1626 * not needed.
1628 Assert(!addrs->extras);
1630 if (addrs->numrefs <= 1)
1631 return; /* nothing to do */
1633 /* Sort the refs so that duplicates are adjacent */
1634 qsort((void *) addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
1635 object_address_comparator);
1637 /* Remove dups */
1638 priorobj = addrs->refs;
1639 newrefs = 1;
1640 for (oldref = 1; oldref < addrs->numrefs; oldref++)
1642 ObjectAddress *thisobj = addrs->refs + oldref;
1644 if (priorobj->classId == thisobj->classId &&
1645 priorobj->objectId == thisobj->objectId)
1647 if (priorobj->objectSubId == thisobj->objectSubId)
1648 continue; /* identical, so drop thisobj */
1651 * If we have a whole-object reference and a reference to a part
1652 * of the same object, we don't need the whole-object reference
1653 * (for example, we don't need to reference both table foo and
1654 * column foo.bar). The whole-object reference will always appear
1655 * first in the sorted list.
1657 if (priorobj->objectSubId == 0)
1659 /* replace whole ref with partial */
1660 priorobj->objectSubId = thisobj->objectSubId;
1661 continue;
1664 /* Not identical, so add thisobj to output set */
1665 priorobj++;
1666 *priorobj = *thisobj;
1667 newrefs++;
1670 addrs->numrefs = newrefs;
1674 * qsort comparator for ObjectAddress items
1676 static int
1677 object_address_comparator(const void *a, const void *b)
1679 const ObjectAddress *obja = (const ObjectAddress *) a;
1680 const ObjectAddress *objb = (const ObjectAddress *) b;
1682 if (obja->classId < objb->classId)
1683 return -1;
1684 if (obja->classId > objb->classId)
1685 return 1;
1686 if (obja->objectId < objb->objectId)
1687 return -1;
1688 if (obja->objectId > objb->objectId)
1689 return 1;
1692 * We sort the subId as an unsigned int so that 0 will come first. See
1693 * logic in eliminate_duplicate_dependencies.
1695 if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
1696 return -1;
1697 if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
1698 return 1;
1699 return 0;
1703 * Routines for handling an expansible array of ObjectAddress items.
1705 * new_object_addresses: create a new ObjectAddresses array.
1707 ObjectAddresses *
1708 new_object_addresses(void)
1710 ObjectAddresses *addrs;
1712 addrs = palloc(sizeof(ObjectAddresses));
1714 addrs->numrefs = 0;
1715 addrs->maxrefs = 32;
1716 addrs->refs = (ObjectAddress *)
1717 palloc(addrs->maxrefs * sizeof(ObjectAddress));
1718 addrs->extras = NULL; /* until/unless needed */
1720 return addrs;
1724 * Add an entry to an ObjectAddresses array.
1726 * It is convenient to specify the class by ObjectClass rather than directly
1727 * by catalog OID.
1729 static void
1730 add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
1731 ObjectAddresses *addrs)
1733 ObjectAddress *item;
1735 /* enlarge array if needed */
1736 if (addrs->numrefs >= addrs->maxrefs)
1738 addrs->maxrefs *= 2;
1739 addrs->refs = (ObjectAddress *)
1740 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1741 Assert(!addrs->extras);
1743 /* record this item */
1744 item = addrs->refs + addrs->numrefs;
1745 item->classId = object_classes[oclass];
1746 item->objectId = objectId;
1747 item->objectSubId = subId;
1748 addrs->numrefs++;
1752 * Add an entry to an ObjectAddresses array.
1754 * As above, but specify entry exactly.
1756 void
1757 add_exact_object_address(const ObjectAddress *object,
1758 ObjectAddresses *addrs)
1760 ObjectAddress *item;
1762 /* enlarge array if needed */
1763 if (addrs->numrefs >= addrs->maxrefs)
1765 addrs->maxrefs *= 2;
1766 addrs->refs = (ObjectAddress *)
1767 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1768 Assert(!addrs->extras);
1770 /* record this item */
1771 item = addrs->refs + addrs->numrefs;
1772 *item = *object;
1773 addrs->numrefs++;
1777 * Add an entry to an ObjectAddresses array.
1779 * As above, but specify entry exactly and provide some "extra" data too.
1781 static void
1782 add_exact_object_address_extra(const ObjectAddress *object,
1783 const ObjectAddressExtra *extra,
1784 ObjectAddresses *addrs)
1786 ObjectAddress *item;
1787 ObjectAddressExtra *itemextra;
1789 /* allocate extra space if first time */
1790 if (!addrs->extras)
1791 addrs->extras = (ObjectAddressExtra *)
1792 palloc(addrs->maxrefs * sizeof(ObjectAddressExtra));
1794 /* enlarge array if needed */
1795 if (addrs->numrefs >= addrs->maxrefs)
1797 addrs->maxrefs *= 2;
1798 addrs->refs = (ObjectAddress *)
1799 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1800 addrs->extras = (ObjectAddressExtra *)
1801 repalloc(addrs->extras, addrs->maxrefs * sizeof(ObjectAddressExtra));
1803 /* record this item */
1804 item = addrs->refs + addrs->numrefs;
1805 *item = *object;
1806 itemextra = addrs->extras + addrs->numrefs;
1807 *itemextra = *extra;
1808 addrs->numrefs++;
1812 * Test whether an object is present in an ObjectAddresses array.
1814 * We return "true" if object is a subobject of something in the array, too.
1816 bool
1817 object_address_present(const ObjectAddress *object,
1818 const ObjectAddresses *addrs)
1820 int i;
1822 for (i = addrs->numrefs - 1; i >= 0; i--)
1824 const ObjectAddress *thisobj = addrs->refs + i;
1826 if (object->classId == thisobj->classId &&
1827 object->objectId == thisobj->objectId)
1829 if (object->objectSubId == thisobj->objectSubId ||
1830 thisobj->objectSubId == 0)
1831 return true;
1835 return false;
1839 * As above, except that if the object is present then also OR the given
1840 * flags into its associated extra data (which must exist).
1842 static bool
1843 object_address_present_add_flags(const ObjectAddress *object,
1844 int flags,
1845 ObjectAddresses *addrs)
1847 int i;
1849 for (i = addrs->numrefs - 1; i >= 0; i--)
1851 ObjectAddress *thisobj = addrs->refs + i;
1853 if (object->classId == thisobj->classId &&
1854 object->objectId == thisobj->objectId)
1856 if (object->objectSubId == thisobj->objectSubId)
1858 ObjectAddressExtra *thisextra = addrs->extras + i;
1860 thisextra->flags |= flags;
1861 return true;
1863 if (thisobj->objectSubId == 0)
1866 * We get here if we find a need to delete a column after
1867 * having already decided to drop its whole table. Obviously
1868 * we no longer need to drop the column. But don't plaster
1869 * its flags on the table.
1871 return true;
1876 return false;
1880 * Record multiple dependencies from an ObjectAddresses array, after first
1881 * removing any duplicates.
1883 void
1884 record_object_address_dependencies(const ObjectAddress *depender,
1885 ObjectAddresses *referenced,
1886 DependencyType behavior)
1888 eliminate_duplicate_dependencies(referenced);
1889 recordMultipleDependencies(depender,
1890 referenced->refs, referenced->numrefs,
1891 behavior);
1895 * Clean up when done with an ObjectAddresses array.
1897 void
1898 free_object_addresses(ObjectAddresses *addrs)
1900 pfree(addrs->refs);
1901 if (addrs->extras)
1902 pfree(addrs->extras);
1903 pfree(addrs);
1907 * Determine the class of a given object identified by objectAddress.
1909 * This function is essentially the reverse mapping for the object_classes[]
1910 * table. We implement it as a function because the OIDs aren't consecutive.
1912 ObjectClass
1913 getObjectClass(const ObjectAddress *object)
1915 switch (object->classId)
1917 case RelationRelationId:
1918 /* caller must check objectSubId */
1919 return OCLASS_CLASS;
1921 case ProcedureRelationId:
1922 Assert(object->objectSubId == 0);
1923 return OCLASS_PROC;
1925 case TypeRelationId:
1926 Assert(object->objectSubId == 0);
1927 return OCLASS_TYPE;
1929 case CastRelationId:
1930 Assert(object->objectSubId == 0);
1931 return OCLASS_CAST;
1933 case ConstraintRelationId:
1934 Assert(object->objectSubId == 0);
1935 return OCLASS_CONSTRAINT;
1937 case ConversionRelationId:
1938 Assert(object->objectSubId == 0);
1939 return OCLASS_CONVERSION;
1941 case AttrDefaultRelationId:
1942 Assert(object->objectSubId == 0);
1943 return OCLASS_DEFAULT;
1945 case LanguageRelationId:
1946 Assert(object->objectSubId == 0);
1947 return OCLASS_LANGUAGE;
1949 case OperatorRelationId:
1950 Assert(object->objectSubId == 0);
1951 return OCLASS_OPERATOR;
1953 case OperatorClassRelationId:
1954 Assert(object->objectSubId == 0);
1955 return OCLASS_OPCLASS;
1957 case OperatorFamilyRelationId:
1958 Assert(object->objectSubId == 0);
1959 return OCLASS_OPFAMILY;
1961 case AccessMethodOperatorRelationId:
1962 Assert(object->objectSubId == 0);
1963 return OCLASS_AMOP;
1965 case AccessMethodProcedureRelationId:
1966 Assert(object->objectSubId == 0);
1967 return OCLASS_AMPROC;
1969 case RewriteRelationId:
1970 Assert(object->objectSubId == 0);
1971 return OCLASS_REWRITE;
1973 case TriggerRelationId:
1974 Assert(object->objectSubId == 0);
1975 return OCLASS_TRIGGER;
1977 case NamespaceRelationId:
1978 Assert(object->objectSubId == 0);
1979 return OCLASS_SCHEMA;
1981 case TSParserRelationId:
1982 Assert(object->objectSubId == 0);
1983 return OCLASS_TSPARSER;
1985 case TSDictionaryRelationId:
1986 Assert(object->objectSubId == 0);
1987 return OCLASS_TSDICT;
1989 case TSTemplateRelationId:
1990 Assert(object->objectSubId == 0);
1991 return OCLASS_TSTEMPLATE;
1993 case TSConfigRelationId:
1994 Assert(object->objectSubId == 0);
1995 return OCLASS_TSCONFIG;
1997 case AuthIdRelationId:
1998 Assert(object->objectSubId == 0);
1999 return OCLASS_ROLE;
2001 case DatabaseRelationId:
2002 Assert(object->objectSubId == 0);
2003 return OCLASS_DATABASE;
2005 case TableSpaceRelationId:
2006 Assert(object->objectSubId == 0);
2007 return OCLASS_TBLSPACE;
2010 /* shouldn't get here */
2011 elog(ERROR, "unrecognized object class: %u", object->classId);
2012 return OCLASS_CLASS; /* keep compiler quiet */
2016 * getObjectDescription: build an object description for messages
2018 * The result is a palloc'd string.
2020 char *
2021 getObjectDescription(const ObjectAddress *object)
2023 StringInfoData buffer;
2025 initStringInfo(&buffer);
2027 switch (getObjectClass(object))
2029 case OCLASS_CLASS:
2030 getRelationDescription(&buffer, object->objectId);
2031 if (object->objectSubId != 0)
2032 appendStringInfo(&buffer, _(" column %s"),
2033 get_relid_attribute_name(object->objectId,
2034 object->objectSubId));
2035 break;
2037 case OCLASS_PROC:
2038 appendStringInfo(&buffer, _("function %s"),
2039 format_procedure(object->objectId));
2040 break;
2042 case OCLASS_TYPE:
2043 appendStringInfo(&buffer, _("type %s"),
2044 format_type_be(object->objectId));
2045 break;
2047 case OCLASS_CAST:
2049 Relation castDesc;
2050 ScanKeyData skey[1];
2051 SysScanDesc rcscan;
2052 HeapTuple tup;
2053 Form_pg_cast castForm;
2055 castDesc = heap_open(CastRelationId, AccessShareLock);
2057 ScanKeyInit(&skey[0],
2058 ObjectIdAttributeNumber,
2059 BTEqualStrategyNumber, F_OIDEQ,
2060 ObjectIdGetDatum(object->objectId));
2062 rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
2063 SnapshotNow, 1, skey);
2065 tup = systable_getnext(rcscan);
2067 if (!HeapTupleIsValid(tup))
2068 elog(ERROR, "could not find tuple for cast %u",
2069 object->objectId);
2071 castForm = (Form_pg_cast) GETSTRUCT(tup);
2073 appendStringInfo(&buffer, _("cast from %s to %s"),
2074 format_type_be(castForm->castsource),
2075 format_type_be(castForm->casttarget));
2077 systable_endscan(rcscan);
2078 heap_close(castDesc, AccessShareLock);
2079 break;
2082 case OCLASS_CONSTRAINT:
2084 HeapTuple conTup;
2085 Form_pg_constraint con;
2087 conTup = SearchSysCache(CONSTROID,
2088 ObjectIdGetDatum(object->objectId),
2089 0, 0, 0);
2090 if (!HeapTupleIsValid(conTup))
2091 elog(ERROR, "cache lookup failed for constraint %u",
2092 object->objectId);
2093 con = (Form_pg_constraint) GETSTRUCT(conTup);
2095 if (OidIsValid(con->conrelid))
2097 StringInfoData rel;
2099 initStringInfo(&rel);
2100 getRelationDescription(&rel, con->conrelid);
2101 appendStringInfo(&buffer, _("constraint %s on %s"),
2102 NameStr(con->conname), rel.data);
2103 pfree(rel.data);
2105 else
2107 appendStringInfo(&buffer, _("constraint %s"),
2108 NameStr(con->conname));
2111 ReleaseSysCache(conTup);
2112 break;
2115 case OCLASS_CONVERSION:
2117 HeapTuple conTup;
2119 conTup = SearchSysCache(CONVOID,
2120 ObjectIdGetDatum(object->objectId),
2121 0, 0, 0);
2122 if (!HeapTupleIsValid(conTup))
2123 elog(ERROR, "cache lookup failed for conversion %u",
2124 object->objectId);
2125 appendStringInfo(&buffer, _("conversion %s"),
2126 NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
2127 ReleaseSysCache(conTup);
2128 break;
2131 case OCLASS_DEFAULT:
2133 Relation attrdefDesc;
2134 ScanKeyData skey[1];
2135 SysScanDesc adscan;
2136 HeapTuple tup;
2137 Form_pg_attrdef attrdef;
2138 ObjectAddress colobject;
2140 attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
2142 ScanKeyInit(&skey[0],
2143 ObjectIdAttributeNumber,
2144 BTEqualStrategyNumber, F_OIDEQ,
2145 ObjectIdGetDatum(object->objectId));
2147 adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
2148 true, SnapshotNow, 1, skey);
2150 tup = systable_getnext(adscan);
2152 if (!HeapTupleIsValid(tup))
2153 elog(ERROR, "could not find tuple for attrdef %u",
2154 object->objectId);
2156 attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
2158 colobject.classId = RelationRelationId;
2159 colobject.objectId = attrdef->adrelid;
2160 colobject.objectSubId = attrdef->adnum;
2162 appendStringInfo(&buffer, _("default for %s"),
2163 getObjectDescription(&colobject));
2165 systable_endscan(adscan);
2166 heap_close(attrdefDesc, AccessShareLock);
2167 break;
2170 case OCLASS_LANGUAGE:
2172 HeapTuple langTup;
2174 langTup = SearchSysCache(LANGOID,
2175 ObjectIdGetDatum(object->objectId),
2176 0, 0, 0);
2177 if (!HeapTupleIsValid(langTup))
2178 elog(ERROR, "cache lookup failed for language %u",
2179 object->objectId);
2180 appendStringInfo(&buffer, _("language %s"),
2181 NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
2182 ReleaseSysCache(langTup);
2183 break;
2186 case OCLASS_OPERATOR:
2187 appendStringInfo(&buffer, _("operator %s"),
2188 format_operator(object->objectId));
2189 break;
2191 case OCLASS_OPCLASS:
2193 HeapTuple opcTup;
2194 Form_pg_opclass opcForm;
2195 HeapTuple amTup;
2196 Form_pg_am amForm;
2197 char *nspname;
2199 opcTup = SearchSysCache(CLAOID,
2200 ObjectIdGetDatum(object->objectId),
2201 0, 0, 0);
2202 if (!HeapTupleIsValid(opcTup))
2203 elog(ERROR, "cache lookup failed for opclass %u",
2204 object->objectId);
2205 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
2207 amTup = SearchSysCache(AMOID,
2208 ObjectIdGetDatum(opcForm->opcmethod),
2209 0, 0, 0);
2210 if (!HeapTupleIsValid(amTup))
2211 elog(ERROR, "cache lookup failed for access method %u",
2212 opcForm->opcmethod);
2213 amForm = (Form_pg_am) GETSTRUCT(amTup);
2215 /* Qualify the name if not visible in search path */
2216 if (OpclassIsVisible(object->objectId))
2217 nspname = NULL;
2218 else
2219 nspname = get_namespace_name(opcForm->opcnamespace);
2221 appendStringInfo(&buffer, _("operator class %s for access method %s"),
2222 quote_qualified_identifier(nspname,
2223 NameStr(opcForm->opcname)),
2224 NameStr(amForm->amname));
2226 ReleaseSysCache(amTup);
2227 ReleaseSysCache(opcTup);
2228 break;
2231 case OCLASS_OPFAMILY:
2232 getOpFamilyDescription(&buffer, object->objectId);
2233 break;
2235 case OCLASS_AMOP:
2237 Relation amopDesc;
2238 ScanKeyData skey[1];
2239 SysScanDesc amscan;
2240 HeapTuple tup;
2241 Form_pg_amop amopForm;
2242 StringInfoData opfam;
2244 amopDesc = heap_open(AccessMethodOperatorRelationId,
2245 AccessShareLock);
2247 ScanKeyInit(&skey[0],
2248 ObjectIdAttributeNumber,
2249 BTEqualStrategyNumber, F_OIDEQ,
2250 ObjectIdGetDatum(object->objectId));
2252 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
2253 SnapshotNow, 1, skey);
2255 tup = systable_getnext(amscan);
2257 if (!HeapTupleIsValid(tup))
2258 elog(ERROR, "could not find tuple for amop entry %u",
2259 object->objectId);
2261 amopForm = (Form_pg_amop) GETSTRUCT(tup);
2263 initStringInfo(&opfam);
2264 getOpFamilyDescription(&opfam, amopForm->amopfamily);
2266 * translator: %d is the operator strategy (a number), the
2267 * first %s is the textual form of the operator, and the second
2268 * %s is the description of the operator family.
2270 appendStringInfo(&buffer, _("operator %d %s of %s"),
2271 amopForm->amopstrategy,
2272 format_operator(amopForm->amopopr),
2273 opfam.data);
2274 pfree(opfam.data);
2276 systable_endscan(amscan);
2277 heap_close(amopDesc, AccessShareLock);
2278 break;
2281 case OCLASS_AMPROC:
2283 Relation amprocDesc;
2284 ScanKeyData skey[1];
2285 SysScanDesc amscan;
2286 HeapTuple tup;
2287 Form_pg_amproc amprocForm;
2288 StringInfoData opfam;
2290 amprocDesc = heap_open(AccessMethodProcedureRelationId,
2291 AccessShareLock);
2293 ScanKeyInit(&skey[0],
2294 ObjectIdAttributeNumber,
2295 BTEqualStrategyNumber, F_OIDEQ,
2296 ObjectIdGetDatum(object->objectId));
2298 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
2299 SnapshotNow, 1, skey);
2301 tup = systable_getnext(amscan);
2303 if (!HeapTupleIsValid(tup))
2304 elog(ERROR, "could not find tuple for amproc entry %u",
2305 object->objectId);
2307 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
2309 initStringInfo(&opfam);
2310 getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
2312 * translator: %d is the function number, the first %s is the
2313 * textual form of the function with arguments, and the second
2314 * %s is the description of the operator family.
2316 appendStringInfo(&buffer, _("function %d %s of %s"),
2317 amprocForm->amprocnum,
2318 format_procedure(amprocForm->amproc),
2319 opfam.data);
2320 pfree(opfam.data);
2322 systable_endscan(amscan);
2323 heap_close(amprocDesc, AccessShareLock);
2324 break;
2327 case OCLASS_REWRITE:
2329 Relation ruleDesc;
2330 ScanKeyData skey[1];
2331 SysScanDesc rcscan;
2332 HeapTuple tup;
2333 Form_pg_rewrite rule;
2335 ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
2337 ScanKeyInit(&skey[0],
2338 ObjectIdAttributeNumber,
2339 BTEqualStrategyNumber, F_OIDEQ,
2340 ObjectIdGetDatum(object->objectId));
2342 rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
2343 SnapshotNow, 1, skey);
2345 tup = systable_getnext(rcscan);
2347 if (!HeapTupleIsValid(tup))
2348 elog(ERROR, "could not find tuple for rule %u",
2349 object->objectId);
2351 rule = (Form_pg_rewrite) GETSTRUCT(tup);
2353 appendStringInfo(&buffer, _("rule %s on "),
2354 NameStr(rule->rulename));
2355 getRelationDescription(&buffer, rule->ev_class);
2357 systable_endscan(rcscan);
2358 heap_close(ruleDesc, AccessShareLock);
2359 break;
2362 case OCLASS_TRIGGER:
2364 Relation trigDesc;
2365 ScanKeyData skey[1];
2366 SysScanDesc tgscan;
2367 HeapTuple tup;
2368 Form_pg_trigger trig;
2370 trigDesc = heap_open(TriggerRelationId, AccessShareLock);
2372 ScanKeyInit(&skey[0],
2373 ObjectIdAttributeNumber,
2374 BTEqualStrategyNumber, F_OIDEQ,
2375 ObjectIdGetDatum(object->objectId));
2377 tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
2378 SnapshotNow, 1, skey);
2380 tup = systable_getnext(tgscan);
2382 if (!HeapTupleIsValid(tup))
2383 elog(ERROR, "could not find tuple for trigger %u",
2384 object->objectId);
2386 trig = (Form_pg_trigger) GETSTRUCT(tup);
2388 appendStringInfo(&buffer, _("trigger %s on "),
2389 NameStr(trig->tgname));
2390 getRelationDescription(&buffer, trig->tgrelid);
2392 systable_endscan(tgscan);
2393 heap_close(trigDesc, AccessShareLock);
2394 break;
2397 case OCLASS_SCHEMA:
2399 char *nspname;
2401 nspname = get_namespace_name(object->objectId);
2402 if (!nspname)
2403 elog(ERROR, "cache lookup failed for namespace %u",
2404 object->objectId);
2405 appendStringInfo(&buffer, _("schema %s"), nspname);
2406 break;
2409 case OCLASS_TSPARSER:
2411 HeapTuple tup;
2413 tup = SearchSysCache(TSPARSEROID,
2414 ObjectIdGetDatum(object->objectId),
2415 0, 0, 0);
2416 if (!HeapTupleIsValid(tup))
2417 elog(ERROR, "cache lookup failed for text search parser %u",
2418 object->objectId);
2419 appendStringInfo(&buffer, _("text search parser %s"),
2420 NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
2421 ReleaseSysCache(tup);
2422 break;
2425 case OCLASS_TSDICT:
2427 HeapTuple tup;
2429 tup = SearchSysCache(TSDICTOID,
2430 ObjectIdGetDatum(object->objectId),
2431 0, 0, 0);
2432 if (!HeapTupleIsValid(tup))
2433 elog(ERROR, "cache lookup failed for text search dictionary %u",
2434 object->objectId);
2435 appendStringInfo(&buffer, _("text search dictionary %s"),
2436 NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
2437 ReleaseSysCache(tup);
2438 break;
2441 case OCLASS_TSTEMPLATE:
2443 HeapTuple tup;
2445 tup = SearchSysCache(TSTEMPLATEOID,
2446 ObjectIdGetDatum(object->objectId),
2447 0, 0, 0);
2448 if (!HeapTupleIsValid(tup))
2449 elog(ERROR, "cache lookup failed for text search template %u",
2450 object->objectId);
2451 appendStringInfo(&buffer, _("text search template %s"),
2452 NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
2453 ReleaseSysCache(tup);
2454 break;
2457 case OCLASS_TSCONFIG:
2459 HeapTuple tup;
2461 tup = SearchSysCache(TSCONFIGOID,
2462 ObjectIdGetDatum(object->objectId),
2463 0, 0, 0);
2464 if (!HeapTupleIsValid(tup))
2465 elog(ERROR, "cache lookup failed for text search configuration %u",
2466 object->objectId);
2467 appendStringInfo(&buffer, _("text search configuration %s"),
2468 NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
2469 ReleaseSysCache(tup);
2470 break;
2473 case OCLASS_ROLE:
2475 appendStringInfo(&buffer, _("role %s"),
2476 GetUserNameFromId(object->objectId));
2477 break;
2480 case OCLASS_DATABASE:
2482 char *datname;
2484 datname = get_database_name(object->objectId);
2485 if (!datname)
2486 elog(ERROR, "cache lookup failed for database %u",
2487 object->objectId);
2488 appendStringInfo(&buffer, _("database %s"), datname);
2489 break;
2492 case OCLASS_TBLSPACE:
2494 char *tblspace;
2496 tblspace = get_tablespace_name(object->objectId);
2497 if (!tblspace)
2498 elog(ERROR, "cache lookup failed for tablespace %u",
2499 object->objectId);
2500 appendStringInfo(&buffer, _("tablespace %s"), tblspace);
2501 break;
2504 default:
2505 appendStringInfo(&buffer, "unrecognized object %u %u %d",
2506 object->classId,
2507 object->objectId,
2508 object->objectSubId);
2509 break;
2512 return buffer.data;
2516 * subroutine for getObjectDescription: describe a relation
2518 static void
2519 getRelationDescription(StringInfo buffer, Oid relid)
2521 HeapTuple relTup;
2522 Form_pg_class relForm;
2523 char *nspname;
2524 char *relname;
2526 relTup = SearchSysCache(RELOID,
2527 ObjectIdGetDatum(relid),
2528 0, 0, 0);
2529 if (!HeapTupleIsValid(relTup))
2530 elog(ERROR, "cache lookup failed for relation %u", relid);
2531 relForm = (Form_pg_class) GETSTRUCT(relTup);
2533 /* Qualify the name if not visible in search path */
2534 if (RelationIsVisible(relid))
2535 nspname = NULL;
2536 else
2537 nspname = get_namespace_name(relForm->relnamespace);
2539 relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
2541 switch (relForm->relkind)
2543 case RELKIND_RELATION:
2544 appendStringInfo(buffer, _("table %s"),
2545 relname);
2546 break;
2547 case RELKIND_INDEX:
2548 appendStringInfo(buffer, _("index %s"),
2549 relname);
2550 break;
2551 case RELKIND_SEQUENCE:
2552 appendStringInfo(buffer, _("sequence %s"),
2553 relname);
2554 break;
2555 case RELKIND_UNCATALOGED:
2556 appendStringInfo(buffer, _("uncataloged table %s"),
2557 relname);
2558 break;
2559 case RELKIND_TOASTVALUE:
2560 appendStringInfo(buffer, _("toast table %s"),
2561 relname);
2562 break;
2563 case RELKIND_VIEW:
2564 appendStringInfo(buffer, _("view %s"),
2565 relname);
2566 break;
2567 case RELKIND_COMPOSITE_TYPE:
2568 appendStringInfo(buffer, _("composite type %s"),
2569 relname);
2570 break;
2571 default:
2572 /* shouldn't get here */
2573 appendStringInfo(buffer, _("relation %s"),
2574 relname);
2575 break;
2578 ReleaseSysCache(relTup);
2582 * subroutine for getObjectDescription: describe an operator family
2584 static void
2585 getOpFamilyDescription(StringInfo buffer, Oid opfid)
2587 HeapTuple opfTup;
2588 Form_pg_opfamily opfForm;
2589 HeapTuple amTup;
2590 Form_pg_am amForm;
2591 char *nspname;
2593 opfTup = SearchSysCache(OPFAMILYOID,
2594 ObjectIdGetDatum(opfid),
2595 0, 0, 0);
2596 if (!HeapTupleIsValid(opfTup))
2597 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
2598 opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
2600 amTup = SearchSysCache(AMOID,
2601 ObjectIdGetDatum(opfForm->opfmethod),
2602 0, 0, 0);
2603 if (!HeapTupleIsValid(amTup))
2604 elog(ERROR, "cache lookup failed for access method %u",
2605 opfForm->opfmethod);
2606 amForm = (Form_pg_am) GETSTRUCT(amTup);
2608 /* Qualify the name if not visible in search path */
2609 if (OpfamilyIsVisible(opfid))
2610 nspname = NULL;
2611 else
2612 nspname = get_namespace_name(opfForm->opfnamespace);
2614 appendStringInfo(buffer, _("operator family %s for access method %s"),
2615 quote_qualified_identifier(nspname,
2616 NameStr(opfForm->opfname)),
2617 NameStr(amForm->amname));
2619 ReleaseSysCache(amTup);
2620 ReleaseSysCache(opfTup);