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