1 /*-------------------------------------------------------------------------
4 * Routines to support inter-object dependencies.
7 * Portions Copyright (c) 1996-2007, 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.62 2007/01/05 22:19:24 momjian 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_database.h"
33 #include "catalog/pg_depend.h"
34 #include "catalog/pg_language.h"
35 #include "catalog/pg_namespace.h"
36 #include "catalog/pg_opclass.h"
37 #include "catalog/pg_operator.h"
38 #include "catalog/pg_opfamily.h"
39 #include "catalog/pg_proc.h"
40 #include "catalog/pg_rewrite.h"
41 #include "catalog/pg_tablespace.h"
42 #include "catalog/pg_trigger.h"
43 #include "catalog/pg_type.h"
44 #include "commands/comment.h"
45 #include "commands/dbcommands.h"
46 #include "commands/defrem.h"
47 #include "commands/proclang.h"
48 #include "commands/schemacmds.h"
49 #include "commands/tablespace.h"
50 #include "commands/trigger.h"
51 #include "commands/typecmds.h"
52 #include "miscadmin.h"
53 #include "optimizer/clauses.h"
54 #include "parser/parsetree.h"
55 #include "rewrite/rewriteRemove.h"
56 #include "utils/builtins.h"
57 #include "utils/fmgroids.h"
58 #include "utils/lsyscache.h"
59 #include "utils/syscache.h"
62 /* expansible list of ObjectAddresses */
63 struct ObjectAddresses
65 ObjectAddress *refs; /* => palloc'd array */
66 int numrefs; /* current number of references */
67 int maxrefs; /* current size of palloc'd array */
70 /* typedef ObjectAddresses appears in dependency.h */
72 /* for find_expr_references_walker */
75 ObjectAddresses *addrs; /* addresses being accumulated */
76 List *rtables; /* list of rangetables to resolve Vars */
77 } find_expr_references_context;
80 * This constant table maps ObjectClasses to the corresponding catalog OIDs.
81 * See also getObjectClass().
83 static const Oid object_classes[MAX_OCLASS] = {
84 RelationRelationId, /* OCLASS_CLASS */
85 ProcedureRelationId, /* OCLASS_PROC */
86 TypeRelationId, /* OCLASS_TYPE */
87 CastRelationId, /* OCLASS_CAST */
88 ConstraintRelationId, /* OCLASS_CONSTRAINT */
89 ConversionRelationId, /* OCLASS_CONVERSION */
90 AttrDefaultRelationId, /* OCLASS_DEFAULT */
91 LanguageRelationId, /* OCLASS_LANGUAGE */
92 OperatorRelationId, /* OCLASS_OPERATOR */
93 OperatorClassRelationId, /* OCLASS_OPCLASS */
94 OperatorFamilyRelationId, /* OCLASS_OPFAMILY */
95 AccessMethodOperatorRelationId, /* OCLASS_AMOP */
96 AccessMethodProcedureRelationId, /* OCLASS_AMPROC */
97 RewriteRelationId, /* OCLASS_REWRITE */
98 TriggerRelationId, /* OCLASS_TRIGGER */
99 NamespaceRelationId, /* OCLASS_SCHEMA */
100 AuthIdRelationId, /* OCLASS_ROLE */
101 DatabaseRelationId, /* OCLASS_DATABASE */
102 TableSpaceRelationId /* OCLASS_TBLSPACE */
106 static void performDeletionWithList(const ObjectAddress *object,
107 ObjectAddresses *oktodelete,
108 DropBehavior behavior,
109 ObjectAddresses *alreadyDeleted);
110 static void findAutoDeletableObjects(const ObjectAddress *object,
111 ObjectAddresses *oktodelete,
112 Relation depRel, bool addself);
113 static bool recursiveDeletion(const ObjectAddress *object,
114 DropBehavior behavior,
116 const ObjectAddress *callingObject,
117 ObjectAddresses *oktodelete,
119 ObjectAddresses *alreadyDeleted);
120 static bool deleteDependentObjects(const ObjectAddress *object,
121 const char *objDescription,
122 DropBehavior behavior,
124 ObjectAddresses *oktodelete,
126 static void doDeletion(const ObjectAddress *object);
127 static bool find_expr_references_walker(Node *node,
128 find_expr_references_context *context);
129 static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
130 static int object_address_comparator(const void *a, const void *b);
131 static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
132 ObjectAddresses *addrs);
133 static void getRelationDescription(StringInfo buffer, Oid relid);
134 static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
138 * performDeletion: attempt to drop the specified object. If CASCADE
139 * behavior is specified, also drop any dependent objects (recursively).
140 * If RESTRICT behavior is specified, error out if there are any dependent
141 * objects, except for those that should be implicitly dropped anyway
142 * according to the dependency type.
144 * This is the outer control routine for all forms of DROP that drop objects
145 * that can participate in dependencies.
148 performDeletion(const ObjectAddress *object,
149 DropBehavior behavior)
151 char *objDescription;
153 ObjectAddresses *oktodelete;
156 * Get object description for possible use in failure message. Must do
157 * this before deleting it ...
159 objDescription = getObjectDescription(object);
162 * We save some cycles by opening pg_depend just once and passing the
163 * Relation pointer down to all the recursive deletion steps.
165 depRel = heap_open(DependRelationId, RowExclusiveLock);
168 * Construct a list of objects that are reachable by AUTO or INTERNAL
169 * dependencies from the target object. These should be deleted silently,
170 * even if the actual deletion pass first reaches one of them via a
171 * non-auto dependency.
173 oktodelete = new_object_addresses();
175 findAutoDeletableObjects(object, oktodelete, depRel, true);
177 if (!recursiveDeletion(object, behavior, NOTICE,
178 NULL, oktodelete, depRel, NULL))
180 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
181 errmsg("cannot drop %s because other objects depend on it",
183 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
185 free_object_addresses(oktodelete);
187 heap_close(depRel, RowExclusiveLock);
189 pfree(objDescription);
194 * performDeletionWithList: As above, but the oktodelete list may have already
195 * filled with some objects. Also, the deleted objects are saved in the
196 * alreadyDeleted list.
198 * XXX performDeletion could be refactored to be a thin wrapper around this
202 performDeletionWithList(const ObjectAddress *object,
203 ObjectAddresses *oktodelete,
204 DropBehavior behavior,
205 ObjectAddresses *alreadyDeleted)
207 char *objDescription;
211 * Get object description for possible use in failure message. Must do
212 * this before deleting it ...
214 objDescription = getObjectDescription(object);
217 * We save some cycles by opening pg_depend just once and passing the
218 * Relation pointer down to all the recursive deletion steps.
220 depRel = heap_open(DependRelationId, RowExclusiveLock);
223 * Construct a list of objects that are reachable by AUTO or INTERNAL
224 * dependencies from the target object. These should be deleted silently,
225 * even if the actual deletion pass first reaches one of them via a
226 * non-auto dependency.
228 findAutoDeletableObjects(object, oktodelete, depRel, true);
230 if (!recursiveDeletion(object, behavior, NOTICE,
231 NULL, oktodelete, depRel, alreadyDeleted))
233 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
234 errmsg("cannot drop %s because other objects depend on it",
236 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
238 heap_close(depRel, RowExclusiveLock);
240 pfree(objDescription);
244 * performMultipleDeletion: Similar to performDeletion, but act on multiple
247 * The main difference from issuing multiple performDeletion calls is that the
248 * list of objects that would be implicitly dropped, for each object to be
249 * dropped, is the union of the implicit-object list for all objects. This
250 * makes each check be more relaxed.
253 performMultipleDeletions(const ObjectAddresses *objects,
254 DropBehavior behavior)
256 ObjectAddresses *implicit;
257 ObjectAddresses *alreadyDeleted;
261 implicit = new_object_addresses();
262 alreadyDeleted = new_object_addresses();
264 depRel = heap_open(DependRelationId, RowExclusiveLock);
267 * Get the list of all objects that would be deleted after deleting the
268 * whole "objects" list. We do this by creating a list of all implicit
269 * (INTERNAL and AUTO) dependencies for each object we collected above.
270 * Note that we must exclude the objects themselves from this list!
272 for (i = 0; i < objects->numrefs; i++)
274 ObjectAddress obj = objects->refs[i];
277 * If it's in the implicit list, we don't need to delete it explicitly
278 * nor follow the dependencies, because that was already done in a
279 * previous iteration.
281 if (object_address_present(&obj, implicit))
285 * Add the objects dependent on this one to the global list of
288 findAutoDeletableObjects(&obj, implicit, depRel, false);
291 /* Do the deletion. */
292 for (i = 0; i < objects->numrefs; i++)
294 ObjectAddress obj = objects->refs[i];
297 * Skip this object if it was already deleted in a previous iteration.
299 if (object_address_present(&obj, alreadyDeleted))
303 * Skip this object if it's also present in the list of implicit
304 * objects --- it will be deleted later.
306 if (object_address_present(&obj, implicit))
310 performDeletionWithList(&obj, implicit, behavior, alreadyDeleted);
313 heap_close(depRel, RowExclusiveLock);
315 free_object_addresses(implicit);
316 free_object_addresses(alreadyDeleted);
320 * deleteWhatDependsOn: attempt to drop everything that depends on the
321 * specified object, though not the object itself. Behavior is always
324 * This is currently used only to clean out the contents of a schema
325 * (namespace): the passed object is a namespace. We normally want this
326 * to be done silently, so there's an option to suppress NOTICE messages.
329 deleteWhatDependsOn(const ObjectAddress *object,
332 char *objDescription;
334 ObjectAddresses *oktodelete;
337 * Get object description for possible use in failure messages
339 objDescription = getObjectDescription(object);
342 * We save some cycles by opening pg_depend just once and passing the
343 * Relation pointer down to all the recursive deletion steps.
345 depRel = heap_open(DependRelationId, RowExclusiveLock);
348 * Construct a list of objects that are reachable by AUTO or INTERNAL
349 * dependencies from the target object. These should be deleted silently,
350 * even if the actual deletion pass first reaches one of them via a
351 * non-auto dependency.
353 oktodelete = new_object_addresses();
355 findAutoDeletableObjects(object, oktodelete, depRel, true);
358 * Now invoke only step 2 of recursiveDeletion: just recurse to the stuff
359 * dependent on the given object.
361 if (!deleteDependentObjects(object, objDescription,
363 showNotices ? NOTICE : DEBUG2,
366 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
367 errmsg("failed to drop all objects depending on %s",
371 * We do not need CommandCounterIncrement here, since if step 2 did
372 * anything then each recursive call will have ended with one.
375 free_object_addresses(oktodelete);
377 heap_close(depRel, RowExclusiveLock);
379 pfree(objDescription);
384 * findAutoDeletableObjects: find all objects that are reachable by AUTO or
385 * INTERNAL dependency paths from the given object. Add them all to the
386 * oktodelete list. If addself is true, the originally given object will also
387 * be added to the list.
389 * depRel is the already-open pg_depend relation.
392 findAutoDeletableObjects(const ObjectAddress *object,
393 ObjectAddresses *oktodelete,
394 Relation depRel, bool addself)
400 ObjectAddress otherObject;
403 * If this object is already in oktodelete, then we already visited it;
404 * don't do so again (this prevents infinite recursion if there's a loop
405 * in pg_depend). Otherwise, add it.
407 if (object_address_present(object, oktodelete))
410 add_exact_object_address(object, oktodelete);
413 * Scan pg_depend records that link to this object, showing the things
414 * that depend on it. For each one that is AUTO or INTERNAL, visit the
415 * referencing object.
417 * When dropping a whole object (subId = 0), find pg_depend records for
418 * its sub-objects too.
421 Anum_pg_depend_refclassid,
422 BTEqualStrategyNumber, F_OIDEQ,
423 ObjectIdGetDatum(object->classId));
425 Anum_pg_depend_refobjid,
426 BTEqualStrategyNumber, F_OIDEQ,
427 ObjectIdGetDatum(object->objectId));
428 if (object->objectSubId != 0)
431 Anum_pg_depend_refobjsubid,
432 BTEqualStrategyNumber, F_INT4EQ,
433 Int32GetDatum(object->objectSubId));
439 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
440 SnapshotNow, nkeys, key);
442 while (HeapTupleIsValid(tup = systable_getnext(scan)))
444 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
446 switch (foundDep->deptype)
448 case DEPENDENCY_NORMAL:
451 case DEPENDENCY_AUTO:
452 case DEPENDENCY_INTERNAL:
454 otherObject.classId = foundDep->classid;
455 otherObject.objectId = foundDep->objid;
456 otherObject.objectSubId = foundDep->objsubid;
457 findAutoDeletableObjects(&otherObject, oktodelete, depRel, true);
462 * For a PIN dependency we just ereport immediately; there
463 * won't be any others to examine, and we aren't ever going to
464 * let the user delete it.
467 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
468 errmsg("cannot drop %s because it is required by the database system",
469 getObjectDescription(object))));
472 elog(ERROR, "unrecognized dependency type '%c' for %s",
473 foundDep->deptype, getObjectDescription(object));
478 systable_endscan(scan);
483 * recursiveDeletion: delete a single object for performDeletion, plus
484 * (recursively) anything that depends on it.
486 * Returns TRUE if successful, FALSE if not.
488 * callingObject is NULL at the outer level, else identifies the object that
489 * we recursed from (the reference object that someone else needs to delete).
491 * oktodelete is a list of objects verified deletable (ie, reachable by one
492 * or more AUTO or INTERNAL dependencies from the original target).
494 * depRel is the already-open pg_depend relation.
497 * In RESTRICT mode, we perform all the deletions anyway, but ereport a message
498 * and return FALSE if we find a restriction violation. performDeletion
499 * will then abort the transaction to nullify the deletions. We have to
500 * do it this way to (a) report all the direct and indirect dependencies
501 * while (b) not going into infinite recursion if there's a cycle.
503 * This is even more complex than one could wish, because it is possible for
504 * the same pair of objects to be related by both NORMAL and AUTO/INTERNAL
505 * dependencies. Also, we might have a situation where we've been asked to
506 * delete object A, and objects B and C both have AUTO dependencies on A,
507 * but B also has a NORMAL dependency on C. (Since any of these paths might
508 * be indirect, we can't prevent these scenarios, but must cope instead.)
509 * If we visit C before B then we would mistakenly decide that the B->C link
510 * should prevent the restricted drop from occurring. To handle this, we make
511 * a pre-scan to find all the objects that are auto-deletable from A. If we
512 * visit C first, but B is present in the oktodelete list, then we make no
513 * complaint but recurse to delete B anyway. (Note that in general we must
514 * delete B before deleting C; the drop routine for B may try to access C.)
516 * Note: in the case where the path to B is traversed first, we will not
517 * see the NORMAL dependency when we reach C, because of the pg_depend
518 * removals done in step 1. The oktodelete list is necessary just
519 * to make the behavior independent of the order in which pg_depend
520 * entries are visited.
523 recursiveDeletion(const ObjectAddress *object,
524 DropBehavior behavior,
526 const ObjectAddress *callingObject,
527 ObjectAddresses *oktodelete,
529 ObjectAddresses *alreadyDeleted)
532 char *objDescription;
537 ObjectAddress otherObject;
538 ObjectAddress owningObject;
539 bool amOwned = false;
542 * Get object description for possible use in messages. Must do this
543 * before deleting it ...
545 objDescription = getObjectDescription(object);
548 * Step 1: find and remove pg_depend records that link from this object to
549 * others. We have to do this anyway, and doing it first ensures that we
550 * avoid infinite recursion in the case of cycles. Also, some dependency
551 * types require extra processing here.
553 * When dropping a whole object (subId = 0), remove all pg_depend records
554 * for its sub-objects too.
557 Anum_pg_depend_classid,
558 BTEqualStrategyNumber, F_OIDEQ,
559 ObjectIdGetDatum(object->classId));
561 Anum_pg_depend_objid,
562 BTEqualStrategyNumber, F_OIDEQ,
563 ObjectIdGetDatum(object->objectId));
564 if (object->objectSubId != 0)
567 Anum_pg_depend_objsubid,
568 BTEqualStrategyNumber, F_INT4EQ,
569 Int32GetDatum(object->objectSubId));
575 scan = systable_beginscan(depRel, DependDependerIndexId, true,
576 SnapshotNow, nkeys, key);
578 while (HeapTupleIsValid(tup = systable_getnext(scan)))
580 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
582 otherObject.classId = foundDep->refclassid;
583 otherObject.objectId = foundDep->refobjid;
584 otherObject.objectSubId = foundDep->refobjsubid;
586 switch (foundDep->deptype)
588 case DEPENDENCY_NORMAL:
589 case DEPENDENCY_AUTO:
592 case DEPENDENCY_INTERNAL:
595 * This object is part of the internal implementation of
596 * another object. We have three cases:
598 * 1. At the outermost recursion level, disallow the DROP. (We
599 * just ereport here, rather than proceeding, since no other
600 * dependencies are likely to be interesting.)
602 if (callingObject == NULL)
604 char *otherObjDesc = getObjectDescription(&otherObject);
607 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
608 errmsg("cannot drop %s because %s requires it",
609 objDescription, otherObjDesc),
610 errhint("You may drop %s instead.",
615 * 2. When recursing from the other end of this dependency,
616 * it's okay to continue with the deletion. This holds when
617 * recursing from a whole object that includes the nominal
618 * other end as a component, too.
620 if (callingObject->classId == otherObject.classId &&
621 callingObject->objectId == otherObject.objectId &&
622 (callingObject->objectSubId == otherObject.objectSubId ||
623 callingObject->objectSubId == 0))
627 * 3. When recursing from anyplace else, transform this
628 * deletion request into a delete of the other object. (This
629 * will be an error condition iff RESTRICT mode.) In this case
630 * we finish deleting my dependencies except for the INTERNAL
631 * link, which will be needed to cause the owning object to
632 * recurse back to me.
634 if (amOwned) /* shouldn't happen */
635 elog(ERROR, "multiple INTERNAL dependencies for %s",
637 owningObject = otherObject;
639 /* "continue" bypasses the simple_heap_delete call below */
644 * Should not happen; PIN dependencies should have zeroes in
645 * the depender fields...
647 elog(ERROR, "incorrect use of PIN dependency with %s",
651 elog(ERROR, "unrecognized dependency type '%c' for %s",
652 foundDep->deptype, objDescription);
656 /* delete the pg_depend tuple */
657 simple_heap_delete(depRel, &tup->t_self);
660 systable_endscan(scan);
663 * CommandCounterIncrement here to ensure that preceding changes are all
664 * visible; in particular, that the above deletions of pg_depend entries
665 * are visible. That prevents infinite recursion in case of a dependency
666 * loop (which is perfectly legal).
668 CommandCounterIncrement();
671 * If we found we are owned by another object, ask it to delete itself
672 * instead of proceeding. Complain if RESTRICT mode, unless the other
673 * object is in oktodelete.
677 if (object_address_present(&owningObject, oktodelete))
679 (errmsg("drop auto-cascades to %s",
680 getObjectDescription(&owningObject))));
681 else if (behavior == DROP_RESTRICT)
684 (errmsg("%s depends on %s",
685 getObjectDescription(&owningObject),
691 (errmsg("drop cascades to %s",
692 getObjectDescription(&owningObject))));
694 if (!recursiveDeletion(&owningObject, behavior, msglevel,
695 object, oktodelete, depRel, alreadyDeleted))
698 pfree(objDescription);
704 * Step 2: scan pg_depend records that link to this object, showing the
705 * things that depend on it. Recursively delete those things. Note it's
706 * important to delete the dependent objects before the referenced one,
707 * since the deletion routines might do things like try to update the
708 * pg_class record when deleting a check constraint.
710 if (!deleteDependentObjects(object, objDescription,
716 * We do not need CommandCounterIncrement here, since if step 2 did
717 * anything then each recursive call will have ended with one.
721 * Step 3: delete the object itself, and save it to the list of deleted
722 * objects if appropiate.
725 if (alreadyDeleted != NULL)
727 if (!object_address_present(object, alreadyDeleted))
728 add_exact_object_address(object, alreadyDeleted);
732 * Delete any comments associated with this object. (This is a convenient
733 * place to do it instead of having every object type know to do it.)
735 DeleteComments(object->objectId, object->classId, object->objectSubId);
738 * Delete shared dependency references related to this object. Sub-objects
739 * (columns) don't have dependencies on global objects, so skip them.
741 if (object->objectSubId == 0)
742 deleteSharedDependencyRecordsFor(object->classId, object->objectId);
745 * CommandCounterIncrement here to ensure that preceding changes are all
748 CommandCounterIncrement();
753 pfree(objDescription);
760 * deleteDependentObjects - find and delete objects that depend on 'object'
762 * Scan pg_depend records that link to the given object, showing
763 * the things that depend on it. Recursively delete those things. (We
764 * don't delete the pg_depend records here, as the recursive call will
765 * do that.) Note it's important to delete the dependent objects
766 * before the referenced one, since the deletion routines might do
767 * things like try to update the pg_class record when deleting a check
770 * When dropping a whole object (subId = 0), find pg_depend records for
771 * its sub-objects too.
773 * object: the object to find dependencies on
774 * objDescription: description of object (only used for error messages)
775 * behavior: desired drop behavior
776 * oktodelete: stuff that's AUTO-deletable
777 * depRel: already opened pg_depend relation
779 * Returns TRUE if all is well, false if any problem found.
781 * NOTE: because we are using SnapshotNow, if a recursive call deletes
782 * any pg_depend tuples that our scan hasn't yet visited, we will not
783 * see them as good when we do visit them. This is essential for
784 * correct behavior if there are multiple dependency paths between two
785 * objects --- else we might try to delete an already-deleted object.
788 deleteDependentObjects(const ObjectAddress *object,
789 const char *objDescription,
790 DropBehavior behavior,
792 ObjectAddresses *oktodelete,
800 ObjectAddress otherObject;
803 Anum_pg_depend_refclassid,
804 BTEqualStrategyNumber, F_OIDEQ,
805 ObjectIdGetDatum(object->classId));
807 Anum_pg_depend_refobjid,
808 BTEqualStrategyNumber, F_OIDEQ,
809 ObjectIdGetDatum(object->objectId));
810 if (object->objectSubId != 0)
813 Anum_pg_depend_refobjsubid,
814 BTEqualStrategyNumber, F_INT4EQ,
815 Int32GetDatum(object->objectSubId));
821 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
822 SnapshotNow, nkeys, key);
824 while (HeapTupleIsValid(tup = systable_getnext(scan)))
826 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
828 otherObject.classId = foundDep->classid;
829 otherObject.objectId = foundDep->objid;
830 otherObject.objectSubId = foundDep->objsubid;
832 switch (foundDep->deptype)
834 case DEPENDENCY_NORMAL:
837 * Perhaps there was another dependency path that would have
838 * allowed silent deletion of the otherObject, had we only
839 * taken that path first. In that case, act like this link is
842 if (object_address_present(&otherObject, oktodelete))
844 (errmsg("drop auto-cascades to %s",
845 getObjectDescription(&otherObject))));
846 else if (behavior == DROP_RESTRICT)
849 (errmsg("%s depends on %s",
850 getObjectDescription(&otherObject),
856 (errmsg("drop cascades to %s",
857 getObjectDescription(&otherObject))));
859 if (!recursiveDeletion(&otherObject, behavior, msglevel,
860 object, oktodelete, depRel, NULL))
863 case DEPENDENCY_AUTO:
864 case DEPENDENCY_INTERNAL:
867 * We propagate the DROP without complaint even in the
868 * RESTRICT case. (However, normal dependencies on the
869 * component object could still cause failure.)
872 (errmsg("drop auto-cascades to %s",
873 getObjectDescription(&otherObject))));
875 if (!recursiveDeletion(&otherObject, behavior, msglevel,
876 object, oktodelete, depRel, NULL))
882 * For a PIN dependency we just ereport immediately; there
883 * won't be any others to report.
886 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
887 errmsg("cannot drop %s because it is required by the database system",
891 elog(ERROR, "unrecognized dependency type '%c' for %s",
892 foundDep->deptype, objDescription);
897 systable_endscan(scan);
904 * doDeletion: actually delete a single object
907 doDeletion(const ObjectAddress *object)
909 switch (getObjectClass(object))
913 char relKind = get_rel_relkind(object->objectId);
915 if (relKind == RELKIND_INDEX)
917 Assert(object->objectSubId == 0);
918 index_drop(object->objectId);
922 if (object->objectSubId != 0)
923 RemoveAttributeById(object->objectId,
924 object->objectSubId);
926 heap_drop_with_catalog(object->objectId);
932 RemoveFunctionById(object->objectId);
936 RemoveTypeById(object->objectId);
940 DropCastById(object->objectId);
943 case OCLASS_CONSTRAINT:
944 RemoveConstraintById(object->objectId);
947 case OCLASS_CONVERSION:
948 RemoveConversionById(object->objectId);
952 RemoveAttrDefaultById(object->objectId);
955 case OCLASS_LANGUAGE:
956 DropProceduralLanguageById(object->objectId);
959 case OCLASS_OPERATOR:
960 RemoveOperatorById(object->objectId);
964 RemoveOpClassById(object->objectId);
967 case OCLASS_OPFAMILY:
968 RemoveOpFamilyById(object->objectId);
972 RemoveAmOpEntryById(object->objectId);
976 RemoveAmProcEntryById(object->objectId);
980 RemoveRewriteRuleById(object->objectId);
984 RemoveTriggerById(object->objectId);
988 RemoveSchemaById(object->objectId);
991 /* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
994 elog(ERROR, "unrecognized object class: %u",
1000 * recordDependencyOnExpr - find expression dependencies
1002 * This is used to find the dependencies of rules, constraint expressions,
1005 * Given an expression or query in node-tree form, find all the objects
1006 * it refers to (tables, columns, operators, functions, etc). Record
1007 * a dependency of the specified type from the given depender object
1008 * to each object mentioned in the expression.
1010 * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
1011 * It can be NIL if no such variables are expected.
1014 recordDependencyOnExpr(const ObjectAddress *depender,
1015 Node *expr, List *rtable,
1016 DependencyType behavior)
1018 find_expr_references_context context;
1020 context.addrs = new_object_addresses();
1022 /* Set up interpretation for Vars at varlevelsup = 0 */
1023 context.rtables = list_make1(rtable);
1025 /* Scan the expression tree for referenceable objects */
1026 find_expr_references_walker(expr, &context);
1028 /* Remove any duplicates */
1029 eliminate_duplicate_dependencies(context.addrs);
1031 /* And record 'em */
1032 recordMultipleDependencies(depender,
1033 context.addrs->refs, context.addrs->numrefs,
1036 free_object_addresses(context.addrs);
1040 * recordDependencyOnSingleRelExpr - find expression dependencies
1042 * As above, but only one relation is expected to be referenced (with
1043 * varno = 1 and varlevelsup = 0). Pass the relation OID instead of a
1044 * range table. An additional frammish is that dependencies on that
1045 * relation (or its component columns) will be marked with 'self_behavior',
1046 * whereas 'behavior' is used for everything else.
1049 recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
1050 Node *expr, Oid relId,
1051 DependencyType behavior,
1052 DependencyType self_behavior)
1054 find_expr_references_context context;
1057 context.addrs = new_object_addresses();
1059 /* We gin up a rather bogus rangetable list to handle Vars */
1060 MemSet(&rte, 0, sizeof(rte));
1061 rte.type = T_RangeTblEntry;
1062 rte.rtekind = RTE_RELATION;
1065 context.rtables = list_make1(list_make1(&rte));
1067 /* Scan the expression tree for referenceable objects */
1068 find_expr_references_walker(expr, &context);
1070 /* Remove any duplicates */
1071 eliminate_duplicate_dependencies(context.addrs);
1073 /* Separate self-dependencies if necessary */
1074 if (behavior != self_behavior && context.addrs->numrefs > 0)
1076 ObjectAddresses *self_addrs;
1077 ObjectAddress *outobj;
1081 self_addrs = new_object_addresses();
1083 outobj = context.addrs->refs;
1085 for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
1087 ObjectAddress *thisobj = context.addrs->refs + oldref;
1089 if (thisobj->classId == RelationRelationId &&
1090 thisobj->objectId == relId)
1092 /* Move this ref into self_addrs */
1093 add_object_address(OCLASS_CLASS, relId, thisobj->objectSubId,
1098 /* Keep it in context.addrs */
1099 outobj->classId = thisobj->classId;
1100 outobj->objectId = thisobj->objectId;
1101 outobj->objectSubId = thisobj->objectSubId;
1106 context.addrs->numrefs = outrefs;
1108 /* Record the self-dependencies */
1109 recordMultipleDependencies(depender,
1110 self_addrs->refs, self_addrs->numrefs,
1113 free_object_addresses(self_addrs);
1116 /* Record the external dependencies */
1117 recordMultipleDependencies(depender,
1118 context.addrs->refs, context.addrs->numrefs,
1121 free_object_addresses(context.addrs);
1125 * Recursively search an expression tree for object references.
1127 * Note: we avoid creating references to columns of tables that participate
1128 * in an SQL JOIN construct, but are not actually used anywhere in the query.
1129 * To do so, we do not scan the joinaliasvars list of a join RTE while
1130 * scanning the query rangetable, but instead scan each individual entry
1131 * of the alias list when we find a reference to it.
1133 * Note: in many cases we do not need to create dependencies on the datatypes
1134 * involved in an expression, because we'll have an indirect dependency via
1135 * some other object. For instance Var nodes depend on a column which depends
1136 * on the datatype, and OpExpr nodes depend on the operator which depends on
1137 * the datatype. However we do need a type dependency if there is no such
1138 * indirect dependency, as for example in Const and CoerceToDomain nodes.
1141 find_expr_references_walker(Node *node,
1142 find_expr_references_context *context)
1148 Var *var = (Var *) node;
1152 /* Find matching rtable entry, or complain if not found */
1153 if (var->varlevelsup >= list_length(context->rtables))
1154 elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
1155 rtable = (List *) list_nth(context->rtables, var->varlevelsup);
1156 if (var->varno <= 0 || var->varno > list_length(rtable))
1157 elog(ERROR, "invalid varno %d", var->varno);
1158 rte = rt_fetch(var->varno, rtable);
1161 * A whole-row Var references no specific columns, so adds no new
1164 if (var->varattno == InvalidAttrNumber)
1166 if (rte->rtekind == RTE_RELATION)
1168 /* If it's a plain relation, reference this column */
1169 add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
1172 else if (rte->rtekind == RTE_JOIN)
1174 /* Scan join output column to add references to join inputs */
1177 /* We must make the context appropriate for join's level */
1178 save_rtables = context->rtables;
1179 context->rtables = list_copy_tail(context->rtables,
1181 if (var->varattno <= 0 ||
1182 var->varattno > list_length(rte->joinaliasvars))
1183 elog(ERROR, "invalid varattno %d", var->varattno);
1184 find_expr_references_walker((Node *) list_nth(rte->joinaliasvars,
1187 list_free(context->rtables);
1188 context->rtables = save_rtables;
1192 if (IsA(node, Const))
1194 Const *con = (Const *) node;
1197 /* A constant must depend on the constant's datatype */
1198 add_object_address(OCLASS_TYPE, con->consttype, 0,
1202 * If it's a regclass or similar literal referring to an existing
1203 * object, add a reference to that object. (Currently, only the
1204 * regclass case has any likely use, but we may as well handle all the
1205 * OID-alias datatypes consistently.)
1207 if (!con->constisnull)
1209 switch (con->consttype)
1212 case REGPROCEDUREOID:
1213 objoid = DatumGetObjectId(con->constvalue);
1214 if (SearchSysCacheExists(PROCOID,
1215 ObjectIdGetDatum(objoid),
1217 add_object_address(OCLASS_PROC, objoid, 0,
1221 case REGOPERATOROID:
1222 objoid = DatumGetObjectId(con->constvalue);
1223 if (SearchSysCacheExists(OPEROID,
1224 ObjectIdGetDatum(objoid),
1226 add_object_address(OCLASS_OPERATOR, objoid, 0,
1230 objoid = DatumGetObjectId(con->constvalue);
1231 if (SearchSysCacheExists(RELOID,
1232 ObjectIdGetDatum(objoid),
1234 add_object_address(OCLASS_CLASS, objoid, 0,
1238 objoid = DatumGetObjectId(con->constvalue);
1239 if (SearchSysCacheExists(TYPEOID,
1240 ObjectIdGetDatum(objoid),
1242 add_object_address(OCLASS_TYPE, objoid, 0,
1249 if (IsA(node, Param))
1251 Param *param = (Param *) node;
1253 /* A parameter must depend on the parameter's datatype */
1254 add_object_address(OCLASS_TYPE, param->paramtype, 0,
1257 if (IsA(node, FuncExpr))
1259 FuncExpr *funcexpr = (FuncExpr *) node;
1261 add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
1263 /* fall through to examine arguments */
1265 if (IsA(node, OpExpr))
1267 OpExpr *opexpr = (OpExpr *) node;
1269 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1271 /* fall through to examine arguments */
1273 if (IsA(node, DistinctExpr))
1275 DistinctExpr *distinctexpr = (DistinctExpr *) node;
1277 add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
1279 /* fall through to examine arguments */
1281 if (IsA(node, ScalarArrayOpExpr))
1283 ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1285 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1287 /* fall through to examine arguments */
1289 if (IsA(node, NullIfExpr))
1291 NullIfExpr *nullifexpr = (NullIfExpr *) node;
1293 add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
1295 /* fall through to examine arguments */
1297 if (IsA(node, Aggref))
1299 Aggref *aggref = (Aggref *) node;
1301 add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
1303 /* fall through to examine arguments */
1305 if (is_subplan(node))
1307 /* Extra work needed here if we ever need this case */
1308 elog(ERROR, "already-planned subqueries not supported");
1310 if (IsA(node, RelabelType))
1312 RelabelType *relab = (RelabelType *) node;
1314 /* since there is no function dependency, need to depend on type */
1315 add_object_address(OCLASS_TYPE, relab->resulttype, 0,
1318 if (IsA(node, ConvertRowtypeExpr))
1320 ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
1322 /* since there is no function dependency, need to depend on type */
1323 add_object_address(OCLASS_TYPE, cvt->resulttype, 0,
1326 if (IsA(node, RowExpr))
1328 RowExpr *rowexpr = (RowExpr *) node;
1330 add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
1333 if (IsA(node, RowCompareExpr))
1335 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1338 foreach(l, rcexpr->opnos)
1340 add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
1343 foreach(l, rcexpr->opfamilies)
1345 add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
1348 /* fall through to examine arguments */
1350 if (IsA(node, CoerceToDomain))
1352 CoerceToDomain *cd = (CoerceToDomain *) node;
1354 add_object_address(OCLASS_TYPE, cd->resulttype, 0,
1357 if (IsA(node, Query))
1359 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1360 Query *query = (Query *) node;
1365 * Add whole-relation refs for each plain relation mentioned in the
1366 * subquery's rtable, as well as datatype refs for any datatypes used
1367 * as a RECORD function's output. (Note: query_tree_walker takes care
1368 * of recursing into RTE_FUNCTION and RTE_SUBQUERY RTEs, so no need to
1369 * do that here. But keep it from looking at join alias lists.)
1371 foreach(rtable, query->rtable)
1373 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtable);
1376 switch (rte->rtekind)
1379 add_object_address(OCLASS_CLASS, rte->relid, 0,
1383 foreach(ct, rte->funccoltypes)
1385 add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0,
1394 /* Examine substructure of query */
1395 context->rtables = lcons(query->rtable, context->rtables);
1396 result = query_tree_walker(query,
1397 find_expr_references_walker,
1399 QTW_IGNORE_JOINALIASES);
1400 context->rtables = list_delete_first(context->rtables);
1403 return expression_tree_walker(node, find_expr_references_walker,
1408 * Given an array of dependency references, eliminate any duplicates.
1411 eliminate_duplicate_dependencies(ObjectAddresses *addrs)
1413 ObjectAddress *priorobj;
1417 if (addrs->numrefs <= 1)
1418 return; /* nothing to do */
1420 /* Sort the refs so that duplicates are adjacent */
1421 qsort((void *) addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
1422 object_address_comparator);
1425 priorobj = addrs->refs;
1427 for (oldref = 1; oldref < addrs->numrefs; oldref++)
1429 ObjectAddress *thisobj = addrs->refs + oldref;
1431 if (priorobj->classId == thisobj->classId &&
1432 priorobj->objectId == thisobj->objectId)
1434 if (priorobj->objectSubId == thisobj->objectSubId)
1435 continue; /* identical, so drop thisobj */
1438 * If we have a whole-object reference and a reference to a part
1439 * of the same object, we don't need the whole-object reference
1440 * (for example, we don't need to reference both table foo and
1441 * column foo.bar). The whole-object reference will always appear
1442 * first in the sorted list.
1444 if (priorobj->objectSubId == 0)
1446 /* replace whole ref with partial */
1447 priorobj->objectSubId = thisobj->objectSubId;
1451 /* Not identical, so add thisobj to output set */
1453 priorobj->classId = thisobj->classId;
1454 priorobj->objectId = thisobj->objectId;
1455 priorobj->objectSubId = thisobj->objectSubId;
1459 addrs->numrefs = newrefs;
1463 * qsort comparator for ObjectAddress items
1466 object_address_comparator(const void *a, const void *b)
1468 const ObjectAddress *obja = (const ObjectAddress *) a;
1469 const ObjectAddress *objb = (const ObjectAddress *) b;
1471 if (obja->classId < objb->classId)
1473 if (obja->classId > objb->classId)
1475 if (obja->objectId < objb->objectId)
1477 if (obja->objectId > objb->objectId)
1481 * We sort the subId as an unsigned int so that 0 will come first. See
1482 * logic in eliminate_duplicate_dependencies.
1484 if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
1486 if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
1492 * Routines for handling an expansible array of ObjectAddress items.
1494 * new_object_addresses: create a new ObjectAddresses array.
1497 new_object_addresses(void)
1499 ObjectAddresses *addrs;
1501 addrs = palloc(sizeof(ObjectAddresses));
1504 addrs->maxrefs = 32;
1505 addrs->refs = (ObjectAddress *)
1506 palloc(addrs->maxrefs * sizeof(ObjectAddress));
1512 * Add an entry to an ObjectAddresses array.
1514 * It is convenient to specify the class by ObjectClass rather than directly
1518 add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
1519 ObjectAddresses *addrs)
1521 ObjectAddress *item;
1523 /* enlarge array if needed */
1524 if (addrs->numrefs >= addrs->maxrefs)
1526 addrs->maxrefs *= 2;
1527 addrs->refs = (ObjectAddress *)
1528 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1530 /* record this item */
1531 item = addrs->refs + addrs->numrefs;
1532 item->classId = object_classes[oclass];
1533 item->objectId = objectId;
1534 item->objectSubId = subId;
1539 * Add an entry to an ObjectAddresses array.
1541 * As above, but specify entry exactly.
1544 add_exact_object_address(const ObjectAddress *object,
1545 ObjectAddresses *addrs)
1547 ObjectAddress *item;
1549 /* enlarge array if needed */
1550 if (addrs->numrefs >= addrs->maxrefs)
1552 addrs->maxrefs *= 2;
1553 addrs->refs = (ObjectAddress *)
1554 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1556 /* record this item */
1557 item = addrs->refs + addrs->numrefs;
1563 * Test whether an object is present in an ObjectAddresses array.
1565 * We return "true" if object is a subobject of something in the array, too.
1568 object_address_present(const ObjectAddress *object,
1569 ObjectAddresses *addrs)
1573 for (i = addrs->numrefs - 1; i >= 0; i--)
1575 ObjectAddress *thisobj = addrs->refs + i;
1577 if (object->classId == thisobj->classId &&
1578 object->objectId == thisobj->objectId)
1580 if (object->objectSubId == thisobj->objectSubId ||
1581 thisobj->objectSubId == 0)
1590 * Clean up when done with an ObjectAddresses array.
1593 free_object_addresses(ObjectAddresses *addrs)
1600 * Determine the class of a given object identified by objectAddress.
1602 * This function is essentially the reverse mapping for the object_classes[]
1603 * table. We implement it as a function because the OIDs aren't consecutive.
1606 getObjectClass(const ObjectAddress *object)
1608 switch (object->classId)
1610 case RelationRelationId:
1611 /* caller must check objectSubId */
1612 return OCLASS_CLASS;
1614 case ProcedureRelationId:
1615 Assert(object->objectSubId == 0);
1618 case TypeRelationId:
1619 Assert(object->objectSubId == 0);
1622 case CastRelationId:
1623 Assert(object->objectSubId == 0);
1626 case ConstraintRelationId:
1627 Assert(object->objectSubId == 0);
1628 return OCLASS_CONSTRAINT;
1630 case ConversionRelationId:
1631 Assert(object->objectSubId == 0);
1632 return OCLASS_CONVERSION;
1634 case AttrDefaultRelationId:
1635 Assert(object->objectSubId == 0);
1636 return OCLASS_DEFAULT;
1638 case LanguageRelationId:
1639 Assert(object->objectSubId == 0);
1640 return OCLASS_LANGUAGE;
1642 case OperatorRelationId:
1643 Assert(object->objectSubId == 0);
1644 return OCLASS_OPERATOR;
1646 case OperatorClassRelationId:
1647 Assert(object->objectSubId == 0);
1648 return OCLASS_OPCLASS;
1650 case OperatorFamilyRelationId:
1651 Assert(object->objectSubId == 0);
1652 return OCLASS_OPFAMILY;
1654 case AccessMethodOperatorRelationId:
1655 Assert(object->objectSubId == 0);
1658 case AccessMethodProcedureRelationId:
1659 Assert(object->objectSubId == 0);
1660 return OCLASS_AMPROC;
1662 case RewriteRelationId:
1663 Assert(object->objectSubId == 0);
1664 return OCLASS_REWRITE;
1666 case TriggerRelationId:
1667 Assert(object->objectSubId == 0);
1668 return OCLASS_TRIGGER;
1670 case NamespaceRelationId:
1671 Assert(object->objectSubId == 0);
1672 return OCLASS_SCHEMA;
1674 case AuthIdRelationId:
1675 Assert(object->objectSubId == 0);
1678 case DatabaseRelationId:
1679 Assert(object->objectSubId == 0);
1680 return OCLASS_DATABASE;
1682 case TableSpaceRelationId:
1683 Assert(object->objectSubId == 0);
1684 return OCLASS_TBLSPACE;
1687 /* shouldn't get here */
1688 elog(ERROR, "unrecognized object class: %u", object->classId);
1689 return OCLASS_CLASS; /* keep compiler quiet */
1693 * getObjectDescription: build an object description for messages
1695 * The result is a palloc'd string.
1698 getObjectDescription(const ObjectAddress *object)
1700 StringInfoData buffer;
1702 initStringInfo(&buffer);
1704 switch (getObjectClass(object))
1707 getRelationDescription(&buffer, object->objectId);
1708 if (object->objectSubId != 0)
1709 appendStringInfo(&buffer, _(" column %s"),
1710 get_relid_attribute_name(object->objectId,
1711 object->objectSubId));
1715 appendStringInfo(&buffer, _("function %s"),
1716 format_procedure(object->objectId));
1720 appendStringInfo(&buffer, _("type %s"),
1721 format_type_be(object->objectId));
1727 ScanKeyData skey[1];
1730 Form_pg_cast castForm;
1732 castDesc = heap_open(CastRelationId, AccessShareLock);
1734 ScanKeyInit(&skey[0],
1735 ObjectIdAttributeNumber,
1736 BTEqualStrategyNumber, F_OIDEQ,
1737 ObjectIdGetDatum(object->objectId));
1739 rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
1740 SnapshotNow, 1, skey);
1742 tup = systable_getnext(rcscan);
1744 if (!HeapTupleIsValid(tup))
1745 elog(ERROR, "could not find tuple for cast %u",
1748 castForm = (Form_pg_cast) GETSTRUCT(tup);
1750 appendStringInfo(&buffer, _("cast from %s to %s"),
1751 format_type_be(castForm->castsource),
1752 format_type_be(castForm->casttarget));
1754 systable_endscan(rcscan);
1755 heap_close(castDesc, AccessShareLock);
1759 case OCLASS_CONSTRAINT:
1762 ScanKeyData skey[1];
1765 Form_pg_constraint con;
1767 conDesc = heap_open(ConstraintRelationId, AccessShareLock);
1769 ScanKeyInit(&skey[0],
1770 ObjectIdAttributeNumber,
1771 BTEqualStrategyNumber, F_OIDEQ,
1772 ObjectIdGetDatum(object->objectId));
1774 rcscan = systable_beginscan(conDesc, ConstraintOidIndexId, true,
1775 SnapshotNow, 1, skey);
1777 tup = systable_getnext(rcscan);
1779 if (!HeapTupleIsValid(tup))
1780 elog(ERROR, "could not find tuple for constraint %u",
1783 con = (Form_pg_constraint) GETSTRUCT(tup);
1785 if (OidIsValid(con->conrelid))
1787 appendStringInfo(&buffer, _("constraint %s on "),
1788 NameStr(con->conname));
1789 getRelationDescription(&buffer, con->conrelid);
1793 appendStringInfo(&buffer, _("constraint %s"),
1794 NameStr(con->conname));
1797 systable_endscan(rcscan);
1798 heap_close(conDesc, AccessShareLock);
1802 case OCLASS_CONVERSION:
1806 conTup = SearchSysCache(CONOID,
1807 ObjectIdGetDatum(object->objectId),
1809 if (!HeapTupleIsValid(conTup))
1810 elog(ERROR, "cache lookup failed for conversion %u",
1812 appendStringInfo(&buffer, _("conversion %s"),
1813 NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
1814 ReleaseSysCache(conTup);
1818 case OCLASS_DEFAULT:
1820 Relation attrdefDesc;
1821 ScanKeyData skey[1];
1824 Form_pg_attrdef attrdef;
1825 ObjectAddress colobject;
1827 attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
1829 ScanKeyInit(&skey[0],
1830 ObjectIdAttributeNumber,
1831 BTEqualStrategyNumber, F_OIDEQ,
1832 ObjectIdGetDatum(object->objectId));
1834 adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
1835 true, SnapshotNow, 1, skey);
1837 tup = systable_getnext(adscan);
1839 if (!HeapTupleIsValid(tup))
1840 elog(ERROR, "could not find tuple for attrdef %u",
1843 attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
1845 colobject.classId = RelationRelationId;
1846 colobject.objectId = attrdef->adrelid;
1847 colobject.objectSubId = attrdef->adnum;
1849 appendStringInfo(&buffer, _("default for %s"),
1850 getObjectDescription(&colobject));
1852 systable_endscan(adscan);
1853 heap_close(attrdefDesc, AccessShareLock);
1857 case OCLASS_LANGUAGE:
1861 langTup = SearchSysCache(LANGOID,
1862 ObjectIdGetDatum(object->objectId),
1864 if (!HeapTupleIsValid(langTup))
1865 elog(ERROR, "cache lookup failed for language %u",
1867 appendStringInfo(&buffer, _("language %s"),
1868 NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
1869 ReleaseSysCache(langTup);
1873 case OCLASS_OPERATOR:
1874 appendStringInfo(&buffer, _("operator %s"),
1875 format_operator(object->objectId));
1878 case OCLASS_OPCLASS:
1881 Form_pg_opclass opcForm;
1886 opcTup = SearchSysCache(CLAOID,
1887 ObjectIdGetDatum(object->objectId),
1889 if (!HeapTupleIsValid(opcTup))
1890 elog(ERROR, "cache lookup failed for opclass %u",
1892 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
1894 amTup = SearchSysCache(AMOID,
1895 ObjectIdGetDatum(opcForm->opcmethod),
1897 if (!HeapTupleIsValid(amTup))
1898 elog(ERROR, "cache lookup failed for access method %u",
1899 opcForm->opcmethod);
1900 amForm = (Form_pg_am) GETSTRUCT(amTup);
1902 /* Qualify the name if not visible in search path */
1903 if (OpclassIsVisible(object->objectId))
1906 nspname = get_namespace_name(opcForm->opcnamespace);
1908 appendStringInfo(&buffer, _("operator class %s for access method %s"),
1909 quote_qualified_identifier(nspname,
1910 NameStr(opcForm->opcname)),
1911 NameStr(amForm->amname));
1913 ReleaseSysCache(amTup);
1914 ReleaseSysCache(opcTup);
1918 case OCLASS_OPFAMILY:
1919 getOpFamilyDescription(&buffer, object->objectId);
1925 ScanKeyData skey[1];
1928 Form_pg_amop amopForm;
1930 amopDesc = heap_open(AccessMethodOperatorRelationId,
1933 ScanKeyInit(&skey[0],
1934 ObjectIdAttributeNumber,
1935 BTEqualStrategyNumber, F_OIDEQ,
1936 ObjectIdGetDatum(object->objectId));
1938 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
1939 SnapshotNow, 1, skey);
1941 tup = systable_getnext(amscan);
1943 if (!HeapTupleIsValid(tup))
1944 elog(ERROR, "could not find tuple for amop entry %u",
1947 amopForm = (Form_pg_amop) GETSTRUCT(tup);
1949 appendStringInfo(&buffer, _("operator %d %s of "),
1950 amopForm->amopstrategy,
1951 format_operator(amopForm->amopopr));
1952 getOpFamilyDescription(&buffer, amopForm->amopfamily);
1954 systable_endscan(amscan);
1955 heap_close(amopDesc, AccessShareLock);
1961 Relation amprocDesc;
1962 ScanKeyData skey[1];
1965 Form_pg_amproc amprocForm;
1967 amprocDesc = heap_open(AccessMethodProcedureRelationId,
1970 ScanKeyInit(&skey[0],
1971 ObjectIdAttributeNumber,
1972 BTEqualStrategyNumber, F_OIDEQ,
1973 ObjectIdGetDatum(object->objectId));
1975 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
1976 SnapshotNow, 1, skey);
1978 tup = systable_getnext(amscan);
1980 if (!HeapTupleIsValid(tup))
1981 elog(ERROR, "could not find tuple for amproc entry %u",
1984 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
1986 appendStringInfo(&buffer, _("function %d %s of "),
1987 amprocForm->amprocnum,
1988 format_procedure(amprocForm->amproc));
1989 getOpFamilyDescription(&buffer, amprocForm->amprocfamily);
1991 systable_endscan(amscan);
1992 heap_close(amprocDesc, AccessShareLock);
1996 case OCLASS_REWRITE:
1999 ScanKeyData skey[1];
2002 Form_pg_rewrite rule;
2004 ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
2006 ScanKeyInit(&skey[0],
2007 ObjectIdAttributeNumber,
2008 BTEqualStrategyNumber, F_OIDEQ,
2009 ObjectIdGetDatum(object->objectId));
2011 rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
2012 SnapshotNow, 1, skey);
2014 tup = systable_getnext(rcscan);
2016 if (!HeapTupleIsValid(tup))
2017 elog(ERROR, "could not find tuple for rule %u",
2020 rule = (Form_pg_rewrite) GETSTRUCT(tup);
2022 appendStringInfo(&buffer, _("rule %s on "),
2023 NameStr(rule->rulename));
2024 getRelationDescription(&buffer, rule->ev_class);
2026 systable_endscan(rcscan);
2027 heap_close(ruleDesc, AccessShareLock);
2031 case OCLASS_TRIGGER:
2034 ScanKeyData skey[1];
2037 Form_pg_trigger trig;
2039 trigDesc = heap_open(TriggerRelationId, AccessShareLock);
2041 ScanKeyInit(&skey[0],
2042 ObjectIdAttributeNumber,
2043 BTEqualStrategyNumber, F_OIDEQ,
2044 ObjectIdGetDatum(object->objectId));
2046 tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
2047 SnapshotNow, 1, skey);
2049 tup = systable_getnext(tgscan);
2051 if (!HeapTupleIsValid(tup))
2052 elog(ERROR, "could not find tuple for trigger %u",
2055 trig = (Form_pg_trigger) GETSTRUCT(tup);
2057 appendStringInfo(&buffer, _("trigger %s on "),
2058 NameStr(trig->tgname));
2059 getRelationDescription(&buffer, trig->tgrelid);
2061 systable_endscan(tgscan);
2062 heap_close(trigDesc, AccessShareLock);
2070 nspname = get_namespace_name(object->objectId);
2072 elog(ERROR, "cache lookup failed for namespace %u",
2074 appendStringInfo(&buffer, _("schema %s"), nspname);
2080 appendStringInfo(&buffer, _("role %s"),
2081 GetUserNameFromId(object->objectId));
2085 case OCLASS_DATABASE:
2089 datname = get_database_name(object->objectId);
2091 elog(ERROR, "cache lookup failed for database %u",
2093 appendStringInfo(&buffer, _("database %s"), datname);
2097 case OCLASS_TBLSPACE:
2101 tblspace = get_tablespace_name(object->objectId);
2103 elog(ERROR, "cache lookup failed for tablespace %u",
2105 appendStringInfo(&buffer, _("tablespace %s"), tblspace);
2110 appendStringInfo(&buffer, "unrecognized object %u %u %d",
2113 object->objectSubId);
2121 * subroutine for getObjectDescription: describe a relation
2124 getRelationDescription(StringInfo buffer, Oid relid)
2127 Form_pg_class relForm;
2131 relTup = SearchSysCache(RELOID,
2132 ObjectIdGetDatum(relid),
2134 if (!HeapTupleIsValid(relTup))
2135 elog(ERROR, "cache lookup failed for relation %u", relid);
2136 relForm = (Form_pg_class) GETSTRUCT(relTup);
2138 /* Qualify the name if not visible in search path */
2139 if (RelationIsVisible(relid))
2142 nspname = get_namespace_name(relForm->relnamespace);
2144 relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
2146 switch (relForm->relkind)
2148 case RELKIND_RELATION:
2149 appendStringInfo(buffer, _("table %s"),
2153 appendStringInfo(buffer, _("index %s"),
2156 case RELKIND_SEQUENCE:
2157 appendStringInfo(buffer, _("sequence %s"),
2160 case RELKIND_UNCATALOGED:
2161 appendStringInfo(buffer, _("uncataloged table %s"),
2164 case RELKIND_TOASTVALUE:
2165 appendStringInfo(buffer, _("toast table %s"),
2169 appendStringInfo(buffer, _("view %s"),
2172 case RELKIND_COMPOSITE_TYPE:
2173 appendStringInfo(buffer, _("composite type %s"),
2177 /* shouldn't get here */
2178 appendStringInfo(buffer, _("relation %s"),
2183 ReleaseSysCache(relTup);
2187 * subroutine for getObjectDescription: describe an operator family
2190 getOpFamilyDescription(StringInfo buffer, Oid opfid)
2193 Form_pg_opfamily opfForm;
2198 opfTup = SearchSysCache(OPFAMILYOID,
2199 ObjectIdGetDatum(opfid),
2201 if (!HeapTupleIsValid(opfTup))
2202 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
2203 opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
2205 amTup = SearchSysCache(AMOID,
2206 ObjectIdGetDatum(opfForm->opfmethod),
2208 if (!HeapTupleIsValid(amTup))
2209 elog(ERROR, "cache lookup failed for access method %u",
2210 opfForm->opfmethod);
2211 amForm = (Form_pg_am) GETSTRUCT(amTup);
2213 /* Qualify the name if not visible in search path */
2214 if (OpfamilyIsVisible(opfid))
2217 nspname = get_namespace_name(opfForm->opfnamespace);
2219 appendStringInfo(buffer, _("operator family %s for access method %s"),
2220 quote_qualified_identifier(nspname,
2221 NameStr(opfForm->opfname)),
2222 NameStr(amForm->amname));
2224 ReleaseSysCache(amTup);
2225 ReleaseSysCache(opfTup);