1 /*-------------------------------------------------------------------------
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
11 * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.71 2008/03/27 03:57:33 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "access/xact.h"
20 #include "catalog/dependency.h"
21 #include "catalog/heap.h"
22 #include "catalog/index.h"
23 #include "catalog/indexing.h"
24 #include "catalog/namespace.h"
25 #include "catalog/pg_amop.h"
26 #include "catalog/pg_amproc.h"
27 #include "catalog/pg_attrdef.h"
28 #include "catalog/pg_authid.h"
29 #include "catalog/pg_cast.h"
30 #include "catalog/pg_constraint.h"
31 #include "catalog/pg_conversion.h"
32 #include "catalog/pg_conversion_fn.h"
33 #include "catalog/pg_database.h"
34 #include "catalog/pg_depend.h"
35 #include "catalog/pg_language.h"
36 #include "catalog/pg_namespace.h"
37 #include "catalog/pg_opclass.h"
38 #include "catalog/pg_operator.h"
39 #include "catalog/pg_opfamily.h"
40 #include "catalog/pg_proc.h"
41 #include "catalog/pg_rewrite.h"
42 #include "catalog/pg_tablespace.h"
43 #include "catalog/pg_trigger.h"
44 #include "catalog/pg_ts_config.h"
45 #include "catalog/pg_ts_dict.h"
46 #include "catalog/pg_ts_parser.h"
47 #include "catalog/pg_ts_template.h"
48 #include "catalog/pg_type.h"
49 #include "commands/comment.h"
50 #include "commands/dbcommands.h"
51 #include "commands/defrem.h"
52 #include "commands/proclang.h"
53 #include "commands/schemacmds.h"
54 #include "commands/tablespace.h"
55 #include "commands/trigger.h"
56 #include "commands/typecmds.h"
57 #include "miscadmin.h"
58 #include "optimizer/clauses.h"
59 #include "parser/parsetree.h"
60 #include "rewrite/rewriteRemove.h"
61 #include "utils/builtins.h"
62 #include "utils/fmgroids.h"
63 #include "utils/lsyscache.h"
64 #include "utils/syscache.h"
65 #include "utils/tqual.h"
68 /* expansible list of ObjectAddresses */
69 struct ObjectAddresses
71 ObjectAddress *refs; /* => palloc'd array */
72 int numrefs; /* current number of references */
73 int maxrefs; /* current size of palloc'd array */
76 /* typedef ObjectAddresses appears in dependency.h */
78 /* for find_expr_references_walker */
81 ObjectAddresses *addrs; /* addresses being accumulated */
82 List *rtables; /* list of rangetables to resolve Vars */
83 } find_expr_references_context;
86 * This constant table maps ObjectClasses to the corresponding catalog OIDs.
87 * See also getObjectClass().
89 static const Oid object_classes[MAX_OCLASS] = {
90 RelationRelationId, /* OCLASS_CLASS */
91 ProcedureRelationId, /* OCLASS_PROC */
92 TypeRelationId, /* OCLASS_TYPE */
93 CastRelationId, /* OCLASS_CAST */
94 ConstraintRelationId, /* OCLASS_CONSTRAINT */
95 ConversionRelationId, /* OCLASS_CONVERSION */
96 AttrDefaultRelationId, /* OCLASS_DEFAULT */
97 LanguageRelationId, /* OCLASS_LANGUAGE */
98 OperatorRelationId, /* OCLASS_OPERATOR */
99 OperatorClassRelationId, /* OCLASS_OPCLASS */
100 OperatorFamilyRelationId, /* OCLASS_OPFAMILY */
101 AccessMethodOperatorRelationId, /* OCLASS_AMOP */
102 AccessMethodProcedureRelationId, /* OCLASS_AMPROC */
103 RewriteRelationId, /* OCLASS_REWRITE */
104 TriggerRelationId, /* OCLASS_TRIGGER */
105 NamespaceRelationId, /* OCLASS_SCHEMA */
106 TSParserRelationId, /* OCLASS_TSPARSER */
107 TSDictionaryRelationId, /* OCLASS_TSDICT */
108 TSTemplateRelationId, /* OCLASS_TSTEMPLATE */
109 TSConfigRelationId, /* OCLASS_TSCONFIG */
110 AuthIdRelationId, /* OCLASS_ROLE */
111 DatabaseRelationId, /* OCLASS_DATABASE */
112 TableSpaceRelationId /* OCLASS_TBLSPACE */
116 static void performDeletionWithList(const ObjectAddress *object,
117 ObjectAddresses *oktodelete,
118 DropBehavior behavior,
119 ObjectAddresses *alreadyDeleted);
120 static void findAutoDeletableObjects(const ObjectAddress *object,
121 ObjectAddresses *oktodelete,
122 Relation depRel, bool addself);
123 static bool recursiveDeletion(const ObjectAddress *object,
124 DropBehavior behavior,
126 const ObjectAddress *callingObject,
127 ObjectAddresses *oktodelete,
129 ObjectAddresses *alreadyDeleted);
130 static bool deleteDependentObjects(const ObjectAddress *object,
131 const char *objDescription,
132 DropBehavior behavior,
134 ObjectAddresses *oktodelete,
136 static void doDeletion(const ObjectAddress *object);
137 static bool find_expr_references_walker(Node *node,
138 find_expr_references_context *context);
139 static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
140 static int object_address_comparator(const void *a, const void *b);
141 static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
142 ObjectAddresses *addrs);
143 static void getRelationDescription(StringInfo buffer, Oid relid);
144 static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
148 * performDeletion: attempt to drop the specified object. If CASCADE
149 * behavior is specified, also drop any dependent objects (recursively).
150 * If RESTRICT behavior is specified, error out if there are any dependent
151 * objects, except for those that should be implicitly dropped anyway
152 * according to the dependency type.
154 * This is the outer control routine for all forms of DROP that drop objects
155 * that can participate in dependencies.
158 performDeletion(const ObjectAddress *object,
159 DropBehavior behavior)
161 char *objDescription;
163 ObjectAddresses *oktodelete;
166 * Get object description for possible use in failure message. Must do
167 * this before deleting it ...
169 objDescription = getObjectDescription(object);
172 * We save some cycles by opening pg_depend just once and passing the
173 * Relation pointer down to all the recursive deletion steps.
175 depRel = heap_open(DependRelationId, RowExclusiveLock);
178 * Construct a list of objects that are reachable by AUTO or INTERNAL
179 * dependencies from the target object. These should be deleted silently,
180 * even if the actual deletion pass first reaches one of them via a
181 * non-auto dependency.
183 oktodelete = new_object_addresses();
185 findAutoDeletableObjects(object, oktodelete, depRel, true);
187 if (!recursiveDeletion(object, behavior, NOTICE,
188 NULL, oktodelete, depRel, NULL))
190 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
191 errmsg("cannot drop %s because other objects depend on it",
193 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
195 free_object_addresses(oktodelete);
197 heap_close(depRel, RowExclusiveLock);
199 pfree(objDescription);
204 * performDeletionWithList: As above, but the oktodelete list may have already
205 * filled with some objects. Also, the deleted objects are saved in the
206 * alreadyDeleted list.
208 * XXX performDeletion could be refactored to be a thin wrapper around this
212 performDeletionWithList(const ObjectAddress *object,
213 ObjectAddresses *oktodelete,
214 DropBehavior behavior,
215 ObjectAddresses *alreadyDeleted)
217 char *objDescription;
221 * Get object description for possible use in failure message. Must do
222 * this before deleting it ...
224 objDescription = getObjectDescription(object);
227 * We save some cycles by opening pg_depend just once and passing the
228 * Relation pointer down to all the recursive deletion steps.
230 depRel = heap_open(DependRelationId, RowExclusiveLock);
233 * Construct a list of objects that are reachable by AUTO or INTERNAL
234 * dependencies from the target object. These should be deleted silently,
235 * even if the actual deletion pass first reaches one of them via a
236 * non-auto dependency.
238 findAutoDeletableObjects(object, oktodelete, depRel, true);
240 if (!recursiveDeletion(object, behavior, NOTICE,
241 NULL, oktodelete, depRel, alreadyDeleted))
243 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
244 errmsg("cannot drop %s because other objects depend on it",
246 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
248 heap_close(depRel, RowExclusiveLock);
250 pfree(objDescription);
254 * performMultipleDeletion: Similar to performDeletion, but act on multiple
257 * The main difference from issuing multiple performDeletion calls is that the
258 * list of objects that would be implicitly dropped, for each object to be
259 * dropped, is the union of the implicit-object list for all objects. This
260 * makes each check be more relaxed.
263 performMultipleDeletions(const ObjectAddresses *objects,
264 DropBehavior behavior)
266 ObjectAddresses *implicit;
267 ObjectAddresses *alreadyDeleted;
271 implicit = new_object_addresses();
272 alreadyDeleted = new_object_addresses();
274 depRel = heap_open(DependRelationId, RowExclusiveLock);
277 * Get the list of all objects that would be deleted after deleting the
278 * whole "objects" list. We do this by creating a list of all implicit
279 * (INTERNAL and AUTO) dependencies for each object we collected above.
280 * Note that we must exclude the objects themselves from this list!
282 for (i = 0; i < objects->numrefs; i++)
284 ObjectAddress obj = objects->refs[i];
287 * If it's in the implicit list, we don't need to delete it explicitly
288 * nor follow the dependencies, because that was already done in a
289 * previous iteration.
291 if (object_address_present(&obj, implicit))
295 * Add the objects dependent on this one to the global list of
298 findAutoDeletableObjects(&obj, implicit, depRel, false);
301 /* Do the deletion. */
302 for (i = 0; i < objects->numrefs; i++)
304 ObjectAddress obj = objects->refs[i];
307 * Skip this object if it was already deleted in a previous iteration.
309 if (object_address_present(&obj, alreadyDeleted))
313 * Skip this object if it's also present in the list of implicit
314 * objects --- it will be deleted later.
316 if (object_address_present(&obj, implicit))
320 performDeletionWithList(&obj, implicit, behavior, alreadyDeleted);
323 heap_close(depRel, RowExclusiveLock);
325 free_object_addresses(implicit);
326 free_object_addresses(alreadyDeleted);
330 * deleteWhatDependsOn: attempt to drop everything that depends on the
331 * specified object, though not the object itself. Behavior is always
334 * This is currently used only to clean out the contents of a schema
335 * (namespace): the passed object is a namespace. We normally want this
336 * to be done silently, so there's an option to suppress NOTICE messages.
339 deleteWhatDependsOn(const ObjectAddress *object,
342 char *objDescription;
344 ObjectAddresses *oktodelete;
347 * Get object description for possible use in failure messages
349 objDescription = getObjectDescription(object);
352 * We save some cycles by opening pg_depend just once and passing the
353 * Relation pointer down to all the recursive deletion steps.
355 depRel = heap_open(DependRelationId, RowExclusiveLock);
358 * Construct a list of objects that are reachable by AUTO or INTERNAL
359 * dependencies from the target object. These should be deleted silently,
360 * even if the actual deletion pass first reaches one of them via a
361 * non-auto dependency.
363 oktodelete = new_object_addresses();
365 findAutoDeletableObjects(object, oktodelete, depRel, true);
368 * Now invoke only step 2 of recursiveDeletion: just recurse to the stuff
369 * dependent on the given object.
371 if (!deleteDependentObjects(object, objDescription,
373 showNotices ? NOTICE : DEBUG2,
376 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
377 errmsg("failed to drop all objects depending on %s",
381 * We do not need CommandCounterIncrement here, since if step 2 did
382 * anything then each recursive call will have ended with one.
385 free_object_addresses(oktodelete);
387 heap_close(depRel, RowExclusiveLock);
389 pfree(objDescription);
394 * findAutoDeletableObjects: find all objects that are reachable by AUTO or
395 * INTERNAL dependency paths from the given object. Add them all to the
396 * oktodelete list. If addself is true, the originally given object will also
397 * be added to the list.
399 * depRel is the already-open pg_depend relation.
402 findAutoDeletableObjects(const ObjectAddress *object,
403 ObjectAddresses *oktodelete,
404 Relation depRel, bool addself)
410 ObjectAddress otherObject;
413 * If this object is already in oktodelete, then we already visited it;
414 * don't do so again (this prevents infinite recursion if there's a loop
415 * in pg_depend). Otherwise, add it.
417 if (object_address_present(object, oktodelete))
420 add_exact_object_address(object, oktodelete);
423 * Scan pg_depend records that link to this object, showing the things
424 * that depend on it. For each one that is AUTO or INTERNAL, visit the
425 * referencing object.
427 * When dropping a whole object (subId = 0), find pg_depend records for
428 * its sub-objects too.
431 Anum_pg_depend_refclassid,
432 BTEqualStrategyNumber, F_OIDEQ,
433 ObjectIdGetDatum(object->classId));
435 Anum_pg_depend_refobjid,
436 BTEqualStrategyNumber, F_OIDEQ,
437 ObjectIdGetDatum(object->objectId));
438 if (object->objectSubId != 0)
441 Anum_pg_depend_refobjsubid,
442 BTEqualStrategyNumber, F_INT4EQ,
443 Int32GetDatum(object->objectSubId));
449 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
450 SnapshotNow, nkeys, key);
452 while (HeapTupleIsValid(tup = systable_getnext(scan)))
454 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
456 switch (foundDep->deptype)
458 case DEPENDENCY_NORMAL:
461 case DEPENDENCY_AUTO:
462 case DEPENDENCY_INTERNAL:
464 otherObject.classId = foundDep->classid;
465 otherObject.objectId = foundDep->objid;
466 otherObject.objectSubId = foundDep->objsubid;
467 findAutoDeletableObjects(&otherObject, oktodelete, depRel, true);
472 * For a PIN dependency we just ereport immediately; there
473 * won't be any others to examine, and we aren't ever going to
474 * let the user delete it.
477 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
478 errmsg("cannot drop %s because it is required by the database system",
479 getObjectDescription(object))));
482 elog(ERROR, "unrecognized dependency type '%c' for %s",
483 foundDep->deptype, getObjectDescription(object));
488 systable_endscan(scan);
493 * recursiveDeletion: delete a single object for performDeletion, plus
494 * (recursively) anything that depends on it.
496 * Returns TRUE if successful, FALSE if not.
498 * callingObject is NULL at the outer level, else identifies the object that
499 * we recursed from (the reference object that someone else needs to delete).
501 * oktodelete is a list of objects verified deletable (ie, reachable by one
502 * or more AUTO or INTERNAL dependencies from the original target).
504 * depRel is the already-open pg_depend relation.
507 * In RESTRICT mode, we perform all the deletions anyway, but ereport a message
508 * and return FALSE if we find a restriction violation. performDeletion
509 * will then abort the transaction to nullify the deletions. We have to
510 * do it this way to (a) report all the direct and indirect dependencies
511 * while (b) not going into infinite recursion if there's a cycle.
513 * This is even more complex than one could wish, because it is possible for
514 * the same pair of objects to be related by both NORMAL and AUTO/INTERNAL
515 * dependencies. Also, we might have a situation where we've been asked to
516 * delete object A, and objects B and C both have AUTO dependencies on A,
517 * but B also has a NORMAL dependency on C. (Since any of these paths might
518 * be indirect, we can't prevent these scenarios, but must cope instead.)
519 * If we visit C before B then we would mistakenly decide that the B->C link
520 * should prevent the restricted drop from occurring. To handle this, we make
521 * a pre-scan to find all the objects that are auto-deletable from A. If we
522 * visit C first, but B is present in the oktodelete list, then we make no
523 * complaint but recurse to delete B anyway. (Note that in general we must
524 * delete B before deleting C; the drop routine for B may try to access C.)
526 * Note: in the case where the path to B is traversed first, we will not
527 * see the NORMAL dependency when we reach C, because of the pg_depend
528 * removals done in step 1. The oktodelete list is necessary just
529 * to make the behavior independent of the order in which pg_depend
530 * entries are visited.
533 recursiveDeletion(const ObjectAddress *object,
534 DropBehavior behavior,
536 const ObjectAddress *callingObject,
537 ObjectAddresses *oktodelete,
539 ObjectAddresses *alreadyDeleted)
542 char *objDescription;
547 ObjectAddress otherObject;
548 ObjectAddress owningObject;
549 bool amOwned = false;
552 * Get object description for possible use in messages. Must do this
553 * before deleting it ...
555 objDescription = getObjectDescription(object);
558 * Step 1: find and remove pg_depend records that link from this object to
559 * others. We have to do this anyway, and doing it first ensures that we
560 * avoid infinite recursion in the case of cycles. Also, some dependency
561 * types require extra processing here.
563 * When dropping a whole object (subId = 0), remove all pg_depend records
564 * for its sub-objects too.
567 Anum_pg_depend_classid,
568 BTEqualStrategyNumber, F_OIDEQ,
569 ObjectIdGetDatum(object->classId));
571 Anum_pg_depend_objid,
572 BTEqualStrategyNumber, F_OIDEQ,
573 ObjectIdGetDatum(object->objectId));
574 if (object->objectSubId != 0)
577 Anum_pg_depend_objsubid,
578 BTEqualStrategyNumber, F_INT4EQ,
579 Int32GetDatum(object->objectSubId));
585 scan = systable_beginscan(depRel, DependDependerIndexId, true,
586 SnapshotNow, nkeys, key);
588 while (HeapTupleIsValid(tup = systable_getnext(scan)))
590 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
592 otherObject.classId = foundDep->refclassid;
593 otherObject.objectId = foundDep->refobjid;
594 otherObject.objectSubId = foundDep->refobjsubid;
596 switch (foundDep->deptype)
598 case DEPENDENCY_NORMAL:
599 case DEPENDENCY_AUTO:
602 case DEPENDENCY_INTERNAL:
605 * This object is part of the internal implementation of
606 * another object. We have three cases:
608 * 1. At the outermost recursion level, disallow the DROP. (We
609 * just ereport here, rather than proceeding, since no other
610 * dependencies are likely to be interesting.)
612 if (callingObject == NULL)
614 char *otherObjDesc = getObjectDescription(&otherObject);
617 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
618 errmsg("cannot drop %s because %s requires it",
619 objDescription, otherObjDesc),
620 errhint("You can drop %s instead.",
625 * 2. When recursing from the other end of this dependency,
626 * it's okay to continue with the deletion. This holds when
627 * recursing from a whole object that includes the nominal
628 * other end as a component, too.
630 if (callingObject->classId == otherObject.classId &&
631 callingObject->objectId == otherObject.objectId &&
632 (callingObject->objectSubId == otherObject.objectSubId ||
633 callingObject->objectSubId == 0))
637 * 3. When recursing from anyplace else, transform this
638 * deletion request into a delete of the other object. (This
639 * will be an error condition iff RESTRICT mode.) In this case
640 * we finish deleting my dependencies except for the INTERNAL
641 * link, which will be needed to cause the owning object to
642 * recurse back to me.
644 if (amOwned) /* shouldn't happen */
645 elog(ERROR, "multiple INTERNAL dependencies for %s",
647 owningObject = otherObject;
649 /* "continue" bypasses the simple_heap_delete call below */
654 * Should not happen; PIN dependencies should have zeroes in
655 * the depender fields...
657 elog(ERROR, "incorrect use of PIN dependency with %s",
661 elog(ERROR, "unrecognized dependency type '%c' for %s",
662 foundDep->deptype, objDescription);
666 /* delete the pg_depend tuple */
667 simple_heap_delete(depRel, &tup->t_self);
670 systable_endscan(scan);
673 * CommandCounterIncrement here to ensure that preceding changes are all
674 * visible; in particular, that the above deletions of pg_depend entries
675 * are visible. That prevents infinite recursion in case of a dependency
676 * loop (which is perfectly legal).
678 CommandCounterIncrement();
681 * If we found we are owned by another object, ask it to delete itself
682 * instead of proceeding. Complain if RESTRICT mode, unless the other
683 * object is in oktodelete.
687 if (object_address_present(&owningObject, oktodelete))
689 (errmsg("drop auto-cascades to %s",
690 getObjectDescription(&owningObject))));
691 else if (behavior == DROP_RESTRICT)
694 (errmsg("%s depends on %s",
695 getObjectDescription(&owningObject),
701 (errmsg("drop cascades to %s",
702 getObjectDescription(&owningObject))));
704 if (!recursiveDeletion(&owningObject, behavior, msglevel,
705 object, oktodelete, depRel, alreadyDeleted))
708 pfree(objDescription);
714 * Step 2: scan pg_depend records that link to this object, showing the
715 * things that depend on it. Recursively delete those things. Note it's
716 * important to delete the dependent objects before the referenced one,
717 * since the deletion routines might do things like try to update the
718 * pg_class record when deleting a check constraint.
720 if (!deleteDependentObjects(object, objDescription,
726 * We do not need CommandCounterIncrement here, since if step 2 did
727 * anything then each recursive call will have ended with one.
731 * Step 3: delete the object itself, and save it to the list of deleted
732 * objects if appropiate.
735 if (alreadyDeleted != NULL)
737 if (!object_address_present(object, alreadyDeleted))
738 add_exact_object_address(object, alreadyDeleted);
742 * Delete any comments associated with this object. (This is a convenient
743 * place to do it instead of having every object type know to do it.)
745 DeleteComments(object->objectId, object->classId, object->objectSubId);
748 * Delete shared dependency references related to this object. Sub-objects
749 * (columns) don't have dependencies on global objects, so skip them.
751 if (object->objectSubId == 0)
752 deleteSharedDependencyRecordsFor(object->classId, object->objectId);
755 * CommandCounterIncrement here to ensure that preceding changes are all
758 CommandCounterIncrement();
763 pfree(objDescription);
770 * deleteDependentObjects - find and delete objects that depend on 'object'
772 * Scan pg_depend records that link to the given object, showing
773 * the things that depend on it. Recursively delete those things. (We
774 * don't delete the pg_depend records here, as the recursive call will
775 * do that.) Note it's important to delete the dependent objects
776 * before the referenced one, since the deletion routines might do
777 * things like try to update the pg_class record when deleting a check
780 * When dropping a whole object (subId = 0), find pg_depend records for
781 * its sub-objects too.
783 * object: the object to find dependencies on
784 * objDescription: description of object (only used for error messages)
785 * behavior: desired drop behavior
786 * oktodelete: stuff that's AUTO-deletable
787 * depRel: already opened pg_depend relation
789 * Returns TRUE if all is well, false if any problem found.
791 * NOTE: because we are using SnapshotNow, if a recursive call deletes
792 * any pg_depend tuples that our scan hasn't yet visited, we will not
793 * see them as good when we do visit them. This is essential for
794 * correct behavior if there are multiple dependency paths between two
795 * objects --- else we might try to delete an already-deleted object.
798 deleteDependentObjects(const ObjectAddress *object,
799 const char *objDescription,
800 DropBehavior behavior,
802 ObjectAddresses *oktodelete,
810 ObjectAddress otherObject;
813 Anum_pg_depend_refclassid,
814 BTEqualStrategyNumber, F_OIDEQ,
815 ObjectIdGetDatum(object->classId));
817 Anum_pg_depend_refobjid,
818 BTEqualStrategyNumber, F_OIDEQ,
819 ObjectIdGetDatum(object->objectId));
820 if (object->objectSubId != 0)
823 Anum_pg_depend_refobjsubid,
824 BTEqualStrategyNumber, F_INT4EQ,
825 Int32GetDatum(object->objectSubId));
831 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
832 SnapshotNow, nkeys, key);
834 while (HeapTupleIsValid(tup = systable_getnext(scan)))
836 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
838 otherObject.classId = foundDep->classid;
839 otherObject.objectId = foundDep->objid;
840 otherObject.objectSubId = foundDep->objsubid;
842 switch (foundDep->deptype)
844 case DEPENDENCY_NORMAL:
847 * Perhaps there was another dependency path that would have
848 * allowed silent deletion of the otherObject, had we only
849 * taken that path first. In that case, act like this link is
852 if (object_address_present(&otherObject, oktodelete))
854 (errmsg("drop auto-cascades to %s",
855 getObjectDescription(&otherObject))));
856 else if (behavior == DROP_RESTRICT)
859 (errmsg("%s depends on %s",
860 getObjectDescription(&otherObject),
866 (errmsg("drop cascades to %s",
867 getObjectDescription(&otherObject))));
869 if (!recursiveDeletion(&otherObject, behavior, msglevel,
870 object, oktodelete, depRel, NULL))
873 case DEPENDENCY_AUTO:
874 case DEPENDENCY_INTERNAL:
877 * We propagate the DROP without complaint even in the
878 * RESTRICT case. (However, normal dependencies on the
879 * component object could still cause failure.)
882 (errmsg("drop auto-cascades to %s",
883 getObjectDescription(&otherObject))));
885 if (!recursiveDeletion(&otherObject, behavior, msglevel,
886 object, oktodelete, depRel, NULL))
892 * For a PIN dependency we just ereport immediately; there
893 * won't be any others to report.
896 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
897 errmsg("cannot drop %s because it is required by the database system",
901 elog(ERROR, "unrecognized dependency type '%c' for %s",
902 foundDep->deptype, objDescription);
907 systable_endscan(scan);
914 * doDeletion: actually delete a single object
917 doDeletion(const ObjectAddress *object)
919 switch (getObjectClass(object))
923 char relKind = get_rel_relkind(object->objectId);
925 if (relKind == RELKIND_INDEX)
927 Assert(object->objectSubId == 0);
928 index_drop(object->objectId);
932 if (object->objectSubId != 0)
933 RemoveAttributeById(object->objectId,
934 object->objectSubId);
936 heap_drop_with_catalog(object->objectId);
942 RemoveFunctionById(object->objectId);
946 RemoveTypeById(object->objectId);
950 DropCastById(object->objectId);
953 case OCLASS_CONSTRAINT:
954 RemoveConstraintById(object->objectId);
957 case OCLASS_CONVERSION:
958 RemoveConversionById(object->objectId);
962 RemoveAttrDefaultById(object->objectId);
965 case OCLASS_LANGUAGE:
966 DropProceduralLanguageById(object->objectId);
969 case OCLASS_OPERATOR:
970 RemoveOperatorById(object->objectId);
974 RemoveOpClassById(object->objectId);
977 case OCLASS_OPFAMILY:
978 RemoveOpFamilyById(object->objectId);
982 RemoveAmOpEntryById(object->objectId);
986 RemoveAmProcEntryById(object->objectId);
990 RemoveRewriteRuleById(object->objectId);
994 RemoveTriggerById(object->objectId);
998 RemoveSchemaById(object->objectId);
1001 case OCLASS_TSPARSER:
1002 RemoveTSParserById(object->objectId);
1006 RemoveTSDictionaryById(object->objectId);
1009 case OCLASS_TSTEMPLATE:
1010 RemoveTSTemplateById(object->objectId);
1013 case OCLASS_TSCONFIG:
1014 RemoveTSConfigurationById(object->objectId);
1017 /* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
1020 elog(ERROR, "unrecognized object class: %u",
1026 * recordDependencyOnExpr - find expression dependencies
1028 * This is used to find the dependencies of rules, constraint expressions,
1031 * Given an expression or query in node-tree form, find all the objects
1032 * it refers to (tables, columns, operators, functions, etc). Record
1033 * a dependency of the specified type from the given depender object
1034 * to each object mentioned in the expression.
1036 * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
1037 * It can be NIL if no such variables are expected.
1040 recordDependencyOnExpr(const ObjectAddress *depender,
1041 Node *expr, List *rtable,
1042 DependencyType behavior)
1044 find_expr_references_context context;
1046 context.addrs = new_object_addresses();
1048 /* Set up interpretation for Vars at varlevelsup = 0 */
1049 context.rtables = list_make1(rtable);
1051 /* Scan the expression tree for referenceable objects */
1052 find_expr_references_walker(expr, &context);
1054 /* Remove any duplicates */
1055 eliminate_duplicate_dependencies(context.addrs);
1057 /* And record 'em */
1058 recordMultipleDependencies(depender,
1059 context.addrs->refs, context.addrs->numrefs,
1062 free_object_addresses(context.addrs);
1066 * recordDependencyOnSingleRelExpr - find expression dependencies
1068 * As above, but only one relation is expected to be referenced (with
1069 * varno = 1 and varlevelsup = 0). Pass the relation OID instead of a
1070 * range table. An additional frammish is that dependencies on that
1071 * relation (or its component columns) will be marked with 'self_behavior',
1072 * whereas 'behavior' is used for everything else.
1075 recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
1076 Node *expr, Oid relId,
1077 DependencyType behavior,
1078 DependencyType self_behavior)
1080 find_expr_references_context context;
1083 context.addrs = new_object_addresses();
1085 /* We gin up a rather bogus rangetable list to handle Vars */
1086 MemSet(&rte, 0, sizeof(rte));
1087 rte.type = T_RangeTblEntry;
1088 rte.rtekind = RTE_RELATION;
1091 context.rtables = list_make1(list_make1(&rte));
1093 /* Scan the expression tree for referenceable objects */
1094 find_expr_references_walker(expr, &context);
1096 /* Remove any duplicates */
1097 eliminate_duplicate_dependencies(context.addrs);
1099 /* Separate self-dependencies if necessary */
1100 if (behavior != self_behavior && context.addrs->numrefs > 0)
1102 ObjectAddresses *self_addrs;
1103 ObjectAddress *outobj;
1107 self_addrs = new_object_addresses();
1109 outobj = context.addrs->refs;
1111 for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
1113 ObjectAddress *thisobj = context.addrs->refs + oldref;
1115 if (thisobj->classId == RelationRelationId &&
1116 thisobj->objectId == relId)
1118 /* Move this ref into self_addrs */
1119 add_object_address(OCLASS_CLASS, relId, thisobj->objectSubId,
1124 /* Keep it in context.addrs */
1125 outobj->classId = thisobj->classId;
1126 outobj->objectId = thisobj->objectId;
1127 outobj->objectSubId = thisobj->objectSubId;
1132 context.addrs->numrefs = outrefs;
1134 /* Record the self-dependencies */
1135 recordMultipleDependencies(depender,
1136 self_addrs->refs, self_addrs->numrefs,
1139 free_object_addresses(self_addrs);
1142 /* Record the external dependencies */
1143 recordMultipleDependencies(depender,
1144 context.addrs->refs, context.addrs->numrefs,
1147 free_object_addresses(context.addrs);
1151 * Recursively search an expression tree for object references.
1153 * Note: we avoid creating references to columns of tables that participate
1154 * in an SQL JOIN construct, but are not actually used anywhere in the query.
1155 * To do so, we do not scan the joinaliasvars list of a join RTE while
1156 * scanning the query rangetable, but instead scan each individual entry
1157 * of the alias list when we find a reference to it.
1159 * Note: in many cases we do not need to create dependencies on the datatypes
1160 * involved in an expression, because we'll have an indirect dependency via
1161 * some other object. For instance Var nodes depend on a column which depends
1162 * on the datatype, and OpExpr nodes depend on the operator which depends on
1163 * the datatype. However we do need a type dependency if there is no such
1164 * indirect dependency, as for example in Const and CoerceToDomain nodes.
1167 find_expr_references_walker(Node *node,
1168 find_expr_references_context *context)
1174 Var *var = (Var *) node;
1178 /* Find matching rtable entry, or complain if not found */
1179 if (var->varlevelsup >= list_length(context->rtables))
1180 elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
1181 rtable = (List *) list_nth(context->rtables, var->varlevelsup);
1182 if (var->varno <= 0 || var->varno > list_length(rtable))
1183 elog(ERROR, "invalid varno %d", var->varno);
1184 rte = rt_fetch(var->varno, rtable);
1187 * A whole-row Var references no specific columns, so adds no new
1190 if (var->varattno == InvalidAttrNumber)
1192 if (rte->rtekind == RTE_RELATION)
1194 /* If it's a plain relation, reference this column */
1195 add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
1198 else if (rte->rtekind == RTE_JOIN)
1200 /* Scan join output column to add references to join inputs */
1203 /* We must make the context appropriate for join's level */
1204 save_rtables = context->rtables;
1205 context->rtables = list_copy_tail(context->rtables,
1207 if (var->varattno <= 0 ||
1208 var->varattno > list_length(rte->joinaliasvars))
1209 elog(ERROR, "invalid varattno %d", var->varattno);
1210 find_expr_references_walker((Node *) list_nth(rte->joinaliasvars,
1213 list_free(context->rtables);
1214 context->rtables = save_rtables;
1218 if (IsA(node, Const))
1220 Const *con = (Const *) node;
1223 /* A constant must depend on the constant's datatype */
1224 add_object_address(OCLASS_TYPE, con->consttype, 0,
1228 * If it's a regclass or similar literal referring to an existing
1229 * object, add a reference to that object. (Currently, only the
1230 * regclass and regconfig cases have any likely use, but we may as
1231 * well handle all the OID-alias datatypes consistently.)
1233 if (!con->constisnull)
1235 switch (con->consttype)
1238 case REGPROCEDUREOID:
1239 objoid = DatumGetObjectId(con->constvalue);
1240 if (SearchSysCacheExists(PROCOID,
1241 ObjectIdGetDatum(objoid),
1243 add_object_address(OCLASS_PROC, objoid, 0,
1247 case REGOPERATOROID:
1248 objoid = DatumGetObjectId(con->constvalue);
1249 if (SearchSysCacheExists(OPEROID,
1250 ObjectIdGetDatum(objoid),
1252 add_object_address(OCLASS_OPERATOR, objoid, 0,
1256 objoid = DatumGetObjectId(con->constvalue);
1257 if (SearchSysCacheExists(RELOID,
1258 ObjectIdGetDatum(objoid),
1260 add_object_address(OCLASS_CLASS, objoid, 0,
1264 objoid = DatumGetObjectId(con->constvalue);
1265 if (SearchSysCacheExists(TYPEOID,
1266 ObjectIdGetDatum(objoid),
1268 add_object_address(OCLASS_TYPE, objoid, 0,
1272 objoid = DatumGetObjectId(con->constvalue);
1273 if (SearchSysCacheExists(TSCONFIGOID,
1274 ObjectIdGetDatum(objoid),
1276 add_object_address(OCLASS_TSCONFIG, objoid, 0,
1279 case REGDICTIONARYOID:
1280 objoid = DatumGetObjectId(con->constvalue);
1281 if (SearchSysCacheExists(TSDICTOID,
1282 ObjectIdGetDatum(objoid),
1284 add_object_address(OCLASS_TSDICT, objoid, 0,
1291 if (IsA(node, Param))
1293 Param *param = (Param *) node;
1295 /* A parameter must depend on the parameter's datatype */
1296 add_object_address(OCLASS_TYPE, param->paramtype, 0,
1299 if (IsA(node, FuncExpr))
1301 FuncExpr *funcexpr = (FuncExpr *) node;
1303 add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
1305 /* fall through to examine arguments */
1307 if (IsA(node, OpExpr))
1309 OpExpr *opexpr = (OpExpr *) node;
1311 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1313 /* fall through to examine arguments */
1315 if (IsA(node, DistinctExpr))
1317 DistinctExpr *distinctexpr = (DistinctExpr *) node;
1319 add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
1321 /* fall through to examine arguments */
1323 if (IsA(node, ScalarArrayOpExpr))
1325 ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1327 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1329 /* fall through to examine arguments */
1331 if (IsA(node, NullIfExpr))
1333 NullIfExpr *nullifexpr = (NullIfExpr *) node;
1335 add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
1337 /* fall through to examine arguments */
1339 if (IsA(node, Aggref))
1341 Aggref *aggref = (Aggref *) node;
1343 add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
1345 /* fall through to examine arguments */
1347 if (is_subplan(node))
1349 /* Extra work needed here if we ever need this case */
1350 elog(ERROR, "already-planned subqueries not supported");
1352 if (IsA(node, RelabelType))
1354 RelabelType *relab = (RelabelType *) node;
1356 /* since there is no function dependency, need to depend on type */
1357 add_object_address(OCLASS_TYPE, relab->resulttype, 0,
1360 if (IsA(node, CoerceViaIO))
1362 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1364 /* since there is no exposed function, need to depend on type */
1365 add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0,
1368 if (IsA(node, ArrayCoerceExpr))
1370 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1372 if (OidIsValid(acoerce->elemfuncid))
1373 add_object_address(OCLASS_PROC, acoerce->elemfuncid, 0,
1375 add_object_address(OCLASS_TYPE, acoerce->resulttype, 0,
1377 /* fall through to examine arguments */
1379 if (IsA(node, ConvertRowtypeExpr))
1381 ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
1383 /* since there is no function dependency, need to depend on type */
1384 add_object_address(OCLASS_TYPE, cvt->resulttype, 0,
1387 if (IsA(node, RowExpr))
1389 RowExpr *rowexpr = (RowExpr *) node;
1391 add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
1394 if (IsA(node, RowCompareExpr))
1396 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1399 foreach(l, rcexpr->opnos)
1401 add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
1404 foreach(l, rcexpr->opfamilies)
1406 add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
1409 /* fall through to examine arguments */
1411 if (IsA(node, CoerceToDomain))
1413 CoerceToDomain *cd = (CoerceToDomain *) node;
1415 add_object_address(OCLASS_TYPE, cd->resulttype, 0,
1418 if (IsA(node, Query))
1420 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1421 Query *query = (Query *) node;
1426 * Add whole-relation refs for each plain relation mentioned in the
1427 * subquery's rtable, as well as datatype refs for any datatypes used
1428 * as a RECORD function's output. (Note: query_tree_walker takes care
1429 * of recursing into RTE_FUNCTION and RTE_SUBQUERY RTEs, so no need to
1430 * do that here. But keep it from looking at join alias lists.)
1432 foreach(rtable, query->rtable)
1434 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtable);
1437 switch (rte->rtekind)
1440 add_object_address(OCLASS_CLASS, rte->relid, 0,
1444 foreach(ct, rte->funccoltypes)
1446 add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0,
1455 /* Examine substructure of query */
1456 context->rtables = lcons(query->rtable, context->rtables);
1457 result = query_tree_walker(query,
1458 find_expr_references_walker,
1460 QTW_IGNORE_JOINALIASES);
1461 context->rtables = list_delete_first(context->rtables);
1464 return expression_tree_walker(node, find_expr_references_walker,
1469 * Given an array of dependency references, eliminate any duplicates.
1472 eliminate_duplicate_dependencies(ObjectAddresses *addrs)
1474 ObjectAddress *priorobj;
1478 if (addrs->numrefs <= 1)
1479 return; /* nothing to do */
1481 /* Sort the refs so that duplicates are adjacent */
1482 qsort((void *) addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
1483 object_address_comparator);
1486 priorobj = addrs->refs;
1488 for (oldref = 1; oldref < addrs->numrefs; oldref++)
1490 ObjectAddress *thisobj = addrs->refs + oldref;
1492 if (priorobj->classId == thisobj->classId &&
1493 priorobj->objectId == thisobj->objectId)
1495 if (priorobj->objectSubId == thisobj->objectSubId)
1496 continue; /* identical, so drop thisobj */
1499 * If we have a whole-object reference and a reference to a part
1500 * of the same object, we don't need the whole-object reference
1501 * (for example, we don't need to reference both table foo and
1502 * column foo.bar). The whole-object reference will always appear
1503 * first in the sorted list.
1505 if (priorobj->objectSubId == 0)
1507 /* replace whole ref with partial */
1508 priorobj->objectSubId = thisobj->objectSubId;
1512 /* Not identical, so add thisobj to output set */
1514 priorobj->classId = thisobj->classId;
1515 priorobj->objectId = thisobj->objectId;
1516 priorobj->objectSubId = thisobj->objectSubId;
1520 addrs->numrefs = newrefs;
1524 * qsort comparator for ObjectAddress items
1527 object_address_comparator(const void *a, const void *b)
1529 const ObjectAddress *obja = (const ObjectAddress *) a;
1530 const ObjectAddress *objb = (const ObjectAddress *) b;
1532 if (obja->classId < objb->classId)
1534 if (obja->classId > objb->classId)
1536 if (obja->objectId < objb->objectId)
1538 if (obja->objectId > objb->objectId)
1542 * We sort the subId as an unsigned int so that 0 will come first. See
1543 * logic in eliminate_duplicate_dependencies.
1545 if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
1547 if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
1553 * Routines for handling an expansible array of ObjectAddress items.
1555 * new_object_addresses: create a new ObjectAddresses array.
1558 new_object_addresses(void)
1560 ObjectAddresses *addrs;
1562 addrs = palloc(sizeof(ObjectAddresses));
1565 addrs->maxrefs = 32;
1566 addrs->refs = (ObjectAddress *)
1567 palloc(addrs->maxrefs * sizeof(ObjectAddress));
1573 * Add an entry to an ObjectAddresses array.
1575 * It is convenient to specify the class by ObjectClass rather than directly
1579 add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
1580 ObjectAddresses *addrs)
1582 ObjectAddress *item;
1584 /* enlarge array if needed */
1585 if (addrs->numrefs >= addrs->maxrefs)
1587 addrs->maxrefs *= 2;
1588 addrs->refs = (ObjectAddress *)
1589 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1591 /* record this item */
1592 item = addrs->refs + addrs->numrefs;
1593 item->classId = object_classes[oclass];
1594 item->objectId = objectId;
1595 item->objectSubId = subId;
1600 * Add an entry to an ObjectAddresses array.
1602 * As above, but specify entry exactly.
1605 add_exact_object_address(const ObjectAddress *object,
1606 ObjectAddresses *addrs)
1608 ObjectAddress *item;
1610 /* enlarge array if needed */
1611 if (addrs->numrefs >= addrs->maxrefs)
1613 addrs->maxrefs *= 2;
1614 addrs->refs = (ObjectAddress *)
1615 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1617 /* record this item */
1618 item = addrs->refs + addrs->numrefs;
1624 * Test whether an object is present in an ObjectAddresses array.
1626 * We return "true" if object is a subobject of something in the array, too.
1629 object_address_present(const ObjectAddress *object,
1630 ObjectAddresses *addrs)
1634 for (i = addrs->numrefs - 1; i >= 0; i--)
1636 ObjectAddress *thisobj = addrs->refs + i;
1638 if (object->classId == thisobj->classId &&
1639 object->objectId == thisobj->objectId)
1641 if (object->objectSubId == thisobj->objectSubId ||
1642 thisobj->objectSubId == 0)
1651 * Record multiple dependencies from an ObjectAddresses array, after first
1652 * removing any duplicates.
1655 record_object_address_dependencies(const ObjectAddress *depender,
1656 ObjectAddresses *referenced,
1657 DependencyType behavior)
1659 eliminate_duplicate_dependencies(referenced);
1660 recordMultipleDependencies(depender,
1661 referenced->refs, referenced->numrefs,
1666 * Clean up when done with an ObjectAddresses array.
1669 free_object_addresses(ObjectAddresses *addrs)
1676 * Determine the class of a given object identified by objectAddress.
1678 * This function is essentially the reverse mapping for the object_classes[]
1679 * table. We implement it as a function because the OIDs aren't consecutive.
1682 getObjectClass(const ObjectAddress *object)
1684 switch (object->classId)
1686 case RelationRelationId:
1687 /* caller must check objectSubId */
1688 return OCLASS_CLASS;
1690 case ProcedureRelationId:
1691 Assert(object->objectSubId == 0);
1694 case TypeRelationId:
1695 Assert(object->objectSubId == 0);
1698 case CastRelationId:
1699 Assert(object->objectSubId == 0);
1702 case ConstraintRelationId:
1703 Assert(object->objectSubId == 0);
1704 return OCLASS_CONSTRAINT;
1706 case ConversionRelationId:
1707 Assert(object->objectSubId == 0);
1708 return OCLASS_CONVERSION;
1710 case AttrDefaultRelationId:
1711 Assert(object->objectSubId == 0);
1712 return OCLASS_DEFAULT;
1714 case LanguageRelationId:
1715 Assert(object->objectSubId == 0);
1716 return OCLASS_LANGUAGE;
1718 case OperatorRelationId:
1719 Assert(object->objectSubId == 0);
1720 return OCLASS_OPERATOR;
1722 case OperatorClassRelationId:
1723 Assert(object->objectSubId == 0);
1724 return OCLASS_OPCLASS;
1726 case OperatorFamilyRelationId:
1727 Assert(object->objectSubId == 0);
1728 return OCLASS_OPFAMILY;
1730 case AccessMethodOperatorRelationId:
1731 Assert(object->objectSubId == 0);
1734 case AccessMethodProcedureRelationId:
1735 Assert(object->objectSubId == 0);
1736 return OCLASS_AMPROC;
1738 case RewriteRelationId:
1739 Assert(object->objectSubId == 0);
1740 return OCLASS_REWRITE;
1742 case TriggerRelationId:
1743 Assert(object->objectSubId == 0);
1744 return OCLASS_TRIGGER;
1746 case NamespaceRelationId:
1747 Assert(object->objectSubId == 0);
1748 return OCLASS_SCHEMA;
1750 case TSParserRelationId:
1751 Assert(object->objectSubId == 0);
1752 return OCLASS_TSPARSER;
1754 case TSDictionaryRelationId:
1755 Assert(object->objectSubId == 0);
1756 return OCLASS_TSDICT;
1758 case TSTemplateRelationId:
1759 Assert(object->objectSubId == 0);
1760 return OCLASS_TSTEMPLATE;
1762 case TSConfigRelationId:
1763 Assert(object->objectSubId == 0);
1764 return OCLASS_TSCONFIG;
1766 case AuthIdRelationId:
1767 Assert(object->objectSubId == 0);
1770 case DatabaseRelationId:
1771 Assert(object->objectSubId == 0);
1772 return OCLASS_DATABASE;
1774 case TableSpaceRelationId:
1775 Assert(object->objectSubId == 0);
1776 return OCLASS_TBLSPACE;
1779 /* shouldn't get here */
1780 elog(ERROR, "unrecognized object class: %u", object->classId);
1781 return OCLASS_CLASS; /* keep compiler quiet */
1785 * getObjectDescription: build an object description for messages
1787 * The result is a palloc'd string.
1790 getObjectDescription(const ObjectAddress *object)
1792 StringInfoData buffer;
1794 initStringInfo(&buffer);
1796 switch (getObjectClass(object))
1799 getRelationDescription(&buffer, object->objectId);
1800 if (object->objectSubId != 0)
1801 appendStringInfo(&buffer, _(" column %s"),
1802 get_relid_attribute_name(object->objectId,
1803 object->objectSubId));
1807 appendStringInfo(&buffer, _("function %s"),
1808 format_procedure(object->objectId));
1812 appendStringInfo(&buffer, _("type %s"),
1813 format_type_be(object->objectId));
1819 ScanKeyData skey[1];
1822 Form_pg_cast castForm;
1824 castDesc = heap_open(CastRelationId, AccessShareLock);
1826 ScanKeyInit(&skey[0],
1827 ObjectIdAttributeNumber,
1828 BTEqualStrategyNumber, F_OIDEQ,
1829 ObjectIdGetDatum(object->objectId));
1831 rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
1832 SnapshotNow, 1, skey);
1834 tup = systable_getnext(rcscan);
1836 if (!HeapTupleIsValid(tup))
1837 elog(ERROR, "could not find tuple for cast %u",
1840 castForm = (Form_pg_cast) GETSTRUCT(tup);
1842 appendStringInfo(&buffer, _("cast from %s to %s"),
1843 format_type_be(castForm->castsource),
1844 format_type_be(castForm->casttarget));
1846 systable_endscan(rcscan);
1847 heap_close(castDesc, AccessShareLock);
1851 case OCLASS_CONSTRAINT:
1854 Form_pg_constraint con;
1856 conTup = SearchSysCache(CONSTROID,
1857 ObjectIdGetDatum(object->objectId),
1859 if (!HeapTupleIsValid(conTup))
1860 elog(ERROR, "cache lookup failed for constraint %u",
1862 con = (Form_pg_constraint) GETSTRUCT(conTup);
1864 if (OidIsValid(con->conrelid))
1866 appendStringInfo(&buffer, _("constraint %s on "),
1867 NameStr(con->conname));
1868 getRelationDescription(&buffer, con->conrelid);
1872 appendStringInfo(&buffer, _("constraint %s"),
1873 NameStr(con->conname));
1876 ReleaseSysCache(conTup);
1880 case OCLASS_CONVERSION:
1884 conTup = SearchSysCache(CONVOID,
1885 ObjectIdGetDatum(object->objectId),
1887 if (!HeapTupleIsValid(conTup))
1888 elog(ERROR, "cache lookup failed for conversion %u",
1890 appendStringInfo(&buffer, _("conversion %s"),
1891 NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
1892 ReleaseSysCache(conTup);
1896 case OCLASS_DEFAULT:
1898 Relation attrdefDesc;
1899 ScanKeyData skey[1];
1902 Form_pg_attrdef attrdef;
1903 ObjectAddress colobject;
1905 attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
1907 ScanKeyInit(&skey[0],
1908 ObjectIdAttributeNumber,
1909 BTEqualStrategyNumber, F_OIDEQ,
1910 ObjectIdGetDatum(object->objectId));
1912 adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
1913 true, SnapshotNow, 1, skey);
1915 tup = systable_getnext(adscan);
1917 if (!HeapTupleIsValid(tup))
1918 elog(ERROR, "could not find tuple for attrdef %u",
1921 attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
1923 colobject.classId = RelationRelationId;
1924 colobject.objectId = attrdef->adrelid;
1925 colobject.objectSubId = attrdef->adnum;
1927 appendStringInfo(&buffer, _("default for %s"),
1928 getObjectDescription(&colobject));
1930 systable_endscan(adscan);
1931 heap_close(attrdefDesc, AccessShareLock);
1935 case OCLASS_LANGUAGE:
1939 langTup = SearchSysCache(LANGOID,
1940 ObjectIdGetDatum(object->objectId),
1942 if (!HeapTupleIsValid(langTup))
1943 elog(ERROR, "cache lookup failed for language %u",
1945 appendStringInfo(&buffer, _("language %s"),
1946 NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
1947 ReleaseSysCache(langTup);
1951 case OCLASS_OPERATOR:
1952 appendStringInfo(&buffer, _("operator %s"),
1953 format_operator(object->objectId));
1956 case OCLASS_OPCLASS:
1959 Form_pg_opclass opcForm;
1964 opcTup = SearchSysCache(CLAOID,
1965 ObjectIdGetDatum(object->objectId),
1967 if (!HeapTupleIsValid(opcTup))
1968 elog(ERROR, "cache lookup failed for opclass %u",
1970 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
1972 amTup = SearchSysCache(AMOID,
1973 ObjectIdGetDatum(opcForm->opcmethod),
1975 if (!HeapTupleIsValid(amTup))
1976 elog(ERROR, "cache lookup failed for access method %u",
1977 opcForm->opcmethod);
1978 amForm = (Form_pg_am) GETSTRUCT(amTup);
1980 /* Qualify the name if not visible in search path */
1981 if (OpclassIsVisible(object->objectId))
1984 nspname = get_namespace_name(opcForm->opcnamespace);
1986 appendStringInfo(&buffer, _("operator class %s for access method %s"),
1987 quote_qualified_identifier(nspname,
1988 NameStr(opcForm->opcname)),
1989 NameStr(amForm->amname));
1991 ReleaseSysCache(amTup);
1992 ReleaseSysCache(opcTup);
1996 case OCLASS_OPFAMILY:
1997 getOpFamilyDescription(&buffer, object->objectId);
2003 ScanKeyData skey[1];
2006 Form_pg_amop amopForm;
2008 amopDesc = heap_open(AccessMethodOperatorRelationId,
2011 ScanKeyInit(&skey[0],
2012 ObjectIdAttributeNumber,
2013 BTEqualStrategyNumber, F_OIDEQ,
2014 ObjectIdGetDatum(object->objectId));
2016 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
2017 SnapshotNow, 1, skey);
2019 tup = systable_getnext(amscan);
2021 if (!HeapTupleIsValid(tup))
2022 elog(ERROR, "could not find tuple for amop entry %u",
2025 amopForm = (Form_pg_amop) GETSTRUCT(tup);
2027 appendStringInfo(&buffer, _("operator %d %s of "),
2028 amopForm->amopstrategy,
2029 format_operator(amopForm->amopopr));
2030 getOpFamilyDescription(&buffer, amopForm->amopfamily);
2032 systable_endscan(amscan);
2033 heap_close(amopDesc, AccessShareLock);
2039 Relation amprocDesc;
2040 ScanKeyData skey[1];
2043 Form_pg_amproc amprocForm;
2045 amprocDesc = heap_open(AccessMethodProcedureRelationId,
2048 ScanKeyInit(&skey[0],
2049 ObjectIdAttributeNumber,
2050 BTEqualStrategyNumber, F_OIDEQ,
2051 ObjectIdGetDatum(object->objectId));
2053 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
2054 SnapshotNow, 1, skey);
2056 tup = systable_getnext(amscan);
2058 if (!HeapTupleIsValid(tup))
2059 elog(ERROR, "could not find tuple for amproc entry %u",
2062 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
2064 appendStringInfo(&buffer, _("function %d %s of "),
2065 amprocForm->amprocnum,
2066 format_procedure(amprocForm->amproc));
2067 getOpFamilyDescription(&buffer, amprocForm->amprocfamily);
2069 systable_endscan(amscan);
2070 heap_close(amprocDesc, AccessShareLock);
2074 case OCLASS_REWRITE:
2077 ScanKeyData skey[1];
2080 Form_pg_rewrite rule;
2082 ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
2084 ScanKeyInit(&skey[0],
2085 ObjectIdAttributeNumber,
2086 BTEqualStrategyNumber, F_OIDEQ,
2087 ObjectIdGetDatum(object->objectId));
2089 rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
2090 SnapshotNow, 1, skey);
2092 tup = systable_getnext(rcscan);
2094 if (!HeapTupleIsValid(tup))
2095 elog(ERROR, "could not find tuple for rule %u",
2098 rule = (Form_pg_rewrite) GETSTRUCT(tup);
2100 appendStringInfo(&buffer, _("rule %s on "),
2101 NameStr(rule->rulename));
2102 getRelationDescription(&buffer, rule->ev_class);
2104 systable_endscan(rcscan);
2105 heap_close(ruleDesc, AccessShareLock);
2109 case OCLASS_TRIGGER:
2112 ScanKeyData skey[1];
2115 Form_pg_trigger trig;
2117 trigDesc = heap_open(TriggerRelationId, AccessShareLock);
2119 ScanKeyInit(&skey[0],
2120 ObjectIdAttributeNumber,
2121 BTEqualStrategyNumber, F_OIDEQ,
2122 ObjectIdGetDatum(object->objectId));
2124 tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
2125 SnapshotNow, 1, skey);
2127 tup = systable_getnext(tgscan);
2129 if (!HeapTupleIsValid(tup))
2130 elog(ERROR, "could not find tuple for trigger %u",
2133 trig = (Form_pg_trigger) GETSTRUCT(tup);
2135 appendStringInfo(&buffer, _("trigger %s on "),
2136 NameStr(trig->tgname));
2137 getRelationDescription(&buffer, trig->tgrelid);
2139 systable_endscan(tgscan);
2140 heap_close(trigDesc, AccessShareLock);
2148 nspname = get_namespace_name(object->objectId);
2150 elog(ERROR, "cache lookup failed for namespace %u",
2152 appendStringInfo(&buffer, _("schema %s"), nspname);
2156 case OCLASS_TSPARSER:
2160 tup = SearchSysCache(TSPARSEROID,
2161 ObjectIdGetDatum(object->objectId),
2163 if (!HeapTupleIsValid(tup))
2164 elog(ERROR, "cache lookup failed for text search parser %u",
2166 appendStringInfo(&buffer, _("text search parser %s"),
2167 NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
2168 ReleaseSysCache(tup);
2176 tup = SearchSysCache(TSDICTOID,
2177 ObjectIdGetDatum(object->objectId),
2179 if (!HeapTupleIsValid(tup))
2180 elog(ERROR, "cache lookup failed for text search dictionary %u",
2182 appendStringInfo(&buffer, _("text search dictionary %s"),
2183 NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
2184 ReleaseSysCache(tup);
2188 case OCLASS_TSTEMPLATE:
2192 tup = SearchSysCache(TSTEMPLATEOID,
2193 ObjectIdGetDatum(object->objectId),
2195 if (!HeapTupleIsValid(tup))
2196 elog(ERROR, "cache lookup failed for text search template %u",
2198 appendStringInfo(&buffer, _("text search template %s"),
2199 NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
2200 ReleaseSysCache(tup);
2204 case OCLASS_TSCONFIG:
2208 tup = SearchSysCache(TSCONFIGOID,
2209 ObjectIdGetDatum(object->objectId),
2211 if (!HeapTupleIsValid(tup))
2212 elog(ERROR, "cache lookup failed for text search configuration %u",
2214 appendStringInfo(&buffer, _("text search configuration %s"),
2215 NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
2216 ReleaseSysCache(tup);
2222 appendStringInfo(&buffer, _("role %s"),
2223 GetUserNameFromId(object->objectId));
2227 case OCLASS_DATABASE:
2231 datname = get_database_name(object->objectId);
2233 elog(ERROR, "cache lookup failed for database %u",
2235 appendStringInfo(&buffer, _("database %s"), datname);
2239 case OCLASS_TBLSPACE:
2243 tblspace = get_tablespace_name(object->objectId);
2245 elog(ERROR, "cache lookup failed for tablespace %u",
2247 appendStringInfo(&buffer, _("tablespace %s"), tblspace);
2252 appendStringInfo(&buffer, "unrecognized object %u %u %d",
2255 object->objectSubId);
2263 * subroutine for getObjectDescription: describe a relation
2266 getRelationDescription(StringInfo buffer, Oid relid)
2269 Form_pg_class relForm;
2273 relTup = SearchSysCache(RELOID,
2274 ObjectIdGetDatum(relid),
2276 if (!HeapTupleIsValid(relTup))
2277 elog(ERROR, "cache lookup failed for relation %u", relid);
2278 relForm = (Form_pg_class) GETSTRUCT(relTup);
2280 /* Qualify the name if not visible in search path */
2281 if (RelationIsVisible(relid))
2284 nspname = get_namespace_name(relForm->relnamespace);
2286 relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
2288 switch (relForm->relkind)
2290 case RELKIND_RELATION:
2291 appendStringInfo(buffer, _("table %s"),
2295 appendStringInfo(buffer, _("index %s"),
2298 case RELKIND_SEQUENCE:
2299 appendStringInfo(buffer, _("sequence %s"),
2302 case RELKIND_UNCATALOGED:
2303 appendStringInfo(buffer, _("uncataloged table %s"),
2306 case RELKIND_TOASTVALUE:
2307 appendStringInfo(buffer, _("toast table %s"),
2311 appendStringInfo(buffer, _("view %s"),
2314 case RELKIND_COMPOSITE_TYPE:
2315 appendStringInfo(buffer, _("composite type %s"),
2319 /* shouldn't get here */
2320 appendStringInfo(buffer, _("relation %s"),
2325 ReleaseSysCache(relTup);
2329 * subroutine for getObjectDescription: describe an operator family
2332 getOpFamilyDescription(StringInfo buffer, Oid opfid)
2335 Form_pg_opfamily opfForm;
2340 opfTup = SearchSysCache(OPFAMILYOID,
2341 ObjectIdGetDatum(opfid),
2343 if (!HeapTupleIsValid(opfTup))
2344 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
2345 opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
2347 amTup = SearchSysCache(AMOID,
2348 ObjectIdGetDatum(opfForm->opfmethod),
2350 if (!HeapTupleIsValid(amTup))
2351 elog(ERROR, "cache lookup failed for access method %u",
2352 opfForm->opfmethod);
2353 amForm = (Form_pg_am) GETSTRUCT(amTup);
2355 /* Qualify the name if not visible in search path */
2356 if (OpfamilyIsVisible(opfid))
2359 nspname = get_namespace_name(opfForm->opfnamespace);
2361 appendStringInfo(buffer, _("operator family %s for access method %s"),
2362 quote_qualified_identifier(nspname,
2363 NameStr(opfForm->opfname)),
2364 NameStr(amForm->amname));
2366 ReleaseSysCache(amTup);
2367 ReleaseSysCache(opfTup);