1 /*-------------------------------------------------------------------------
4 * Routines to support inter-object dependencies.
7 * Portions Copyright (c) 1996-2010, 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.96 2010/02/26 02:00:36 momjian Exp $
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "access/sysattr.h"
20 #include "access/xact.h"
21 #include "catalog/dependency.h"
22 #include "catalog/heap.h"
23 #include "catalog/index.h"
24 #include "catalog/indexing.h"
25 #include "catalog/namespace.h"
26 #include "catalog/pg_amop.h"
27 #include "catalog/pg_amproc.h"
28 #include "catalog/pg_attrdef.h"
29 #include "catalog/pg_authid.h"
30 #include "catalog/pg_cast.h"
31 #include "catalog/pg_constraint.h"
32 #include "catalog/pg_conversion.h"
33 #include "catalog/pg_conversion_fn.h"
34 #include "catalog/pg_database.h"
35 #include "catalog/pg_default_acl.h"
36 #include "catalog/pg_depend.h"
37 #include "catalog/pg_foreign_data_wrapper.h"
38 #include "catalog/pg_foreign_server.h"
39 #include "catalog/pg_language.h"
40 #include "catalog/pg_largeobject.h"
41 #include "catalog/pg_namespace.h"
42 #include "catalog/pg_opclass.h"
43 #include "catalog/pg_operator.h"
44 #include "catalog/pg_opfamily.h"
45 #include "catalog/pg_proc.h"
46 #include "catalog/pg_rewrite.h"
47 #include "catalog/pg_tablespace.h"
48 #include "catalog/pg_trigger.h"
49 #include "catalog/pg_ts_config.h"
50 #include "catalog/pg_ts_dict.h"
51 #include "catalog/pg_ts_parser.h"
52 #include "catalog/pg_ts_template.h"
53 #include "catalog/pg_type.h"
54 #include "catalog/pg_user_mapping.h"
55 #include "commands/comment.h"
56 #include "commands/dbcommands.h"
57 #include "commands/defrem.h"
58 #include "commands/proclang.h"
59 #include "commands/schemacmds.h"
60 #include "commands/tablespace.h"
61 #include "commands/trigger.h"
62 #include "commands/typecmds.h"
63 #include "foreign/foreign.h"
64 #include "miscadmin.h"
65 #include "nodes/nodeFuncs.h"
66 #include "parser/parsetree.h"
67 #include "rewrite/rewriteRemove.h"
68 #include "storage/lmgr.h"
69 #include "utils/acl.h"
70 #include "utils/builtins.h"
71 #include "utils/fmgroids.h"
72 #include "utils/guc.h"
73 #include "utils/lsyscache.h"
74 #include "utils/syscache.h"
75 #include "utils/tqual.h"
79 * Deletion processing requires additional state for each ObjectAddress that
80 * it's planning to delete. For simplicity and code-sharing we make the
81 * ObjectAddresses code support arrays with or without this extra state.
85 int flags; /* bitmask, see bit definitions below */
86 ObjectAddress dependee; /* object whose deletion forced this one */
89 /* ObjectAddressExtra flag bits */
90 #define DEPFLAG_ORIGINAL 0x0001 /* an original deletion target */
91 #define DEPFLAG_NORMAL 0x0002 /* reached via normal dependency */
92 #define DEPFLAG_AUTO 0x0004 /* reached via auto dependency */
93 #define DEPFLAG_INTERNAL 0x0008 /* reached via internal dependency */
96 /* expansible list of ObjectAddresses */
97 struct ObjectAddresses
99 ObjectAddress *refs; /* => palloc'd array */
100 ObjectAddressExtra *extras; /* => palloc'd array, or NULL if not used */
101 int numrefs; /* current number of references */
102 int maxrefs; /* current size of palloc'd array(s) */
105 /* typedef ObjectAddresses appears in dependency.h */
107 /* threaded list of ObjectAddresses, for recursion detection */
108 typedef struct ObjectAddressStack
110 const ObjectAddress *object; /* object being visited */
111 int flags; /* its current flag bits */
112 struct ObjectAddressStack *next; /* next outer stack level */
113 } ObjectAddressStack;
115 /* for find_expr_references_walker */
118 ObjectAddresses *addrs; /* addresses being accumulated */
119 List *rtables; /* list of rangetables to resolve Vars */
120 } find_expr_references_context;
123 * This constant table maps ObjectClasses to the corresponding catalog OIDs.
124 * See also getObjectClass().
126 static const Oid object_classes[MAX_OCLASS] = {
127 RelationRelationId, /* OCLASS_CLASS */
128 ProcedureRelationId, /* OCLASS_PROC */
129 TypeRelationId, /* OCLASS_TYPE */
130 CastRelationId, /* OCLASS_CAST */
131 ConstraintRelationId, /* OCLASS_CONSTRAINT */
132 ConversionRelationId, /* OCLASS_CONVERSION */
133 AttrDefaultRelationId, /* OCLASS_DEFAULT */
134 LanguageRelationId, /* OCLASS_LANGUAGE */
135 LargeObjectRelationId, /* OCLASS_LARGEOBJECT */
136 OperatorRelationId, /* OCLASS_OPERATOR */
137 OperatorClassRelationId, /* OCLASS_OPCLASS */
138 OperatorFamilyRelationId, /* OCLASS_OPFAMILY */
139 AccessMethodOperatorRelationId, /* OCLASS_AMOP */
140 AccessMethodProcedureRelationId, /* OCLASS_AMPROC */
141 RewriteRelationId, /* OCLASS_REWRITE */
142 TriggerRelationId, /* OCLASS_TRIGGER */
143 NamespaceRelationId, /* OCLASS_SCHEMA */
144 TSParserRelationId, /* OCLASS_TSPARSER */
145 TSDictionaryRelationId, /* OCLASS_TSDICT */
146 TSTemplateRelationId, /* OCLASS_TSTEMPLATE */
147 TSConfigRelationId, /* OCLASS_TSCONFIG */
148 AuthIdRelationId, /* OCLASS_ROLE */
149 DatabaseRelationId, /* OCLASS_DATABASE */
150 TableSpaceRelationId, /* OCLASS_TBLSPACE */
151 ForeignDataWrapperRelationId, /* OCLASS_FDW */
152 ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */
153 UserMappingRelationId, /* OCLASS_USER_MAPPING */
154 DefaultAclRelationId /* OCLASS_DEFACL */
158 static void findDependentObjects(const ObjectAddress *object,
160 ObjectAddressStack *stack,
161 ObjectAddresses *targetObjects,
162 const ObjectAddresses *pendingObjects,
164 static void reportDependentObjects(const ObjectAddresses *targetObjects,
165 DropBehavior behavior,
167 const ObjectAddress *origObject);
168 static void deleteOneObject(const ObjectAddress *object, Relation depRel);
169 static void doDeletion(const ObjectAddress *object);
170 static void AcquireDeletionLock(const ObjectAddress *object);
171 static void ReleaseDeletionLock(const ObjectAddress *object);
172 static bool find_expr_references_walker(Node *node,
173 find_expr_references_context *context);
174 static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
175 static int object_address_comparator(const void *a, const void *b);
176 static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
177 ObjectAddresses *addrs);
178 static void add_exact_object_address_extra(const ObjectAddress *object,
179 const ObjectAddressExtra *extra,
180 ObjectAddresses *addrs);
181 static bool object_address_present_add_flags(const ObjectAddress *object,
183 ObjectAddresses *addrs);
184 static void getRelationDescription(StringInfo buffer, Oid relid);
185 static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
189 * performDeletion: attempt to drop the specified object. If CASCADE
190 * behavior is specified, also drop any dependent objects (recursively).
191 * If RESTRICT behavior is specified, error out if there are any dependent
192 * objects, except for those that should be implicitly dropped anyway
193 * according to the dependency type.
195 * This is the outer control routine for all forms of DROP that drop objects
196 * that can participate in dependencies. Note that the next two routines
197 * are variants on the same theme; if you change anything here you'll likely
198 * need to fix them too.
201 performDeletion(const ObjectAddress *object,
202 DropBehavior behavior)
205 ObjectAddresses *targetObjects;
209 * We save some cycles by opening pg_depend just once and passing the
210 * Relation pointer down to all the recursive deletion steps.
212 depRel = heap_open(DependRelationId, RowExclusiveLock);
215 * Acquire deletion lock on the target object. (Ideally the caller has
216 * done this already, but many places are sloppy about it.)
218 AcquireDeletionLock(object);
221 * Construct a list of objects to delete (ie, the given object plus
222 * everything directly or indirectly dependent on it).
224 targetObjects = new_object_addresses();
226 findDependentObjects(object,
228 NULL, /* empty stack */
230 NULL, /* no pendingObjects */
234 * Check if deletion is allowed, and report about cascaded deletes.
236 reportDependentObjects(targetObjects,
242 * Delete all the objects in the proper order.
244 for (i = 0; i < targetObjects->numrefs; i++)
246 ObjectAddress *thisobj = targetObjects->refs + i;
248 deleteOneObject(thisobj, depRel);
252 free_object_addresses(targetObjects);
254 heap_close(depRel, RowExclusiveLock);
258 * performMultipleDeletions: Similar to performDeletion, but act on multiple
261 * The main difference from issuing multiple performDeletion calls is that the
262 * list of objects that would be implicitly dropped, for each object to be
263 * dropped, is the union of the implicit-object list for all objects. This
264 * makes each check be more relaxed.
267 performMultipleDeletions(const ObjectAddresses *objects,
268 DropBehavior behavior)
271 ObjectAddresses *targetObjects;
274 /* No work if no objects... */
275 if (objects->numrefs <= 0)
279 * We save some cycles by opening pg_depend just once and passing the
280 * Relation pointer down to all the recursive deletion steps.
282 depRel = heap_open(DependRelationId, RowExclusiveLock);
285 * Construct a list of objects to delete (ie, the given objects plus
286 * everything directly or indirectly dependent on them). Note that
287 * because we pass the whole objects list as pendingObjects context, we
288 * won't get a failure from trying to delete an object that is internally
289 * dependent on another one in the list; we'll just skip that object and
290 * delete it when we reach its owner.
292 targetObjects = new_object_addresses();
294 for (i = 0; i < objects->numrefs; i++)
296 const ObjectAddress *thisobj = objects->refs + i;
299 * Acquire deletion lock on each target object. (Ideally the caller
300 * has done this already, but many places are sloppy about it.)
302 AcquireDeletionLock(thisobj);
304 findDependentObjects(thisobj,
306 NULL, /* empty stack */
313 * Check if deletion is allowed, and report about cascaded deletes.
315 * If there's exactly one object being deleted, report it the same way as
316 * in performDeletion(), else we have to be vaguer.
318 reportDependentObjects(targetObjects,
321 (objects->numrefs == 1 ? objects->refs : NULL));
324 * Delete all the objects in the proper order.
326 for (i = 0; i < targetObjects->numrefs; i++)
328 ObjectAddress *thisobj = targetObjects->refs + i;
330 deleteOneObject(thisobj, depRel);
334 free_object_addresses(targetObjects);
336 heap_close(depRel, RowExclusiveLock);
340 * deleteWhatDependsOn: attempt to drop everything that depends on the
341 * specified object, though not the object itself. Behavior is always
344 * This is currently used only to clean out the contents of a schema
345 * (namespace): the passed object is a namespace. We normally want this
346 * to be done silently, so there's an option to suppress NOTICE messages.
349 deleteWhatDependsOn(const ObjectAddress *object,
353 ObjectAddresses *targetObjects;
357 * We save some cycles by opening pg_depend just once and passing the
358 * Relation pointer down to all the recursive deletion steps.
360 depRel = heap_open(DependRelationId, RowExclusiveLock);
363 * Acquire deletion lock on the target object. (Ideally the caller has
364 * done this already, but many places are sloppy about it.)
366 AcquireDeletionLock(object);
369 * Construct a list of objects to delete (ie, the given object plus
370 * everything directly or indirectly dependent on it).
372 targetObjects = new_object_addresses();
374 findDependentObjects(object,
376 NULL, /* empty stack */
378 NULL, /* no pendingObjects */
382 * Check if deletion is allowed, and report about cascaded deletes.
384 reportDependentObjects(targetObjects,
386 showNotices ? NOTICE : DEBUG2,
390 * Delete all the objects in the proper order, except we skip the original
393 for (i = 0; i < targetObjects->numrefs; i++)
395 ObjectAddress *thisobj = targetObjects->refs + i;
396 ObjectAddressExtra *thisextra = targetObjects->extras + i;
398 if (thisextra->flags & DEPFLAG_ORIGINAL)
401 deleteOneObject(thisobj, depRel);
405 free_object_addresses(targetObjects);
407 heap_close(depRel, RowExclusiveLock);
411 * findDependentObjects - find all objects that depend on 'object'
413 * For every object that depends on the starting object, acquire a deletion
414 * lock on the object, add it to targetObjects (if not already there),
415 * and recursively find objects that depend on it. An object's dependencies
416 * will be placed into targetObjects before the object itself; this means
417 * that the finished list's order represents a safe deletion order.
419 * The caller must already have a deletion lock on 'object' itself,
420 * but must not have added it to targetObjects. (Note: there are corner
421 * cases where we won't add the object either, and will also release the
422 * caller-taken lock. This is a bit ugly, but the API is set up this way
423 * to allow easy rechecking of an object's liveness after we lock it. See
424 * notes within the function.)
426 * When dropping a whole object (subId = 0), we find dependencies for
427 * its sub-objects too.
429 * object: the object to add to targetObjects and find dependencies on
430 * flags: flags to be ORed into the object's targetObjects entry
431 * stack: list of objects being visited in current recursion; topmost item
432 * is the object that we recursed from (NULL for external callers)
433 * targetObjects: list of objects that are scheduled to be deleted
434 * pendingObjects: list of other objects slated for destruction, but
435 * not necessarily in targetObjects yet (can be NULL if none)
436 * depRel: already opened pg_depend relation
439 findDependentObjects(const ObjectAddress *object,
441 ObjectAddressStack *stack,
442 ObjectAddresses *targetObjects,
443 const ObjectAddresses *pendingObjects,
450 ObjectAddress otherObject;
451 ObjectAddressStack mystack;
452 ObjectAddressExtra extra;
453 ObjectAddressStack *stackptr;
456 * If the target object is already being visited in an outer recursion
457 * level, just report the current flags back to that level and exit. This
458 * is needed to avoid infinite recursion in the face of circular
461 * The stack check alone would result in dependency loops being broken at
462 * an arbitrary point, ie, the first member object of the loop to be
463 * visited is the last one to be deleted. This is obviously unworkable.
464 * However, the check for internal dependency below guarantees that we
465 * will not break a loop at an internal dependency: if we enter the loop
466 * at an "owned" object we will switch and start at the "owning" object
467 * instead. We could probably hack something up to avoid breaking at an
468 * auto dependency, too, if we had to. However there are no known cases
469 * where that would be necessary.
471 for (stackptr = stack; stackptr; stackptr = stackptr->next)
473 if (object->classId == stackptr->object->classId &&
474 object->objectId == stackptr->object->objectId)
476 if (object->objectSubId == stackptr->object->objectSubId)
478 stackptr->flags |= flags;
483 * Could visit column with whole table already on stack; this is
484 * the same case noted in object_address_present_add_flags().
485 * (It's not clear this can really happen, but we might as well
488 if (stackptr->object->objectSubId == 0)
494 * It's also possible that the target object has already been completely
495 * processed and put into targetObjects. If so, again we just add the
496 * specified flags to its entry and return.
498 * (Note: in these early-exit cases we could release the caller-taken
499 * lock, since the object is presumably now locked multiple times; but it
500 * seems not worth the cycles.)
502 if (object_address_present_add_flags(object, flags, targetObjects))
506 * The target object might be internally dependent on some other object
507 * (its "owner"). If so, and if we aren't recursing from the owning
508 * object, we have to transform this deletion request into a deletion
509 * request of the owning object. (We'll eventually recurse back to this
510 * object, but the owning object has to be visited first so it will be
511 * deleted after.) The way to find out about this is to scan the
512 * pg_depend entries that show what this object depends on.
515 Anum_pg_depend_classid,
516 BTEqualStrategyNumber, F_OIDEQ,
517 ObjectIdGetDatum(object->classId));
519 Anum_pg_depend_objid,
520 BTEqualStrategyNumber, F_OIDEQ,
521 ObjectIdGetDatum(object->objectId));
522 if (object->objectSubId != 0)
525 Anum_pg_depend_objsubid,
526 BTEqualStrategyNumber, F_INT4EQ,
527 Int32GetDatum(object->objectSubId));
533 scan = systable_beginscan(depRel, DependDependerIndexId, true,
534 SnapshotNow, nkeys, key);
536 while (HeapTupleIsValid(tup = systable_getnext(scan)))
538 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
540 otherObject.classId = foundDep->refclassid;
541 otherObject.objectId = foundDep->refobjid;
542 otherObject.objectSubId = foundDep->refobjsubid;
544 switch (foundDep->deptype)
546 case DEPENDENCY_NORMAL:
547 case DEPENDENCY_AUTO:
550 case DEPENDENCY_INTERNAL:
553 * This object is part of the internal implementation of
554 * another object. We have three cases:
556 * 1. At the outermost recursion level, disallow the DROP. (We
557 * just ereport here, rather than proceeding, since no other
558 * dependencies are likely to be interesting.) However, if
559 * the other object is listed in pendingObjects, just release
560 * the caller's lock and return; we'll eventually complete the
561 * DROP when we reach that entry in the pending list.
567 if (pendingObjects &&
568 object_address_present(&otherObject, pendingObjects))
570 systable_endscan(scan);
571 /* need to release caller's lock; see notes below */
572 ReleaseDeletionLock(object);
575 otherObjDesc = getObjectDescription(&otherObject);
577 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
578 errmsg("cannot drop %s because %s requires it",
579 getObjectDescription(object),
581 errhint("You can drop %s instead.",
586 * 2. When recursing from the other end of this dependency,
587 * it's okay to continue with the deletion. This holds when
588 * recursing from a whole object that includes the nominal
589 * other end as a component, too.
591 if (stack->object->classId == otherObject.classId &&
592 stack->object->objectId == otherObject.objectId &&
593 (stack->object->objectSubId == otherObject.objectSubId ||
594 stack->object->objectSubId == 0))
598 * 3. When recursing from anyplace else, transform this
599 * deletion request into a delete of the other object.
601 * First, release caller's lock on this object and get
602 * deletion lock on the other object. (We must release
603 * caller's lock to avoid deadlock against a concurrent
604 * deletion of the other object.)
606 ReleaseDeletionLock(object);
607 AcquireDeletionLock(&otherObject);
610 * The other object might have been deleted while we waited to
611 * lock it; if so, neither it nor the current object are
612 * interesting anymore. We test this by checking the
613 * pg_depend entry (see notes below).
615 if (!systable_recheck_tuple(scan, tup))
617 systable_endscan(scan);
618 ReleaseDeletionLock(&otherObject);
623 * Okay, recurse to the other object instead of proceeding. We
624 * treat this exactly as if the original reference had linked
625 * to that object instead of this one; hence, pass through the
626 * same flags and stack.
628 findDependentObjects(&otherObject,
634 /* And we're done here. */
635 systable_endscan(scan);
640 * Should not happen; PIN dependencies should have zeroes in
641 * the depender fields...
643 elog(ERROR, "incorrect use of PIN dependency with %s",
644 getObjectDescription(object));
647 elog(ERROR, "unrecognized dependency type '%c' for %s",
648 foundDep->deptype, getObjectDescription(object));
653 systable_endscan(scan);
656 * Now recurse to any dependent objects. We must visit them first since
657 * they have to be deleted before the current object.
659 mystack.object = object; /* set up a new stack level */
660 mystack.flags = flags;
661 mystack.next = stack;
664 Anum_pg_depend_refclassid,
665 BTEqualStrategyNumber, F_OIDEQ,
666 ObjectIdGetDatum(object->classId));
668 Anum_pg_depend_refobjid,
669 BTEqualStrategyNumber, F_OIDEQ,
670 ObjectIdGetDatum(object->objectId));
671 if (object->objectSubId != 0)
674 Anum_pg_depend_refobjsubid,
675 BTEqualStrategyNumber, F_INT4EQ,
676 Int32GetDatum(object->objectSubId));
682 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
683 SnapshotNow, nkeys, key);
685 while (HeapTupleIsValid(tup = systable_getnext(scan)))
687 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
690 otherObject.classId = foundDep->classid;
691 otherObject.objectId = foundDep->objid;
692 otherObject.objectSubId = foundDep->objsubid;
695 * Must lock the dependent object before recursing to it.
697 AcquireDeletionLock(&otherObject);
700 * The dependent object might have been deleted while we waited to
701 * lock it; if so, we don't need to do anything more with it. We can
702 * test this cheaply and independently of the object's type by seeing
703 * if the pg_depend tuple we are looking at is still live. (If the
704 * object got deleted, the tuple would have been deleted too.)
706 if (!systable_recheck_tuple(scan, tup))
708 /* release the now-useless lock */
709 ReleaseDeletionLock(&otherObject);
710 /* and continue scanning for dependencies */
714 /* Recurse, passing flags indicating the dependency type */
715 switch (foundDep->deptype)
717 case DEPENDENCY_NORMAL:
718 subflags = DEPFLAG_NORMAL;
720 case DEPENDENCY_AUTO:
721 subflags = DEPFLAG_AUTO;
723 case DEPENDENCY_INTERNAL:
724 subflags = DEPFLAG_INTERNAL;
729 * For a PIN dependency we just ereport immediately; there
730 * won't be any others to report.
733 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
734 errmsg("cannot drop %s because it is required by the database system",
735 getObjectDescription(object))));
736 subflags = 0; /* keep compiler quiet */
739 elog(ERROR, "unrecognized dependency type '%c' for %s",
740 foundDep->deptype, getObjectDescription(object));
741 subflags = 0; /* keep compiler quiet */
745 findDependentObjects(&otherObject,
753 systable_endscan(scan);
756 * Finally, we can add the target object to targetObjects. Be careful to
757 * include any flags that were passed back down to us from inner recursion
760 extra.flags = mystack.flags;
762 extra.dependee = *stack->object;
764 memset(&extra.dependee, 0, sizeof(extra.dependee));
765 add_exact_object_address_extra(object, &extra, targetObjects);
769 * reportDependentObjects - report about dependencies, and fail if RESTRICT
771 * Tell the user about dependent objects that we are going to delete
772 * (or would need to delete, but are prevented by RESTRICT mode);
773 * then error out if there are any and it's not CASCADE mode.
775 * targetObjects: list of objects that are scheduled to be deleted
776 * behavior: RESTRICT or CASCADE
777 * msglevel: elog level for non-error report messages
778 * origObject: base object of deletion, or NULL if not available
779 * (the latter case occurs in DROP OWNED)
782 reportDependentObjects(const ObjectAddresses *targetObjects,
783 DropBehavior behavior,
785 const ObjectAddress *origObject)
788 StringInfoData clientdetail;
789 StringInfoData logdetail;
790 int numReportedClient = 0;
791 int numNotReportedClient = 0;
795 * If no error is to be thrown, and the msglevel is too low to be shown to
796 * either client or server log, there's no need to do any of the work.
798 * Note: this code doesn't know all there is to be known about elog
799 * levels, but it works for NOTICE and DEBUG2, which are the only values
800 * msglevel can currently have. We also assume we are running in a normal
801 * operating environment.
803 if (behavior == DROP_CASCADE &&
804 msglevel < client_min_messages &&
805 (msglevel < log_min_messages || log_min_messages == LOG))
809 * We limit the number of dependencies reported to the client to
810 * MAX_REPORTED_DEPS, since client software may not deal well with
811 * enormous error strings. The server log always gets a full report.
813 #define MAX_REPORTED_DEPS 100
815 initStringInfo(&clientdetail);
816 initStringInfo(&logdetail);
819 * We process the list back to front (ie, in dependency order not deletion
820 * order), since this makes for a more understandable display.
822 for (i = targetObjects->numrefs - 1; i >= 0; i--)
824 const ObjectAddress *obj = &targetObjects->refs[i];
825 const ObjectAddressExtra *extra = &targetObjects->extras[i];
828 /* Ignore the original deletion target(s) */
829 if (extra->flags & DEPFLAG_ORIGINAL)
832 objDesc = getObjectDescription(obj);
835 * If, at any stage of the recursive search, we reached the object via
836 * an AUTO or INTERNAL dependency, then it's okay to delete it even in
839 if (extra->flags & (DEPFLAG_AUTO | DEPFLAG_INTERNAL))
842 * auto-cascades are reported at DEBUG2, not msglevel. We don't
843 * try to combine them with the regular message because the
844 * results are too confusing when client_min_messages and
845 * log_min_messages are different.
848 (errmsg("drop auto-cascades to %s",
851 else if (behavior == DROP_RESTRICT)
853 char *otherDesc = getObjectDescription(&extra->dependee);
855 if (numReportedClient < MAX_REPORTED_DEPS)
857 /* separate entries with a newline */
858 if (clientdetail.len != 0)
859 appendStringInfoChar(&clientdetail, '\n');
860 appendStringInfo(&clientdetail, _("%s depends on %s"),
865 numNotReportedClient++;
866 /* separate entries with a newline */
867 if (logdetail.len != 0)
868 appendStringInfoChar(&logdetail, '\n');
869 appendStringInfo(&logdetail, _("%s depends on %s"),
876 if (numReportedClient < MAX_REPORTED_DEPS)
878 /* separate entries with a newline */
879 if (clientdetail.len != 0)
880 appendStringInfoChar(&clientdetail, '\n');
881 appendStringInfo(&clientdetail, _("drop cascades to %s"),
886 numNotReportedClient++;
887 /* separate entries with a newline */
888 if (logdetail.len != 0)
889 appendStringInfoChar(&logdetail, '\n');
890 appendStringInfo(&logdetail, _("drop cascades to %s"),
897 if (numNotReportedClient > 0)
898 appendStringInfo(&clientdetail, ngettext("\nand %d other object "
899 "(see server log for list)",
900 "\nand %d other objects "
901 "(see server log for list)",
902 numNotReportedClient),
903 numNotReportedClient);
909 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
910 errmsg("cannot drop %s because other objects depend on it",
911 getObjectDescription(origObject)),
912 errdetail("%s", clientdetail.data),
913 errdetail_log("%s", logdetail.data),
914 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
917 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
918 errmsg("cannot drop desired object(s) because other objects depend on them"),
919 errdetail("%s", clientdetail.data),
920 errdetail_log("%s", logdetail.data),
921 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
923 else if (numReportedClient > 1)
926 /* translator: %d always has a value larger than 1 */
927 (errmsg_plural("drop cascades to %d other object",
928 "drop cascades to %d other objects",
929 numReportedClient + numNotReportedClient,
930 numReportedClient + numNotReportedClient),
931 errdetail("%s", clientdetail.data),
932 errdetail_log("%s", logdetail.data)));
934 else if (numReportedClient == 1)
936 /* we just use the single item as-is */
938 (errmsg_internal("%s", clientdetail.data)));
941 pfree(clientdetail.data);
942 pfree(logdetail.data);
946 * deleteOneObject: delete a single object for performDeletion.
948 * depRel is the already-open pg_depend relation.
951 deleteOneObject(const ObjectAddress *object, Relation depRel)
959 * First remove any pg_depend records that link from this object to
960 * others. (Any records linking to this object should be gone already.)
962 * When dropping a whole object (subId = 0), remove all pg_depend records
963 * for its sub-objects too.
966 Anum_pg_depend_classid,
967 BTEqualStrategyNumber, F_OIDEQ,
968 ObjectIdGetDatum(object->classId));
970 Anum_pg_depend_objid,
971 BTEqualStrategyNumber, F_OIDEQ,
972 ObjectIdGetDatum(object->objectId));
973 if (object->objectSubId != 0)
976 Anum_pg_depend_objsubid,
977 BTEqualStrategyNumber, F_INT4EQ,
978 Int32GetDatum(object->objectSubId));
984 scan = systable_beginscan(depRel, DependDependerIndexId, true,
985 SnapshotNow, nkeys, key);
987 while (HeapTupleIsValid(tup = systable_getnext(scan)))
989 simple_heap_delete(depRel, &tup->t_self);
992 systable_endscan(scan);
995 * Delete shared dependency references related to this object. Again, if
996 * subId = 0, remove records for sub-objects too.
998 deleteSharedDependencyRecordsFor(object->classId, object->objectId,
999 object->objectSubId);
1002 * Now delete the object itself, in an object-type-dependent way.
1007 * Delete any comments associated with this object. (This is a convenient
1008 * place to do it instead of having every object type know to do it.)
1010 DeleteComments(object->objectId, object->classId, object->objectSubId);
1013 * CommandCounterIncrement here to ensure that preceding changes are all
1014 * visible to the next deletion step.
1016 CommandCounterIncrement();
1024 * doDeletion: actually delete a single object
1027 doDeletion(const ObjectAddress *object)
1029 switch (getObjectClass(object))
1033 char relKind = get_rel_relkind(object->objectId);
1035 if (relKind == RELKIND_INDEX)
1037 Assert(object->objectSubId == 0);
1038 index_drop(object->objectId);
1042 if (object->objectSubId != 0)
1043 RemoveAttributeById(object->objectId,
1044 object->objectSubId);
1046 heap_drop_with_catalog(object->objectId);
1052 RemoveFunctionById(object->objectId);
1056 RemoveTypeById(object->objectId);
1060 DropCastById(object->objectId);
1063 case OCLASS_CONSTRAINT:
1064 RemoveConstraintById(object->objectId);
1067 case OCLASS_CONVERSION:
1068 RemoveConversionById(object->objectId);
1071 case OCLASS_DEFAULT:
1072 RemoveAttrDefaultById(object->objectId);
1075 case OCLASS_LANGUAGE:
1076 DropProceduralLanguageById(object->objectId);
1079 case OCLASS_LARGEOBJECT:
1080 LargeObjectDrop(object->objectId);
1083 case OCLASS_OPERATOR:
1084 RemoveOperatorById(object->objectId);
1087 case OCLASS_OPCLASS:
1088 RemoveOpClassById(object->objectId);
1091 case OCLASS_OPFAMILY:
1092 RemoveOpFamilyById(object->objectId);
1096 RemoveAmOpEntryById(object->objectId);
1100 RemoveAmProcEntryById(object->objectId);
1103 case OCLASS_REWRITE:
1104 RemoveRewriteRuleById(object->objectId);
1107 case OCLASS_TRIGGER:
1108 RemoveTriggerById(object->objectId);
1112 RemoveSchemaById(object->objectId);
1115 case OCLASS_TSPARSER:
1116 RemoveTSParserById(object->objectId);
1120 RemoveTSDictionaryById(object->objectId);
1123 case OCLASS_TSTEMPLATE:
1124 RemoveTSTemplateById(object->objectId);
1127 case OCLASS_TSCONFIG:
1128 RemoveTSConfigurationById(object->objectId);
1132 * OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE intentionally not
1137 RemoveForeignDataWrapperById(object->objectId);
1140 case OCLASS_FOREIGN_SERVER:
1141 RemoveForeignServerById(object->objectId);
1144 case OCLASS_USER_MAPPING:
1145 RemoveUserMappingById(object->objectId);
1149 RemoveDefaultACLById(object->objectId);
1153 elog(ERROR, "unrecognized object class: %u",
1159 * AcquireDeletionLock - acquire a suitable lock for deleting an object
1161 * We use LockRelation for relations, LockDatabaseObject for everything
1162 * else. Note that dependency.c is not concerned with deleting any kind of
1163 * shared-across-databases object, so we have no need for LockSharedObject.
1166 AcquireDeletionLock(const ObjectAddress *object)
1168 if (object->classId == RelationRelationId)
1169 LockRelationOid(object->objectId, AccessExclusiveLock);
1171 /* assume we should lock the whole object not a sub-object */
1172 LockDatabaseObject(object->classId, object->objectId, 0,
1173 AccessExclusiveLock);
1177 * ReleaseDeletionLock - release an object deletion lock
1180 ReleaseDeletionLock(const ObjectAddress *object)
1182 if (object->classId == RelationRelationId)
1183 UnlockRelationOid(object->objectId, AccessExclusiveLock);
1185 /* assume we should lock the whole object not a sub-object */
1186 UnlockDatabaseObject(object->classId, object->objectId, 0,
1187 AccessExclusiveLock);
1191 * recordDependencyOnExpr - find expression dependencies
1193 * This is used to find the dependencies of rules, constraint expressions,
1196 * Given an expression or query in node-tree form, find all the objects
1197 * it refers to (tables, columns, operators, functions, etc). Record
1198 * a dependency of the specified type from the given depender object
1199 * to each object mentioned in the expression.
1201 * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
1202 * It can be NIL if no such variables are expected.
1205 recordDependencyOnExpr(const ObjectAddress *depender,
1206 Node *expr, List *rtable,
1207 DependencyType behavior)
1209 find_expr_references_context context;
1211 context.addrs = new_object_addresses();
1213 /* Set up interpretation for Vars at varlevelsup = 0 */
1214 context.rtables = list_make1(rtable);
1216 /* Scan the expression tree for referenceable objects */
1217 find_expr_references_walker(expr, &context);
1219 /* Remove any duplicates */
1220 eliminate_duplicate_dependencies(context.addrs);
1222 /* And record 'em */
1223 recordMultipleDependencies(depender,
1224 context.addrs->refs, context.addrs->numrefs,
1227 free_object_addresses(context.addrs);
1231 * recordDependencyOnSingleRelExpr - find expression dependencies
1233 * As above, but only one relation is expected to be referenced (with
1234 * varno = 1 and varlevelsup = 0). Pass the relation OID instead of a
1235 * range table. An additional frammish is that dependencies on that
1236 * relation (or its component columns) will be marked with 'self_behavior',
1237 * whereas 'behavior' is used for everything else.
1240 recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
1241 Node *expr, Oid relId,
1242 DependencyType behavior,
1243 DependencyType self_behavior)
1245 find_expr_references_context context;
1248 context.addrs = new_object_addresses();
1250 /* We gin up a rather bogus rangetable list to handle Vars */
1251 MemSet(&rte, 0, sizeof(rte));
1252 rte.type = T_RangeTblEntry;
1253 rte.rtekind = RTE_RELATION;
1256 context.rtables = list_make1(list_make1(&rte));
1258 /* Scan the expression tree for referenceable objects */
1259 find_expr_references_walker(expr, &context);
1261 /* Remove any duplicates */
1262 eliminate_duplicate_dependencies(context.addrs);
1264 /* Separate self-dependencies if necessary */
1265 if (behavior != self_behavior && context.addrs->numrefs > 0)
1267 ObjectAddresses *self_addrs;
1268 ObjectAddress *outobj;
1272 self_addrs = new_object_addresses();
1274 outobj = context.addrs->refs;
1276 for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
1278 ObjectAddress *thisobj = context.addrs->refs + oldref;
1280 if (thisobj->classId == RelationRelationId &&
1281 thisobj->objectId == relId)
1283 /* Move this ref into self_addrs */
1284 add_exact_object_address(thisobj, self_addrs);
1288 /* Keep it in context.addrs */
1294 context.addrs->numrefs = outrefs;
1296 /* Record the self-dependencies */
1297 recordMultipleDependencies(depender,
1298 self_addrs->refs, self_addrs->numrefs,
1301 free_object_addresses(self_addrs);
1304 /* Record the external dependencies */
1305 recordMultipleDependencies(depender,
1306 context.addrs->refs, context.addrs->numrefs,
1309 free_object_addresses(context.addrs);
1313 * Recursively search an expression tree for object references.
1315 * Note: we avoid creating references to columns of tables that participate
1316 * in an SQL JOIN construct, but are not actually used anywhere in the query.
1317 * To do so, we do not scan the joinaliasvars list of a join RTE while
1318 * scanning the query rangetable, but instead scan each individual entry
1319 * of the alias list when we find a reference to it.
1321 * Note: in many cases we do not need to create dependencies on the datatypes
1322 * involved in an expression, because we'll have an indirect dependency via
1323 * some other object. For instance Var nodes depend on a column which depends
1324 * on the datatype, and OpExpr nodes depend on the operator which depends on
1325 * the datatype. However we do need a type dependency if there is no such
1326 * indirect dependency, as for example in Const and CoerceToDomain nodes.
1329 find_expr_references_walker(Node *node,
1330 find_expr_references_context *context)
1336 Var *var = (Var *) node;
1340 /* Find matching rtable entry, or complain if not found */
1341 if (var->varlevelsup >= list_length(context->rtables))
1342 elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
1343 rtable = (List *) list_nth(context->rtables, var->varlevelsup);
1344 if (var->varno <= 0 || var->varno > list_length(rtable))
1345 elog(ERROR, "invalid varno %d", var->varno);
1346 rte = rt_fetch(var->varno, rtable);
1349 * A whole-row Var references no specific columns, so adds no new
1352 if (var->varattno == InvalidAttrNumber)
1354 if (rte->rtekind == RTE_RELATION)
1356 /* If it's a plain relation, reference this column */
1357 add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
1360 else if (rte->rtekind == RTE_JOIN)
1362 /* Scan join output column to add references to join inputs */
1365 /* We must make the context appropriate for join's level */
1366 save_rtables = context->rtables;
1367 context->rtables = list_copy_tail(context->rtables,
1369 if (var->varattno <= 0 ||
1370 var->varattno > list_length(rte->joinaliasvars))
1371 elog(ERROR, "invalid varattno %d", var->varattno);
1372 find_expr_references_walker((Node *) list_nth(rte->joinaliasvars,
1375 list_free(context->rtables);
1376 context->rtables = save_rtables;
1380 else if (IsA(node, Const))
1382 Const *con = (Const *) node;
1385 /* A constant must depend on the constant's datatype */
1386 add_object_address(OCLASS_TYPE, con->consttype, 0,
1390 * If it's a regclass or similar literal referring to an existing
1391 * object, add a reference to that object. (Currently, only the
1392 * regclass and regconfig cases have any likely use, but we may as
1393 * well handle all the OID-alias datatypes consistently.)
1395 if (!con->constisnull)
1397 switch (con->consttype)
1400 case REGPROCEDUREOID:
1401 objoid = DatumGetObjectId(con->constvalue);
1402 if (SearchSysCacheExists1(PROCOID,
1403 ObjectIdGetDatum(objoid)))
1404 add_object_address(OCLASS_PROC, objoid, 0,
1408 case REGOPERATOROID:
1409 objoid = DatumGetObjectId(con->constvalue);
1410 if (SearchSysCacheExists1(OPEROID,
1411 ObjectIdGetDatum(objoid)))
1412 add_object_address(OCLASS_OPERATOR, objoid, 0,
1416 objoid = DatumGetObjectId(con->constvalue);
1417 if (SearchSysCacheExists1(RELOID,
1418 ObjectIdGetDatum(objoid)))
1419 add_object_address(OCLASS_CLASS, objoid, 0,
1423 objoid = DatumGetObjectId(con->constvalue);
1424 if (SearchSysCacheExists1(TYPEOID,
1425 ObjectIdGetDatum(objoid)))
1426 add_object_address(OCLASS_TYPE, objoid, 0,
1430 objoid = DatumGetObjectId(con->constvalue);
1431 if (SearchSysCacheExists1(TSCONFIGOID,
1432 ObjectIdGetDatum(objoid)))
1433 add_object_address(OCLASS_TSCONFIG, objoid, 0,
1436 case REGDICTIONARYOID:
1437 objoid = DatumGetObjectId(con->constvalue);
1438 if (SearchSysCacheExists1(TSDICTOID,
1439 ObjectIdGetDatum(objoid)))
1440 add_object_address(OCLASS_TSDICT, objoid, 0,
1447 else if (IsA(node, Param))
1449 Param *param = (Param *) node;
1451 /* A parameter must depend on the parameter's datatype */
1452 add_object_address(OCLASS_TYPE, param->paramtype, 0,
1455 else if (IsA(node, FuncExpr))
1457 FuncExpr *funcexpr = (FuncExpr *) node;
1459 add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
1461 /* fall through to examine arguments */
1463 else if (IsA(node, OpExpr))
1465 OpExpr *opexpr = (OpExpr *) node;
1467 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1469 /* fall through to examine arguments */
1471 else if (IsA(node, DistinctExpr))
1473 DistinctExpr *distinctexpr = (DistinctExpr *) node;
1475 add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
1477 /* fall through to examine arguments */
1479 else if (IsA(node, ScalarArrayOpExpr))
1481 ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1483 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1485 /* fall through to examine arguments */
1487 else if (IsA(node, NullIfExpr))
1489 NullIfExpr *nullifexpr = (NullIfExpr *) node;
1491 add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
1493 /* fall through to examine arguments */
1495 else if (IsA(node, Aggref))
1497 Aggref *aggref = (Aggref *) node;
1499 add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
1501 /* fall through to examine arguments */
1503 else if (IsA(node, WindowFunc))
1505 WindowFunc *wfunc = (WindowFunc *) node;
1507 add_object_address(OCLASS_PROC, wfunc->winfnoid, 0,
1509 /* fall through to examine arguments */
1511 else if (IsA(node, SubPlan))
1513 /* Extra work needed here if we ever need this case */
1514 elog(ERROR, "already-planned subqueries not supported");
1516 else if (IsA(node, RelabelType))
1518 RelabelType *relab = (RelabelType *) node;
1520 /* since there is no function dependency, need to depend on type */
1521 add_object_address(OCLASS_TYPE, relab->resulttype, 0,
1524 else if (IsA(node, CoerceViaIO))
1526 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1528 /* since there is no exposed function, need to depend on type */
1529 add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0,
1532 else if (IsA(node, ArrayCoerceExpr))
1534 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1536 if (OidIsValid(acoerce->elemfuncid))
1537 add_object_address(OCLASS_PROC, acoerce->elemfuncid, 0,
1539 add_object_address(OCLASS_TYPE, acoerce->resulttype, 0,
1541 /* fall through to examine arguments */
1543 else if (IsA(node, ConvertRowtypeExpr))
1545 ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
1547 /* since there is no function dependency, need to depend on type */
1548 add_object_address(OCLASS_TYPE, cvt->resulttype, 0,
1551 else if (IsA(node, RowExpr))
1553 RowExpr *rowexpr = (RowExpr *) node;
1555 add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
1558 else if (IsA(node, RowCompareExpr))
1560 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1563 foreach(l, rcexpr->opnos)
1565 add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
1568 foreach(l, rcexpr->opfamilies)
1570 add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
1573 /* fall through to examine arguments */
1575 else if (IsA(node, CoerceToDomain))
1577 CoerceToDomain *cd = (CoerceToDomain *) node;
1579 add_object_address(OCLASS_TYPE, cd->resulttype, 0,
1582 else if (IsA(node, SortGroupClause))
1584 SortGroupClause *sgc = (SortGroupClause *) node;
1586 add_object_address(OCLASS_OPERATOR, sgc->eqop, 0,
1588 if (OidIsValid(sgc->sortop))
1589 add_object_address(OCLASS_OPERATOR, sgc->sortop, 0,
1593 else if (IsA(node, Query))
1595 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1596 Query *query = (Query *) node;
1601 * Add whole-relation refs for each plain relation mentioned in the
1602 * subquery's rtable, as well as datatype refs for any datatypes used
1603 * as a RECORD function's output. (Note: query_tree_walker takes care
1604 * of recursing into RTE_FUNCTION RTEs, subqueries, etc, so no need to
1605 * do that here. But keep it from looking at join alias lists.)
1607 foreach(rtable, query->rtable)
1609 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtable);
1612 switch (rte->rtekind)
1615 add_object_address(OCLASS_CLASS, rte->relid, 0,
1619 foreach(ct, rte->funccoltypes)
1621 add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0,
1630 /* query_tree_walker ignores ORDER BY etc, but we need those opers */
1631 find_expr_references_walker((Node *) query->sortClause, context);
1632 find_expr_references_walker((Node *) query->groupClause, context);
1633 find_expr_references_walker((Node *) query->windowClause, context);
1634 find_expr_references_walker((Node *) query->distinctClause, context);
1636 /* Examine substructure of query */
1637 context->rtables = lcons(query->rtable, context->rtables);
1638 result = query_tree_walker(query,
1639 find_expr_references_walker,
1641 QTW_IGNORE_JOINALIASES);
1642 context->rtables = list_delete_first(context->rtables);
1645 else if (IsA(node, SetOperationStmt))
1647 SetOperationStmt *setop = (SetOperationStmt *) node;
1649 /* we need to look at the groupClauses for operator references */
1650 find_expr_references_walker((Node *) setop->groupClauses, context);
1651 /* fall through to examine child nodes */
1654 return expression_tree_walker(node, find_expr_references_walker,
1659 * Given an array of dependency references, eliminate any duplicates.
1662 eliminate_duplicate_dependencies(ObjectAddresses *addrs)
1664 ObjectAddress *priorobj;
1669 * We can't sort if the array has "extra" data, because there's no way to
1670 * keep it in sync. Fortunately that combination of features is not
1673 Assert(!addrs->extras);
1675 if (addrs->numrefs <= 1)
1676 return; /* nothing to do */
1678 /* Sort the refs so that duplicates are adjacent */
1679 qsort((void *) addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
1680 object_address_comparator);
1683 priorobj = addrs->refs;
1685 for (oldref = 1; oldref < addrs->numrefs; oldref++)
1687 ObjectAddress *thisobj = addrs->refs + oldref;
1689 if (priorobj->classId == thisobj->classId &&
1690 priorobj->objectId == thisobj->objectId)
1692 if (priorobj->objectSubId == thisobj->objectSubId)
1693 continue; /* identical, so drop thisobj */
1696 * If we have a whole-object reference and a reference to a part
1697 * of the same object, we don't need the whole-object reference
1698 * (for example, we don't need to reference both table foo and
1699 * column foo.bar). The whole-object reference will always appear
1700 * first in the sorted list.
1702 if (priorobj->objectSubId == 0)
1704 /* replace whole ref with partial */
1705 priorobj->objectSubId = thisobj->objectSubId;
1709 /* Not identical, so add thisobj to output set */
1711 *priorobj = *thisobj;
1715 addrs->numrefs = newrefs;
1719 * qsort comparator for ObjectAddress items
1722 object_address_comparator(const void *a, const void *b)
1724 const ObjectAddress *obja = (const ObjectAddress *) a;
1725 const ObjectAddress *objb = (const ObjectAddress *) b;
1727 if (obja->classId < objb->classId)
1729 if (obja->classId > objb->classId)
1731 if (obja->objectId < objb->objectId)
1733 if (obja->objectId > objb->objectId)
1737 * We sort the subId as an unsigned int so that 0 will come first. See
1738 * logic in eliminate_duplicate_dependencies.
1740 if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
1742 if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
1748 * Routines for handling an expansible array of ObjectAddress items.
1750 * new_object_addresses: create a new ObjectAddresses array.
1753 new_object_addresses(void)
1755 ObjectAddresses *addrs;
1757 addrs = palloc(sizeof(ObjectAddresses));
1760 addrs->maxrefs = 32;
1761 addrs->refs = (ObjectAddress *)
1762 palloc(addrs->maxrefs * sizeof(ObjectAddress));
1763 addrs->extras = NULL; /* until/unless needed */
1769 * Add an entry to an ObjectAddresses array.
1771 * It is convenient to specify the class by ObjectClass rather than directly
1775 add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
1776 ObjectAddresses *addrs)
1778 ObjectAddress *item;
1780 /* enlarge array if needed */
1781 if (addrs->numrefs >= addrs->maxrefs)
1783 addrs->maxrefs *= 2;
1784 addrs->refs = (ObjectAddress *)
1785 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1786 Assert(!addrs->extras);
1788 /* record this item */
1789 item = addrs->refs + addrs->numrefs;
1790 item->classId = object_classes[oclass];
1791 item->objectId = objectId;
1792 item->objectSubId = subId;
1797 * Add an entry to an ObjectAddresses array.
1799 * As above, but specify entry exactly.
1802 add_exact_object_address(const ObjectAddress *object,
1803 ObjectAddresses *addrs)
1805 ObjectAddress *item;
1807 /* enlarge array if needed */
1808 if (addrs->numrefs >= addrs->maxrefs)
1810 addrs->maxrefs *= 2;
1811 addrs->refs = (ObjectAddress *)
1812 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1813 Assert(!addrs->extras);
1815 /* record this item */
1816 item = addrs->refs + addrs->numrefs;
1822 * Add an entry to an ObjectAddresses array.
1824 * As above, but specify entry exactly and provide some "extra" data too.
1827 add_exact_object_address_extra(const ObjectAddress *object,
1828 const ObjectAddressExtra *extra,
1829 ObjectAddresses *addrs)
1831 ObjectAddress *item;
1832 ObjectAddressExtra *itemextra;
1834 /* allocate extra space if first time */
1836 addrs->extras = (ObjectAddressExtra *)
1837 palloc(addrs->maxrefs * sizeof(ObjectAddressExtra));
1839 /* enlarge array if needed */
1840 if (addrs->numrefs >= addrs->maxrefs)
1842 addrs->maxrefs *= 2;
1843 addrs->refs = (ObjectAddress *)
1844 repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1845 addrs->extras = (ObjectAddressExtra *)
1846 repalloc(addrs->extras, addrs->maxrefs * sizeof(ObjectAddressExtra));
1848 /* record this item */
1849 item = addrs->refs + addrs->numrefs;
1851 itemextra = addrs->extras + addrs->numrefs;
1852 *itemextra = *extra;
1857 * Test whether an object is present in an ObjectAddresses array.
1859 * We return "true" if object is a subobject of something in the array, too.
1862 object_address_present(const ObjectAddress *object,
1863 const ObjectAddresses *addrs)
1867 for (i = addrs->numrefs - 1; i >= 0; i--)
1869 const ObjectAddress *thisobj = addrs->refs + i;
1871 if (object->classId == thisobj->classId &&
1872 object->objectId == thisobj->objectId)
1874 if (object->objectSubId == thisobj->objectSubId ||
1875 thisobj->objectSubId == 0)
1884 * As above, except that if the object is present then also OR the given
1885 * flags into its associated extra data (which must exist).
1888 object_address_present_add_flags(const ObjectAddress *object,
1890 ObjectAddresses *addrs)
1894 for (i = addrs->numrefs - 1; i >= 0; i--)
1896 ObjectAddress *thisobj = addrs->refs + i;
1898 if (object->classId == thisobj->classId &&
1899 object->objectId == thisobj->objectId)
1901 if (object->objectSubId == thisobj->objectSubId)
1903 ObjectAddressExtra *thisextra = addrs->extras + i;
1905 thisextra->flags |= flags;
1908 if (thisobj->objectSubId == 0)
1911 * We get here if we find a need to delete a column after
1912 * having already decided to drop its whole table. Obviously
1913 * we no longer need to drop the column. But don't plaster
1914 * its flags on the table.
1925 * Record multiple dependencies from an ObjectAddresses array, after first
1926 * removing any duplicates.
1929 record_object_address_dependencies(const ObjectAddress *depender,
1930 ObjectAddresses *referenced,
1931 DependencyType behavior)
1933 eliminate_duplicate_dependencies(referenced);
1934 recordMultipleDependencies(depender,
1935 referenced->refs, referenced->numrefs,
1940 * Clean up when done with an ObjectAddresses array.
1943 free_object_addresses(ObjectAddresses *addrs)
1947 pfree(addrs->extras);
1952 * Determine the class of a given object identified by objectAddress.
1954 * This function is essentially the reverse mapping for the object_classes[]
1955 * table. We implement it as a function because the OIDs aren't consecutive.
1958 getObjectClass(const ObjectAddress *object)
1960 switch (object->classId)
1962 case RelationRelationId:
1963 /* caller must check objectSubId */
1964 return OCLASS_CLASS;
1966 case ProcedureRelationId:
1967 Assert(object->objectSubId == 0);
1970 case TypeRelationId:
1971 Assert(object->objectSubId == 0);
1974 case CastRelationId:
1975 Assert(object->objectSubId == 0);
1978 case ConstraintRelationId:
1979 Assert(object->objectSubId == 0);
1980 return OCLASS_CONSTRAINT;
1982 case ConversionRelationId:
1983 Assert(object->objectSubId == 0);
1984 return OCLASS_CONVERSION;
1986 case AttrDefaultRelationId:
1987 Assert(object->objectSubId == 0);
1988 return OCLASS_DEFAULT;
1990 case LanguageRelationId:
1991 Assert(object->objectSubId == 0);
1992 return OCLASS_LANGUAGE;
1994 case LargeObjectRelationId:
1995 Assert(object->objectSubId == 0);
1996 return OCLASS_LARGEOBJECT;
1998 case OperatorRelationId:
1999 Assert(object->objectSubId == 0);
2000 return OCLASS_OPERATOR;
2002 case OperatorClassRelationId:
2003 Assert(object->objectSubId == 0);
2004 return OCLASS_OPCLASS;
2006 case OperatorFamilyRelationId:
2007 Assert(object->objectSubId == 0);
2008 return OCLASS_OPFAMILY;
2010 case AccessMethodOperatorRelationId:
2011 Assert(object->objectSubId == 0);
2014 case AccessMethodProcedureRelationId:
2015 Assert(object->objectSubId == 0);
2016 return OCLASS_AMPROC;
2018 case RewriteRelationId:
2019 Assert(object->objectSubId == 0);
2020 return OCLASS_REWRITE;
2022 case TriggerRelationId:
2023 Assert(object->objectSubId == 0);
2024 return OCLASS_TRIGGER;
2026 case NamespaceRelationId:
2027 Assert(object->objectSubId == 0);
2028 return OCLASS_SCHEMA;
2030 case TSParserRelationId:
2031 Assert(object->objectSubId == 0);
2032 return OCLASS_TSPARSER;
2034 case TSDictionaryRelationId:
2035 Assert(object->objectSubId == 0);
2036 return OCLASS_TSDICT;
2038 case TSTemplateRelationId:
2039 Assert(object->objectSubId == 0);
2040 return OCLASS_TSTEMPLATE;
2042 case TSConfigRelationId:
2043 Assert(object->objectSubId == 0);
2044 return OCLASS_TSCONFIG;
2046 case AuthIdRelationId:
2047 Assert(object->objectSubId == 0);
2050 case DatabaseRelationId:
2051 Assert(object->objectSubId == 0);
2052 return OCLASS_DATABASE;
2054 case TableSpaceRelationId:
2055 Assert(object->objectSubId == 0);
2056 return OCLASS_TBLSPACE;
2058 case ForeignDataWrapperRelationId:
2059 Assert(object->objectSubId == 0);
2062 case ForeignServerRelationId:
2063 Assert(object->objectSubId == 0);
2064 return OCLASS_FOREIGN_SERVER;
2066 case UserMappingRelationId:
2067 Assert(object->objectSubId == 0);
2068 return OCLASS_USER_MAPPING;
2070 case DefaultAclRelationId:
2071 Assert(object->objectSubId == 0);
2072 return OCLASS_DEFACL;
2075 /* shouldn't get here */
2076 elog(ERROR, "unrecognized object class: %u", object->classId);
2077 return OCLASS_CLASS; /* keep compiler quiet */
2081 * getObjectDescription: build an object description for messages
2083 * The result is a palloc'd string.
2086 getObjectDescription(const ObjectAddress *object)
2088 StringInfoData buffer;
2090 initStringInfo(&buffer);
2092 switch (getObjectClass(object))
2095 getRelationDescription(&buffer, object->objectId);
2096 if (object->objectSubId != 0)
2097 appendStringInfo(&buffer, _(" column %s"),
2098 get_relid_attribute_name(object->objectId,
2099 object->objectSubId));
2103 appendStringInfo(&buffer, _("function %s"),
2104 format_procedure(object->objectId));
2108 appendStringInfo(&buffer, _("type %s"),
2109 format_type_be(object->objectId));
2115 ScanKeyData skey[1];
2118 Form_pg_cast castForm;
2120 castDesc = heap_open(CastRelationId, AccessShareLock);
2122 ScanKeyInit(&skey[0],
2123 ObjectIdAttributeNumber,
2124 BTEqualStrategyNumber, F_OIDEQ,
2125 ObjectIdGetDatum(object->objectId));
2127 rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
2128 SnapshotNow, 1, skey);
2130 tup = systable_getnext(rcscan);
2132 if (!HeapTupleIsValid(tup))
2133 elog(ERROR, "could not find tuple for cast %u",
2136 castForm = (Form_pg_cast) GETSTRUCT(tup);
2138 appendStringInfo(&buffer, _("cast from %s to %s"),
2139 format_type_be(castForm->castsource),
2140 format_type_be(castForm->casttarget));
2142 systable_endscan(rcscan);
2143 heap_close(castDesc, AccessShareLock);
2147 case OCLASS_CONSTRAINT:
2150 Form_pg_constraint con;
2152 conTup = SearchSysCache1(CONSTROID,
2153 ObjectIdGetDatum(object->objectId));
2154 if (!HeapTupleIsValid(conTup))
2155 elog(ERROR, "cache lookup failed for constraint %u",
2157 con = (Form_pg_constraint) GETSTRUCT(conTup);
2159 if (OidIsValid(con->conrelid))
2163 initStringInfo(&rel);
2164 getRelationDescription(&rel, con->conrelid);
2165 appendStringInfo(&buffer, _("constraint %s on %s"),
2166 NameStr(con->conname), rel.data);
2171 appendStringInfo(&buffer, _("constraint %s"),
2172 NameStr(con->conname));
2175 ReleaseSysCache(conTup);
2179 case OCLASS_CONVERSION:
2183 conTup = SearchSysCache1(CONVOID,
2184 ObjectIdGetDatum(object->objectId));
2185 if (!HeapTupleIsValid(conTup))
2186 elog(ERROR, "cache lookup failed for conversion %u",
2188 appendStringInfo(&buffer, _("conversion %s"),
2189 NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
2190 ReleaseSysCache(conTup);
2194 case OCLASS_DEFAULT:
2196 Relation attrdefDesc;
2197 ScanKeyData skey[1];
2200 Form_pg_attrdef attrdef;
2201 ObjectAddress colobject;
2203 attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
2205 ScanKeyInit(&skey[0],
2206 ObjectIdAttributeNumber,
2207 BTEqualStrategyNumber, F_OIDEQ,
2208 ObjectIdGetDatum(object->objectId));
2210 adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
2211 true, SnapshotNow, 1, skey);
2213 tup = systable_getnext(adscan);
2215 if (!HeapTupleIsValid(tup))
2216 elog(ERROR, "could not find tuple for attrdef %u",
2219 attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
2221 colobject.classId = RelationRelationId;
2222 colobject.objectId = attrdef->adrelid;
2223 colobject.objectSubId = attrdef->adnum;
2225 appendStringInfo(&buffer, _("default for %s"),
2226 getObjectDescription(&colobject));
2228 systable_endscan(adscan);
2229 heap_close(attrdefDesc, AccessShareLock);
2233 case OCLASS_LANGUAGE:
2237 langTup = SearchSysCache1(LANGOID,
2238 ObjectIdGetDatum(object->objectId));
2239 if (!HeapTupleIsValid(langTup))
2240 elog(ERROR, "cache lookup failed for language %u",
2242 appendStringInfo(&buffer, _("language %s"),
2243 NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
2244 ReleaseSysCache(langTup);
2247 case OCLASS_LARGEOBJECT:
2248 appendStringInfo(&buffer, _("large object %u"),
2252 case OCLASS_OPERATOR:
2253 appendStringInfo(&buffer, _("operator %s"),
2254 format_operator(object->objectId));
2257 case OCLASS_OPCLASS:
2260 Form_pg_opclass opcForm;
2265 opcTup = SearchSysCache1(CLAOID,
2266 ObjectIdGetDatum(object->objectId));
2267 if (!HeapTupleIsValid(opcTup))
2268 elog(ERROR, "cache lookup failed for opclass %u",
2270 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
2272 amTup = SearchSysCache1(AMOID,
2273 ObjectIdGetDatum(opcForm->opcmethod));
2274 if (!HeapTupleIsValid(amTup))
2275 elog(ERROR, "cache lookup failed for access method %u",
2276 opcForm->opcmethod);
2277 amForm = (Form_pg_am) GETSTRUCT(amTup);
2279 /* Qualify the name if not visible in search path */
2280 if (OpclassIsVisible(object->objectId))
2283 nspname = get_namespace_name(opcForm->opcnamespace);
2285 appendStringInfo(&buffer, _("operator class %s for access method %s"),
2286 quote_qualified_identifier(nspname,
2287 NameStr(opcForm->opcname)),
2288 NameStr(amForm->amname));
2290 ReleaseSysCache(amTup);
2291 ReleaseSysCache(opcTup);
2295 case OCLASS_OPFAMILY:
2296 getOpFamilyDescription(&buffer, object->objectId);
2302 ScanKeyData skey[1];
2305 Form_pg_amop amopForm;
2306 StringInfoData opfam;
2308 amopDesc = heap_open(AccessMethodOperatorRelationId,
2311 ScanKeyInit(&skey[0],
2312 ObjectIdAttributeNumber,
2313 BTEqualStrategyNumber, F_OIDEQ,
2314 ObjectIdGetDatum(object->objectId));
2316 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
2317 SnapshotNow, 1, skey);
2319 tup = systable_getnext(amscan);
2321 if (!HeapTupleIsValid(tup))
2322 elog(ERROR, "could not find tuple for amop entry %u",
2325 amopForm = (Form_pg_amop) GETSTRUCT(tup);
2327 initStringInfo(&opfam);
2328 getOpFamilyDescription(&opfam, amopForm->amopfamily);
2331 * translator: %d is the operator strategy (a number), the
2332 * first %s is the textual form of the operator, and the
2333 * second %s is the description of the operator family.
2335 appendStringInfo(&buffer, _("operator %d %s of %s"),
2336 amopForm->amopstrategy,
2337 format_operator(amopForm->amopopr),
2341 systable_endscan(amscan);
2342 heap_close(amopDesc, AccessShareLock);
2348 Relation amprocDesc;
2349 ScanKeyData skey[1];
2352 Form_pg_amproc amprocForm;
2353 StringInfoData opfam;
2355 amprocDesc = heap_open(AccessMethodProcedureRelationId,
2358 ScanKeyInit(&skey[0],
2359 ObjectIdAttributeNumber,
2360 BTEqualStrategyNumber, F_OIDEQ,
2361 ObjectIdGetDatum(object->objectId));
2363 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
2364 SnapshotNow, 1, skey);
2366 tup = systable_getnext(amscan);
2368 if (!HeapTupleIsValid(tup))
2369 elog(ERROR, "could not find tuple for amproc entry %u",
2372 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
2374 initStringInfo(&opfam);
2375 getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
2378 * translator: %d is the function number, the first %s is the
2379 * textual form of the function with arguments, and the second
2380 * %s is the description of the operator family.
2382 appendStringInfo(&buffer, _("function %d %s of %s"),
2383 amprocForm->amprocnum,
2384 format_procedure(amprocForm->amproc),
2388 systable_endscan(amscan);
2389 heap_close(amprocDesc, AccessShareLock);
2393 case OCLASS_REWRITE:
2396 ScanKeyData skey[1];
2399 Form_pg_rewrite rule;
2401 ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
2403 ScanKeyInit(&skey[0],
2404 ObjectIdAttributeNumber,
2405 BTEqualStrategyNumber, F_OIDEQ,
2406 ObjectIdGetDatum(object->objectId));
2408 rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
2409 SnapshotNow, 1, skey);
2411 tup = systable_getnext(rcscan);
2413 if (!HeapTupleIsValid(tup))
2414 elog(ERROR, "could not find tuple for rule %u",
2417 rule = (Form_pg_rewrite) GETSTRUCT(tup);
2419 appendStringInfo(&buffer, _("rule %s on "),
2420 NameStr(rule->rulename));
2421 getRelationDescription(&buffer, rule->ev_class);
2423 systable_endscan(rcscan);
2424 heap_close(ruleDesc, AccessShareLock);
2428 case OCLASS_TRIGGER:
2431 ScanKeyData skey[1];
2434 Form_pg_trigger trig;
2436 trigDesc = heap_open(TriggerRelationId, AccessShareLock);
2438 ScanKeyInit(&skey[0],
2439 ObjectIdAttributeNumber,
2440 BTEqualStrategyNumber, F_OIDEQ,
2441 ObjectIdGetDatum(object->objectId));
2443 tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
2444 SnapshotNow, 1, skey);
2446 tup = systable_getnext(tgscan);
2448 if (!HeapTupleIsValid(tup))
2449 elog(ERROR, "could not find tuple for trigger %u",
2452 trig = (Form_pg_trigger) GETSTRUCT(tup);
2454 appendStringInfo(&buffer, _("trigger %s on "),
2455 NameStr(trig->tgname));
2456 getRelationDescription(&buffer, trig->tgrelid);
2458 systable_endscan(tgscan);
2459 heap_close(trigDesc, AccessShareLock);
2467 nspname = get_namespace_name(object->objectId);
2469 elog(ERROR, "cache lookup failed for namespace %u",
2471 appendStringInfo(&buffer, _("schema %s"), nspname);
2475 case OCLASS_TSPARSER:
2479 tup = SearchSysCache1(TSPARSEROID,
2480 ObjectIdGetDatum(object->objectId));
2481 if (!HeapTupleIsValid(tup))
2482 elog(ERROR, "cache lookup failed for text search parser %u",
2484 appendStringInfo(&buffer, _("text search parser %s"),
2485 NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
2486 ReleaseSysCache(tup);
2494 tup = SearchSysCache1(TSDICTOID,
2495 ObjectIdGetDatum(object->objectId));
2496 if (!HeapTupleIsValid(tup))
2497 elog(ERROR, "cache lookup failed for text search dictionary %u",
2499 appendStringInfo(&buffer, _("text search dictionary %s"),
2500 NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
2501 ReleaseSysCache(tup);
2505 case OCLASS_TSTEMPLATE:
2509 tup = SearchSysCache1(TSTEMPLATEOID,
2510 ObjectIdGetDatum(object->objectId));
2511 if (!HeapTupleIsValid(tup))
2512 elog(ERROR, "cache lookup failed for text search template %u",
2514 appendStringInfo(&buffer, _("text search template %s"),
2515 NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
2516 ReleaseSysCache(tup);
2520 case OCLASS_TSCONFIG:
2524 tup = SearchSysCache1(TSCONFIGOID,
2525 ObjectIdGetDatum(object->objectId));
2526 if (!HeapTupleIsValid(tup))
2527 elog(ERROR, "cache lookup failed for text search configuration %u",
2529 appendStringInfo(&buffer, _("text search configuration %s"),
2530 NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
2531 ReleaseSysCache(tup);
2537 appendStringInfo(&buffer, _("role %s"),
2538 GetUserNameFromId(object->objectId));
2542 case OCLASS_DATABASE:
2546 datname = get_database_name(object->objectId);
2548 elog(ERROR, "cache lookup failed for database %u",
2550 appendStringInfo(&buffer, _("database %s"), datname);
2554 case OCLASS_TBLSPACE:
2558 tblspace = get_tablespace_name(object->objectId);
2560 elog(ERROR, "cache lookup failed for tablespace %u",
2562 appendStringInfo(&buffer, _("tablespace %s"), tblspace);
2568 ForeignDataWrapper *fdw;
2570 fdw = GetForeignDataWrapper(object->objectId);
2571 appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
2575 case OCLASS_FOREIGN_SERVER:
2579 srv = GetForeignServer(object->objectId);
2580 appendStringInfo(&buffer, _("server %s"), srv->servername);
2584 case OCLASS_USER_MAPPING:
2590 tup = SearchSysCache1(USERMAPPINGOID,
2591 ObjectIdGetDatum(object->objectId));
2592 if (!HeapTupleIsValid(tup))
2593 elog(ERROR, "cache lookup failed for user mapping %u",
2596 useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
2598 ReleaseSysCache(tup);
2600 if (OidIsValid(useid))
2601 usename = GetUserNameFromId(useid);
2605 appendStringInfo(&buffer, _("user mapping for %s"), usename);
2612 ScanKeyData skey[1];
2615 Form_pg_default_acl defacl;
2617 defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
2619 ScanKeyInit(&skey[0],
2620 ObjectIdAttributeNumber,
2621 BTEqualStrategyNumber, F_OIDEQ,
2622 ObjectIdGetDatum(object->objectId));
2624 rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
2625 true, SnapshotNow, 1, skey);
2627 tup = systable_getnext(rcscan);
2629 if (!HeapTupleIsValid(tup))
2630 elog(ERROR, "could not find tuple for default ACL %u",
2633 defacl = (Form_pg_default_acl) GETSTRUCT(tup);
2635 switch (defacl->defaclobjtype)
2637 case DEFACLOBJ_RELATION:
2638 appendStringInfo(&buffer,
2639 _("default privileges on new relations belonging to role %s"),
2640 GetUserNameFromId(defacl->defaclrole));
2642 case DEFACLOBJ_SEQUENCE:
2643 appendStringInfo(&buffer,
2644 _("default privileges on new sequences belonging to role %s"),
2645 GetUserNameFromId(defacl->defaclrole));
2647 case DEFACLOBJ_FUNCTION:
2648 appendStringInfo(&buffer,
2649 _("default privileges on new functions belonging to role %s"),
2650 GetUserNameFromId(defacl->defaclrole));
2653 /* shouldn't get here */
2654 appendStringInfo(&buffer,
2655 _("default privileges belonging to role %s"),
2656 GetUserNameFromId(defacl->defaclrole));
2660 if (OidIsValid(defacl->defaclnamespace))
2662 appendStringInfo(&buffer,
2664 get_namespace_name(defacl->defaclnamespace));
2667 systable_endscan(rcscan);
2668 heap_close(defaclrel, AccessShareLock);
2673 appendStringInfo(&buffer, "unrecognized object %u %u %d",
2676 object->objectSubId);
2684 * subroutine for getObjectDescription: describe a relation
2687 getRelationDescription(StringInfo buffer, Oid relid)
2690 Form_pg_class relForm;
2694 relTup = SearchSysCache1(RELOID,
2695 ObjectIdGetDatum(relid));
2696 if (!HeapTupleIsValid(relTup))
2697 elog(ERROR, "cache lookup failed for relation %u", relid);
2698 relForm = (Form_pg_class) GETSTRUCT(relTup);
2700 /* Qualify the name if not visible in search path */
2701 if (RelationIsVisible(relid))
2704 nspname = get_namespace_name(relForm->relnamespace);
2706 relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
2708 switch (relForm->relkind)
2710 case RELKIND_RELATION:
2711 appendStringInfo(buffer, _("table %s"),
2715 appendStringInfo(buffer, _("index %s"),
2718 case RELKIND_SEQUENCE:
2719 appendStringInfo(buffer, _("sequence %s"),
2722 case RELKIND_UNCATALOGED:
2723 appendStringInfo(buffer, _("uncataloged table %s"),
2726 case RELKIND_TOASTVALUE:
2727 appendStringInfo(buffer, _("toast table %s"),
2731 appendStringInfo(buffer, _("view %s"),
2734 case RELKIND_COMPOSITE_TYPE:
2735 appendStringInfo(buffer, _("composite type %s"),
2739 /* shouldn't get here */
2740 appendStringInfo(buffer, _("relation %s"),
2745 ReleaseSysCache(relTup);
2749 * subroutine for getObjectDescription: describe an operator family
2752 getOpFamilyDescription(StringInfo buffer, Oid opfid)
2755 Form_pg_opfamily opfForm;
2760 opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
2761 if (!HeapTupleIsValid(opfTup))
2762 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
2763 opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
2765 amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
2766 if (!HeapTupleIsValid(amTup))
2767 elog(ERROR, "cache lookup failed for access method %u",
2768 opfForm->opfmethod);
2769 amForm = (Form_pg_am) GETSTRUCT(amTup);
2771 /* Qualify the name if not visible in search path */
2772 if (OpfamilyIsVisible(opfid))
2775 nspname = get_namespace_name(opfForm->opfnamespace);
2777 appendStringInfo(buffer, _("operator family %s for access method %s"),
2778 quote_qualified_identifier(nspname,
2779 NameStr(opfForm->opfname)),
2780 NameStr(amForm->amname));
2782 ReleaseSysCache(amTup);
2783 ReleaseSysCache(opfTup);