1 /*-------------------------------------------------------------------------
4 * Routines to support inter-object dependencies.
7 * Portions Copyright (c) 1996-2009, 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_foreign_data_wrapper.h"
37 #include "catalog/pg_foreign_server.h"
38 #include "catalog/pg_language.h"
39 #include "catalog/pg_namespace.h"
40 #include "catalog/pg_opclass.h"
41 #include "catalog/pg_operator.h"
42 #include "catalog/pg_opfamily.h"
43 #include "catalog/pg_proc.h"
44 #include "catalog/pg_rewrite.h"
45 #include "catalog/pg_tablespace.h"
46 #include "catalog/pg_trigger.h"
47 #include "catalog/pg_ts_config.h"
48 #include "catalog/pg_ts_dict.h"
49 #include "catalog/pg_ts_parser.h"
50 #include "catalog/pg_ts_template.h"
51 #include "catalog/pg_type.h"
52 #include "catalog/pg_user_mapping.h"
53 #include "commands/comment.h"
54 #include "commands/dbcommands.h"
55 #include "commands/defrem.h"
56 #include "commands/proclang.h"
57 #include "commands/schemacmds.h"
58 #include "commands/tablespace.h"
59 #include "commands/trigger.h"
60 #include "commands/typecmds.h"
61 #include "foreign/foreign.h"
62 #include "miscadmin.h"
63 #include "nodes/nodeFuncs.h"
64 #include "parser/parsetree.h"
65 #include "rewrite/rewriteRemove.h"
66 #include "storage/lmgr.h"
67 #include "utils/builtins.h"
68 #include "utils/fmgroids.h"
69 #include "utils/guc.h"
70 #include "utils/lsyscache.h"
71 #include "utils/syscache.h"
72 #include "utils/tqual.h"
76 * Deletion processing requires additional state for each ObjectAddress that
77 * it's planning to delete. For simplicity and code-sharing we make the
78 * ObjectAddresses code support arrays with or without this extra state.
82 int flags
; /* bitmask, see bit definitions below */
83 ObjectAddress dependee
; /* object whose deletion forced this one */
86 /* ObjectAddressExtra flag bits */
87 #define DEPFLAG_ORIGINAL 0x0001 /* an original deletion target */
88 #define DEPFLAG_NORMAL 0x0002 /* reached via normal dependency */
89 #define DEPFLAG_AUTO 0x0004 /* reached via auto dependency */
90 #define DEPFLAG_INTERNAL 0x0008 /* reached via internal dependency */
93 /* expansible list of ObjectAddresses */
94 struct ObjectAddresses
96 ObjectAddress
*refs
; /* => palloc'd array */
97 ObjectAddressExtra
*extras
; /* => palloc'd array, or NULL if not used */
98 int numrefs
; /* current number of references */
99 int maxrefs
; /* current size of palloc'd array(s) */
102 /* typedef ObjectAddresses appears in dependency.h */
104 /* threaded list of ObjectAddresses, for recursion detection */
105 typedef struct ObjectAddressStack
107 const ObjectAddress
*object
; /* object being visited */
108 int flags
; /* its current flag bits */
109 struct ObjectAddressStack
*next
; /* next outer stack level */
110 } ObjectAddressStack
;
112 /* for find_expr_references_walker */
115 ObjectAddresses
*addrs
; /* addresses being accumulated */
116 List
*rtables
; /* list of rangetables to resolve Vars */
117 } find_expr_references_context
;
120 * This constant table maps ObjectClasses to the corresponding catalog OIDs.
121 * See also getObjectClass().
123 static const Oid object_classes
[MAX_OCLASS
] = {
124 RelationRelationId
, /* OCLASS_CLASS */
125 ProcedureRelationId
, /* OCLASS_PROC */
126 TypeRelationId
, /* OCLASS_TYPE */
127 CastRelationId
, /* OCLASS_CAST */
128 ConstraintRelationId
, /* OCLASS_CONSTRAINT */
129 ConversionRelationId
, /* OCLASS_CONVERSION */
130 AttrDefaultRelationId
, /* OCLASS_DEFAULT */
131 LanguageRelationId
, /* OCLASS_LANGUAGE */
132 OperatorRelationId
, /* OCLASS_OPERATOR */
133 OperatorClassRelationId
, /* OCLASS_OPCLASS */
134 OperatorFamilyRelationId
, /* OCLASS_OPFAMILY */
135 AccessMethodOperatorRelationId
, /* OCLASS_AMOP */
136 AccessMethodProcedureRelationId
, /* OCLASS_AMPROC */
137 RewriteRelationId
, /* OCLASS_REWRITE */
138 TriggerRelationId
, /* OCLASS_TRIGGER */
139 NamespaceRelationId
, /* OCLASS_SCHEMA */
140 TSParserRelationId
, /* OCLASS_TSPARSER */
141 TSDictionaryRelationId
, /* OCLASS_TSDICT */
142 TSTemplateRelationId
, /* OCLASS_TSTEMPLATE */
143 TSConfigRelationId
, /* OCLASS_TSCONFIG */
144 AuthIdRelationId
, /* OCLASS_ROLE */
145 DatabaseRelationId
, /* OCLASS_DATABASE */
146 TableSpaceRelationId
/* OCLASS_TBLSPACE */
150 static void findDependentObjects(const ObjectAddress
*object
,
152 ObjectAddressStack
*stack
,
153 ObjectAddresses
*targetObjects
,
154 const ObjectAddresses
*pendingObjects
,
156 static void reportDependentObjects(const ObjectAddresses
*targetObjects
,
157 DropBehavior behavior
,
159 const ObjectAddress
*origObject
);
160 static void deleteOneObject(const ObjectAddress
*object
, Relation depRel
);
161 static void doDeletion(const ObjectAddress
*object
);
162 static void AcquireDeletionLock(const ObjectAddress
*object
);
163 static void ReleaseDeletionLock(const ObjectAddress
*object
);
164 static bool find_expr_references_walker(Node
*node
,
165 find_expr_references_context
*context
);
166 static void eliminate_duplicate_dependencies(ObjectAddresses
*addrs
);
167 static int object_address_comparator(const void *a
, const void *b
);
168 static void add_object_address(ObjectClass oclass
, Oid objectId
, int32 subId
,
169 ObjectAddresses
*addrs
);
170 static void add_exact_object_address_extra(const ObjectAddress
*object
,
171 const ObjectAddressExtra
*extra
,
172 ObjectAddresses
*addrs
);
173 static bool object_address_present_add_flags(const ObjectAddress
*object
,
175 ObjectAddresses
*addrs
);
176 static void getRelationDescription(StringInfo buffer
, Oid relid
);
177 static void getOpFamilyDescription(StringInfo buffer
, Oid opfid
);
181 * performDeletion: attempt to drop the specified object. If CASCADE
182 * behavior is specified, also drop any dependent objects (recursively).
183 * If RESTRICT behavior is specified, error out if there are any dependent
184 * objects, except for those that should be implicitly dropped anyway
185 * according to the dependency type.
187 * This is the outer control routine for all forms of DROP that drop objects
188 * that can participate in dependencies. Note that the next two routines
189 * are variants on the same theme; if you change anything here you'll likely
190 * need to fix them too.
193 performDeletion(const ObjectAddress
*object
,
194 DropBehavior behavior
)
197 ObjectAddresses
*targetObjects
;
201 * We save some cycles by opening pg_depend just once and passing the
202 * Relation pointer down to all the recursive deletion steps.
204 depRel
= heap_open(DependRelationId
, RowExclusiveLock
);
207 * Acquire deletion lock on the target object. (Ideally the caller has
208 * done this already, but many places are sloppy about it.)
210 AcquireDeletionLock(object
);
213 * Construct a list of objects to delete (ie, the given object plus
214 * everything directly or indirectly dependent on it).
216 targetObjects
= new_object_addresses();
218 findDependentObjects(object
,
220 NULL
, /* empty stack */
222 NULL
, /* no pendingObjects */
226 * Check if deletion is allowed, and report about cascaded deletes.
228 reportDependentObjects(targetObjects
,
234 * Delete all the objects in the proper order.
236 for (i
= 0; i
< targetObjects
->numrefs
; i
++)
238 ObjectAddress
*thisobj
= targetObjects
->refs
+ i
;
240 deleteOneObject(thisobj
, depRel
);
244 free_object_addresses(targetObjects
);
246 heap_close(depRel
, RowExclusiveLock
);
250 * performMultipleDeletions: Similar to performDeletion, but act on multiple
253 * The main difference from issuing multiple performDeletion calls is that the
254 * list of objects that would be implicitly dropped, for each object to be
255 * dropped, is the union of the implicit-object list for all objects. This
256 * makes each check be more relaxed.
259 performMultipleDeletions(const ObjectAddresses
*objects
,
260 DropBehavior behavior
)
263 ObjectAddresses
*targetObjects
;
266 /* No work if no objects... */
267 if (objects
->numrefs
<= 0)
271 * We save some cycles by opening pg_depend just once and passing the
272 * Relation pointer down to all the recursive deletion steps.
274 depRel
= heap_open(DependRelationId
, RowExclusiveLock
);
277 * Construct a list of objects to delete (ie, the given objects plus
278 * everything directly or indirectly dependent on them). Note that
279 * because we pass the whole objects list as pendingObjects context, we
280 * won't get a failure from trying to delete an object that is internally
281 * dependent on another one in the list; we'll just skip that object and
282 * delete it when we reach its owner.
284 targetObjects
= new_object_addresses();
286 for (i
= 0; i
< objects
->numrefs
; i
++)
288 const ObjectAddress
*thisobj
= objects
->refs
+ i
;
291 * Acquire deletion lock on each target object. (Ideally the caller
292 * has done this already, but many places are sloppy about it.)
294 AcquireDeletionLock(thisobj
);
296 findDependentObjects(thisobj
,
298 NULL
, /* empty stack */
305 * Check if deletion is allowed, and report about cascaded deletes.
307 * If there's exactly one object being deleted, report it the same way as
308 * in performDeletion(), else we have to be vaguer.
310 reportDependentObjects(targetObjects
,
313 (objects
->numrefs
== 1 ? objects
->refs
: NULL
));
316 * Delete all the objects in the proper order.
318 for (i
= 0; i
< targetObjects
->numrefs
; i
++)
320 ObjectAddress
*thisobj
= targetObjects
->refs
+ i
;
322 deleteOneObject(thisobj
, depRel
);
326 free_object_addresses(targetObjects
);
328 heap_close(depRel
, RowExclusiveLock
);
332 * deleteWhatDependsOn: attempt to drop everything that depends on the
333 * specified object, though not the object itself. Behavior is always
336 * This is currently used only to clean out the contents of a schema
337 * (namespace): the passed object is a namespace. We normally want this
338 * to be done silently, so there's an option to suppress NOTICE messages.
341 deleteWhatDependsOn(const ObjectAddress
*object
,
345 ObjectAddresses
*targetObjects
;
349 * We save some cycles by opening pg_depend just once and passing the
350 * Relation pointer down to all the recursive deletion steps.
352 depRel
= heap_open(DependRelationId
, RowExclusiveLock
);
355 * Acquire deletion lock on the target object. (Ideally the caller has
356 * done this already, but many places are sloppy about it.)
358 AcquireDeletionLock(object
);
361 * Construct a list of objects to delete (ie, the given object plus
362 * everything directly or indirectly dependent on it).
364 targetObjects
= new_object_addresses();
366 findDependentObjects(object
,
368 NULL
, /* empty stack */
370 NULL
, /* no pendingObjects */
374 * Check if deletion is allowed, and report about cascaded deletes.
376 reportDependentObjects(targetObjects
,
378 showNotices
? NOTICE
: DEBUG2
,
382 * Delete all the objects in the proper order, except we skip the original
385 for (i
= 0; i
< targetObjects
->numrefs
; i
++)
387 ObjectAddress
*thisobj
= targetObjects
->refs
+ i
;
388 ObjectAddressExtra
*thisextra
= targetObjects
->extras
+ i
;
390 if (thisextra
->flags
& DEPFLAG_ORIGINAL
)
393 deleteOneObject(thisobj
, depRel
);
397 free_object_addresses(targetObjects
);
399 heap_close(depRel
, RowExclusiveLock
);
403 * findDependentObjects - find all objects that depend on 'object'
405 * For every object that depends on the starting object, acquire a deletion
406 * lock on the object, add it to targetObjects (if not already there),
407 * and recursively find objects that depend on it. An object's dependencies
408 * will be placed into targetObjects before the object itself; this means
409 * that the finished list's order represents a safe deletion order.
411 * The caller must already have a deletion lock on 'object' itself,
412 * but must not have added it to targetObjects. (Note: there are corner
413 * cases where we won't add the object either, and will also release the
414 * caller-taken lock. This is a bit ugly, but the API is set up this way
415 * to allow easy rechecking of an object's liveness after we lock it. See
416 * notes within the function.)
418 * When dropping a whole object (subId = 0), we find dependencies for
419 * its sub-objects too.
421 * object: the object to add to targetObjects and find dependencies on
422 * flags: flags to be ORed into the object's targetObjects entry
423 * stack: list of objects being visited in current recursion; topmost item
424 * is the object that we recursed from (NULL for external callers)
425 * targetObjects: list of objects that are scheduled to be deleted
426 * pendingObjects: list of other objects slated for destruction, but
427 * not necessarily in targetObjects yet (can be NULL if none)
428 * depRel: already opened pg_depend relation
431 findDependentObjects(const ObjectAddress
*object
,
433 ObjectAddressStack
*stack
,
434 ObjectAddresses
*targetObjects
,
435 const ObjectAddresses
*pendingObjects
,
442 ObjectAddress otherObject
;
443 ObjectAddressStack mystack
;
444 ObjectAddressExtra extra
;
445 ObjectAddressStack
*stackptr
;
448 * If the target object is already being visited in an outer recursion
449 * level, just report the current flags back to that level and exit. This
450 * is needed to avoid infinite recursion in the face of circular
453 * The stack check alone would result in dependency loops being broken at
454 * an arbitrary point, ie, the first member object of the loop to be
455 * visited is the last one to be deleted. This is obviously unworkable.
456 * However, the check for internal dependency below guarantees that we
457 * will not break a loop at an internal dependency: if we enter the loop
458 * at an "owned" object we will switch and start at the "owning" object
459 * instead. We could probably hack something up to avoid breaking at an
460 * auto dependency, too, if we had to. However there are no known cases
461 * where that would be necessary.
463 for (stackptr
= stack
; stackptr
; stackptr
= stackptr
->next
)
465 if (object
->classId
== stackptr
->object
->classId
&&
466 object
->objectId
== stackptr
->object
->objectId
)
468 if (object
->objectSubId
== stackptr
->object
->objectSubId
)
470 stackptr
->flags
|= flags
;
475 * Could visit column with whole table already on stack; this is
476 * the same case noted in object_address_present_add_flags().
477 * (It's not clear this can really happen, but we might as well
480 if (stackptr
->object
->objectSubId
== 0)
486 * It's also possible that the target object has already been completely
487 * processed and put into targetObjects. If so, again we just add the
488 * specified flags to its entry and return.
490 * (Note: in these early-exit cases we could release the caller-taken
491 * lock, since the object is presumably now locked multiple times; but it
492 * seems not worth the cycles.)
494 if (object_address_present_add_flags(object
, flags
, targetObjects
))
498 * The target object might be internally dependent on some other object
499 * (its "owner"). If so, and if we aren't recursing from the owning
500 * object, we have to transform this deletion request into a deletion
501 * request of the owning object. (We'll eventually recurse back to this
502 * object, but the owning object has to be visited first so it will be
503 * deleted after.) The way to find out about this is to scan the
504 * pg_depend entries that show what this object depends on.
507 Anum_pg_depend_classid
,
508 BTEqualStrategyNumber
, F_OIDEQ
,
509 ObjectIdGetDatum(object
->classId
));
511 Anum_pg_depend_objid
,
512 BTEqualStrategyNumber
, F_OIDEQ
,
513 ObjectIdGetDatum(object
->objectId
));
514 if (object
->objectSubId
!= 0)
517 Anum_pg_depend_objsubid
,
518 BTEqualStrategyNumber
, F_INT4EQ
,
519 Int32GetDatum(object
->objectSubId
));
525 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
526 SnapshotNow
, nkeys
, key
);
528 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
530 Form_pg_depend foundDep
= (Form_pg_depend
) GETSTRUCT(tup
);
532 otherObject
.classId
= foundDep
->refclassid
;
533 otherObject
.objectId
= foundDep
->refobjid
;
534 otherObject
.objectSubId
= foundDep
->refobjsubid
;
536 switch (foundDep
->deptype
)
538 case DEPENDENCY_NORMAL
:
539 case DEPENDENCY_AUTO
:
542 case DEPENDENCY_INTERNAL
:
545 * This object is part of the internal implementation of
546 * another object. We have three cases:
548 * 1. At the outermost recursion level, disallow the DROP. (We
549 * just ereport here, rather than proceeding, since no other
550 * dependencies are likely to be interesting.) However, if
551 * the other object is listed in pendingObjects, just release
552 * the caller's lock and return; we'll eventually complete the
553 * DROP when we reach that entry in the pending list.
559 if (object_address_present(&otherObject
, pendingObjects
))
561 systable_endscan(scan
);
562 /* need to release caller's lock; see notes below */
563 ReleaseDeletionLock(object
);
566 otherObjDesc
= getObjectDescription(&otherObject
);
568 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST
),
569 errmsg("cannot drop %s because %s requires it",
570 getObjectDescription(object
),
572 errhint("You can drop %s instead.",
577 * 2. When recursing from the other end of this dependency,
578 * it's okay to continue with the deletion. This holds when
579 * recursing from a whole object that includes the nominal
580 * other end as a component, too.
582 if (stack
->object
->classId
== otherObject
.classId
&&
583 stack
->object
->objectId
== otherObject
.objectId
&&
584 (stack
->object
->objectSubId
== otherObject
.objectSubId
||
585 stack
->object
->objectSubId
== 0))
589 * 3. When recursing from anyplace else, transform this
590 * deletion request into a delete of the other object.
592 * First, release caller's lock on this object and get
593 * deletion lock on the other object. (We must release
594 * caller's lock to avoid deadlock against a concurrent
595 * deletion of the other object.)
597 ReleaseDeletionLock(object
);
598 AcquireDeletionLock(&otherObject
);
601 * The other object might have been deleted while we waited to
602 * lock it; if so, neither it nor the current object are
603 * interesting anymore. We test this by checking the
604 * pg_depend entry (see notes below).
606 if (!systable_recheck_tuple(scan
, tup
))
608 systable_endscan(scan
);
609 ReleaseDeletionLock(&otherObject
);
614 * Okay, recurse to the other object instead of proceeding. We
615 * treat this exactly as if the original reference had linked
616 * to that object instead of this one; hence, pass through the
617 * same flags and stack.
619 findDependentObjects(&otherObject
,
625 /* And we're done here. */
626 systable_endscan(scan
);
631 * Should not happen; PIN dependencies should have zeroes in
632 * the depender fields...
634 elog(ERROR
, "incorrect use of PIN dependency with %s",
635 getObjectDescription(object
));
638 elog(ERROR
, "unrecognized dependency type '%c' for %s",
639 foundDep
->deptype
, getObjectDescription(object
));
644 systable_endscan(scan
);
647 * Now recurse to any dependent objects. We must visit them first since
648 * they have to be deleted before the current object.
650 mystack
.object
= object
; /* set up a new stack level */
651 mystack
.flags
= flags
;
652 mystack
.next
= stack
;
655 Anum_pg_depend_refclassid
,
656 BTEqualStrategyNumber
, F_OIDEQ
,
657 ObjectIdGetDatum(object
->classId
));
659 Anum_pg_depend_refobjid
,
660 BTEqualStrategyNumber
, F_OIDEQ
,
661 ObjectIdGetDatum(object
->objectId
));
662 if (object
->objectSubId
!= 0)
665 Anum_pg_depend_refobjsubid
,
666 BTEqualStrategyNumber
, F_INT4EQ
,
667 Int32GetDatum(object
->objectSubId
));
673 scan
= systable_beginscan(depRel
, DependReferenceIndexId
, true,
674 SnapshotNow
, nkeys
, key
);
676 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
678 Form_pg_depend foundDep
= (Form_pg_depend
) GETSTRUCT(tup
);
681 otherObject
.classId
= foundDep
->classid
;
682 otherObject
.objectId
= foundDep
->objid
;
683 otherObject
.objectSubId
= foundDep
->objsubid
;
686 * Must lock the dependent object before recursing to it.
688 AcquireDeletionLock(&otherObject
);
691 * The dependent object might have been deleted while we waited to
692 * lock it; if so, we don't need to do anything more with it. We can
693 * test this cheaply and independently of the object's type by seeing
694 * if the pg_depend tuple we are looking at is still live. (If the
695 * object got deleted, the tuple would have been deleted too.)
697 if (!systable_recheck_tuple(scan
, tup
))
699 /* release the now-useless lock */
700 ReleaseDeletionLock(&otherObject
);
701 /* and continue scanning for dependencies */
705 /* Recurse, passing flags indicating the dependency type */
706 switch (foundDep
->deptype
)
708 case DEPENDENCY_NORMAL
:
709 subflags
= DEPFLAG_NORMAL
;
711 case DEPENDENCY_AUTO
:
712 subflags
= DEPFLAG_AUTO
;
714 case DEPENDENCY_INTERNAL
:
715 subflags
= DEPFLAG_INTERNAL
;
720 * For a PIN dependency we just ereport immediately; there
721 * won't be any others to report.
724 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST
),
725 errmsg("cannot drop %s because it is required by the database system",
726 getObjectDescription(object
))));
727 subflags
= 0; /* keep compiler quiet */
730 elog(ERROR
, "unrecognized dependency type '%c' for %s",
731 foundDep
->deptype
, getObjectDescription(object
));
732 subflags
= 0; /* keep compiler quiet */
736 findDependentObjects(&otherObject
,
744 systable_endscan(scan
);
747 * Finally, we can add the target object to targetObjects. Be careful to
748 * include any flags that were passed back down to us from inner recursion
751 extra
.flags
= mystack
.flags
;
753 extra
.dependee
= *stack
->object
;
755 memset(&extra
.dependee
, 0, sizeof(extra
.dependee
));
756 add_exact_object_address_extra(object
, &extra
, targetObjects
);
760 * reportDependentObjects - report about dependencies, and fail if RESTRICT
762 * Tell the user about dependent objects that we are going to delete
763 * (or would need to delete, but are prevented by RESTRICT mode);
764 * then error out if there are any and it's not CASCADE mode.
766 * targetObjects: list of objects that are scheduled to be deleted
767 * behavior: RESTRICT or CASCADE
768 * msglevel: elog level for non-error report messages
769 * origObject: base object of deletion, or NULL if not available
770 * (the latter case occurs in DROP OWNED)
773 reportDependentObjects(const ObjectAddresses
*targetObjects
,
774 DropBehavior behavior
,
776 const ObjectAddress
*origObject
)
779 StringInfoData clientdetail
;
780 StringInfoData logdetail
;
781 int numReportedClient
= 0;
782 int numNotReportedClient
= 0;
786 * If no error is to be thrown, and the msglevel is too low to be shown to
787 * either client or server log, there's no need to do any of the work.
789 * Note: this code doesn't know all there is to be known about elog
790 * levels, but it works for NOTICE and DEBUG2, which are the only values
791 * msglevel can currently have. We also assume we are running in a normal
792 * operating environment.
794 if (behavior
== DROP_CASCADE
&&
795 msglevel
< client_min_messages
&&
796 (msglevel
< log_min_messages
|| log_min_messages
== LOG
))
800 * We limit the number of dependencies reported to the client to
801 * MAX_REPORTED_DEPS, since client software may not deal well with
802 * enormous error strings. The server log always gets a full report.
804 #define MAX_REPORTED_DEPS 100
806 initStringInfo(&clientdetail
);
807 initStringInfo(&logdetail
);
810 * We process the list back to front (ie, in dependency order not deletion
811 * order), since this makes for a more understandable display.
813 for (i
= targetObjects
->numrefs
- 1; i
>= 0; i
--)
815 const ObjectAddress
*obj
= &targetObjects
->refs
[i
];
816 const ObjectAddressExtra
*extra
= &targetObjects
->extras
[i
];
819 /* Ignore the original deletion target(s) */
820 if (extra
->flags
& DEPFLAG_ORIGINAL
)
823 objDesc
= getObjectDescription(obj
);
826 * If, at any stage of the recursive search, we reached the object via
827 * an AUTO or INTERNAL dependency, then it's okay to delete it even in
830 if (extra
->flags
& (DEPFLAG_AUTO
| DEPFLAG_INTERNAL
))
833 * auto-cascades are reported at DEBUG2, not msglevel. We don't
834 * try to combine them with the regular message because the
835 * results are too confusing when client_min_messages and
836 * log_min_messages are different.
839 (errmsg("drop auto-cascades to %s",
842 else if (behavior
== DROP_RESTRICT
)
844 char *otherDesc
= getObjectDescription(&extra
->dependee
);
846 if (numReportedClient
< MAX_REPORTED_DEPS
)
848 /* separate entries with a newline */
849 if (clientdetail
.len
!= 0)
850 appendStringInfoChar(&clientdetail
, '\n');
851 appendStringInfo(&clientdetail
, _("%s depends on %s"),
856 numNotReportedClient
++;
857 /* separate entries with a newline */
858 if (logdetail
.len
!= 0)
859 appendStringInfoChar(&logdetail
, '\n');
860 appendStringInfo(&logdetail
, _("%s depends on %s"),
867 if (numReportedClient
< MAX_REPORTED_DEPS
)
869 /* separate entries with a newline */
870 if (clientdetail
.len
!= 0)
871 appendStringInfoChar(&clientdetail
, '\n');
872 appendStringInfo(&clientdetail
, _("drop cascades to %s"),
877 numNotReportedClient
++;
878 /* separate entries with a newline */
879 if (logdetail
.len
!= 0)
880 appendStringInfoChar(&logdetail
, '\n');
881 appendStringInfo(&logdetail
, _("drop cascades to %s"),
888 if (numNotReportedClient
> 0)
889 appendStringInfo(&clientdetail
, ngettext("\nand %d other object "
890 "(see server log for list)",
891 "\nand %d other objects "
892 "(see server log for list)",
893 numNotReportedClient
),
894 numNotReportedClient
);
900 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST
),
901 errmsg("cannot drop %s because other objects depend on it",
902 getObjectDescription(origObject
)),
903 errdetail("%s", clientdetail
.data
),
904 errdetail_log("%s", logdetail
.data
),
905 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
908 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST
),
909 errmsg("cannot drop desired object(s) because other objects depend on them"),
910 errdetail("%s", clientdetail
.data
),
911 errdetail_log("%s", logdetail
.data
),
912 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
914 else if (numReportedClient
> 1)
917 /* translator: %d always has a value larger than 1 */
918 (errmsg_plural("drop cascades to %d other object",
919 "drop cascades to %d other objects",
920 numReportedClient
+ numNotReportedClient
,
921 numReportedClient
+ numNotReportedClient
),
922 errdetail("%s", clientdetail
.data
),
923 errdetail_log("%s", logdetail
.data
)));
925 else if (numReportedClient
== 1)
927 /* we just use the single item as-is */
929 (errmsg_internal("%s", clientdetail
.data
)));
932 pfree(clientdetail
.data
);
933 pfree(logdetail
.data
);
937 * deleteOneObject: delete a single object for performDeletion.
939 * depRel is the already-open pg_depend relation.
942 deleteOneObject(const ObjectAddress
*object
, Relation depRel
)
950 * First remove any pg_depend records that link from this object to
951 * others. (Any records linking to this object should be gone already.)
953 * When dropping a whole object (subId = 0), remove all pg_depend records
954 * for its sub-objects too.
957 Anum_pg_depend_classid
,
958 BTEqualStrategyNumber
, F_OIDEQ
,
959 ObjectIdGetDatum(object
->classId
));
961 Anum_pg_depend_objid
,
962 BTEqualStrategyNumber
, F_OIDEQ
,
963 ObjectIdGetDatum(object
->objectId
));
964 if (object
->objectSubId
!= 0)
967 Anum_pg_depend_objsubid
,
968 BTEqualStrategyNumber
, F_INT4EQ
,
969 Int32GetDatum(object
->objectSubId
));
975 scan
= systable_beginscan(depRel
, DependDependerIndexId
, true,
976 SnapshotNow
, nkeys
, key
);
978 while (HeapTupleIsValid(tup
= systable_getnext(scan
)))
980 simple_heap_delete(depRel
, &tup
->t_self
);
983 systable_endscan(scan
);
986 * Delete shared dependency references related to this object. Again, if
987 * subId = 0, remove records for sub-objects too.
989 deleteSharedDependencyRecordsFor(object
->classId
, object
->objectId
,
990 object
->objectSubId
);
993 * Now delete the object itself, in an object-type-dependent way.
998 * Delete any comments associated with this object. (This is a convenient
999 * place to do it instead of having every object type know to do it.)
1001 DeleteComments(object
->objectId
, object
->classId
, object
->objectSubId
);
1004 * CommandCounterIncrement here to ensure that preceding changes are all
1005 * visible to the next deletion step.
1007 CommandCounterIncrement();
1015 * doDeletion: actually delete a single object
1018 doDeletion(const ObjectAddress
*object
)
1020 switch (getObjectClass(object
))
1024 char relKind
= get_rel_relkind(object
->objectId
);
1026 if (relKind
== RELKIND_INDEX
)
1028 Assert(object
->objectSubId
== 0);
1029 index_drop(object
->objectId
);
1033 if (object
->objectSubId
!= 0)
1034 RemoveAttributeById(object
->objectId
,
1035 object
->objectSubId
);
1037 heap_drop_with_catalog(object
->objectId
);
1043 RemoveFunctionById(object
->objectId
);
1047 RemoveTypeById(object
->objectId
);
1051 DropCastById(object
->objectId
);
1054 case OCLASS_CONSTRAINT
:
1055 RemoveConstraintById(object
->objectId
);
1058 case OCLASS_CONVERSION
:
1059 RemoveConversionById(object
->objectId
);
1062 case OCLASS_DEFAULT
:
1063 RemoveAttrDefaultById(object
->objectId
);
1066 case OCLASS_LANGUAGE
:
1067 DropProceduralLanguageById(object
->objectId
);
1070 case OCLASS_OPERATOR
:
1071 RemoveOperatorById(object
->objectId
);
1074 case OCLASS_OPCLASS
:
1075 RemoveOpClassById(object
->objectId
);
1078 case OCLASS_OPFAMILY
:
1079 RemoveOpFamilyById(object
->objectId
);
1083 RemoveAmOpEntryById(object
->objectId
);
1087 RemoveAmProcEntryById(object
->objectId
);
1090 case OCLASS_REWRITE
:
1091 RemoveRewriteRuleById(object
->objectId
);
1094 case OCLASS_TRIGGER
:
1095 RemoveTriggerById(object
->objectId
);
1099 RemoveSchemaById(object
->objectId
);
1102 case OCLASS_TSPARSER
:
1103 RemoveTSParserById(object
->objectId
);
1107 RemoveTSDictionaryById(object
->objectId
);
1110 case OCLASS_TSTEMPLATE
:
1111 RemoveTSTemplateById(object
->objectId
);
1114 case OCLASS_TSCONFIG
:
1115 RemoveTSConfigurationById(object
->objectId
);
1118 case OCLASS_USER_MAPPING
:
1119 RemoveUserMappingById(object
->objectId
);
1122 case OCLASS_FOREIGN_SERVER
:
1123 RemoveForeignServerById(object
->objectId
);
1127 RemoveForeignDataWrapperById(object
->objectId
);
1130 /* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
1133 elog(ERROR
, "unrecognized object class: %u",
1139 * AcquireDeletionLock - acquire a suitable lock for deleting an object
1141 * We use LockRelation for relations, LockDatabaseObject for everything
1142 * else. Note that dependency.c is not concerned with deleting any kind of
1143 * shared-across-databases object, so we have no need for LockSharedObject.
1146 AcquireDeletionLock(const ObjectAddress
*object
)
1148 if (object
->classId
== RelationRelationId
)
1149 LockRelationOid(object
->objectId
, AccessExclusiveLock
);
1151 /* assume we should lock the whole object not a sub-object */
1152 LockDatabaseObject(object
->classId
, object
->objectId
, 0,
1153 AccessExclusiveLock
);
1157 * ReleaseDeletionLock - release an object deletion lock
1160 ReleaseDeletionLock(const ObjectAddress
*object
)
1162 if (object
->classId
== RelationRelationId
)
1163 UnlockRelationOid(object
->objectId
, AccessExclusiveLock
);
1165 /* assume we should lock the whole object not a sub-object */
1166 UnlockDatabaseObject(object
->classId
, object
->objectId
, 0,
1167 AccessExclusiveLock
);
1171 * recordDependencyOnExpr - find expression dependencies
1173 * This is used to find the dependencies of rules, constraint expressions,
1176 * Given an expression or query in node-tree form, find all the objects
1177 * it refers to (tables, columns, operators, functions, etc). Record
1178 * a dependency of the specified type from the given depender object
1179 * to each object mentioned in the expression.
1181 * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
1182 * It can be NIL if no such variables are expected.
1185 recordDependencyOnExpr(const ObjectAddress
*depender
,
1186 Node
*expr
, List
*rtable
,
1187 DependencyType behavior
)
1189 find_expr_references_context context
;
1191 context
.addrs
= new_object_addresses();
1193 /* Set up interpretation for Vars at varlevelsup = 0 */
1194 context
.rtables
= list_make1(rtable
);
1196 /* Scan the expression tree for referenceable objects */
1197 find_expr_references_walker(expr
, &context
);
1199 /* Remove any duplicates */
1200 eliminate_duplicate_dependencies(context
.addrs
);
1202 /* And record 'em */
1203 recordMultipleDependencies(depender
,
1204 context
.addrs
->refs
, context
.addrs
->numrefs
,
1207 free_object_addresses(context
.addrs
);
1211 * recordDependencyOnSingleRelExpr - find expression dependencies
1213 * As above, but only one relation is expected to be referenced (with
1214 * varno = 1 and varlevelsup = 0). Pass the relation OID instead of a
1215 * range table. An additional frammish is that dependencies on that
1216 * relation (or its component columns) will be marked with 'self_behavior',
1217 * whereas 'behavior' is used for everything else.
1220 recordDependencyOnSingleRelExpr(const ObjectAddress
*depender
,
1221 Node
*expr
, Oid relId
,
1222 DependencyType behavior
,
1223 DependencyType self_behavior
)
1225 find_expr_references_context context
;
1228 context
.addrs
= new_object_addresses();
1230 /* We gin up a rather bogus rangetable list to handle Vars */
1231 MemSet(&rte
, 0, sizeof(rte
));
1232 rte
.type
= T_RangeTblEntry
;
1233 rte
.rtekind
= RTE_RELATION
;
1236 context
.rtables
= list_make1(list_make1(&rte
));
1238 /* Scan the expression tree for referenceable objects */
1239 find_expr_references_walker(expr
, &context
);
1241 /* Remove any duplicates */
1242 eliminate_duplicate_dependencies(context
.addrs
);
1244 /* Separate self-dependencies if necessary */
1245 if (behavior
!= self_behavior
&& context
.addrs
->numrefs
> 0)
1247 ObjectAddresses
*self_addrs
;
1248 ObjectAddress
*outobj
;
1252 self_addrs
= new_object_addresses();
1254 outobj
= context
.addrs
->refs
;
1256 for (oldref
= 0; oldref
< context
.addrs
->numrefs
; oldref
++)
1258 ObjectAddress
*thisobj
= context
.addrs
->refs
+ oldref
;
1260 if (thisobj
->classId
== RelationRelationId
&&
1261 thisobj
->objectId
== relId
)
1263 /* Move this ref into self_addrs */
1264 add_exact_object_address(thisobj
, self_addrs
);
1268 /* Keep it in context.addrs */
1274 context
.addrs
->numrefs
= outrefs
;
1276 /* Record the self-dependencies */
1277 recordMultipleDependencies(depender
,
1278 self_addrs
->refs
, self_addrs
->numrefs
,
1281 free_object_addresses(self_addrs
);
1284 /* Record the external dependencies */
1285 recordMultipleDependencies(depender
,
1286 context
.addrs
->refs
, context
.addrs
->numrefs
,
1289 free_object_addresses(context
.addrs
);
1293 * Recursively search an expression tree for object references.
1295 * Note: we avoid creating references to columns of tables that participate
1296 * in an SQL JOIN construct, but are not actually used anywhere in the query.
1297 * To do so, we do not scan the joinaliasvars list of a join RTE while
1298 * scanning the query rangetable, but instead scan each individual entry
1299 * of the alias list when we find a reference to it.
1301 * Note: in many cases we do not need to create dependencies on the datatypes
1302 * involved in an expression, because we'll have an indirect dependency via
1303 * some other object. For instance Var nodes depend on a column which depends
1304 * on the datatype, and OpExpr nodes depend on the operator which depends on
1305 * the datatype. However we do need a type dependency if there is no such
1306 * indirect dependency, as for example in Const and CoerceToDomain nodes.
1309 find_expr_references_walker(Node
*node
,
1310 find_expr_references_context
*context
)
1316 Var
*var
= (Var
*) node
;
1320 /* Find matching rtable entry, or complain if not found */
1321 if (var
->varlevelsup
>= list_length(context
->rtables
))
1322 elog(ERROR
, "invalid varlevelsup %d", var
->varlevelsup
);
1323 rtable
= (List
*) list_nth(context
->rtables
, var
->varlevelsup
);
1324 if (var
->varno
<= 0 || var
->varno
> list_length(rtable
))
1325 elog(ERROR
, "invalid varno %d", var
->varno
);
1326 rte
= rt_fetch(var
->varno
, rtable
);
1329 * A whole-row Var references no specific columns, so adds no new
1332 if (var
->varattno
== InvalidAttrNumber
)
1334 if (rte
->rtekind
== RTE_RELATION
)
1336 /* If it's a plain relation, reference this column */
1337 add_object_address(OCLASS_CLASS
, rte
->relid
, var
->varattno
,
1340 else if (rte
->rtekind
== RTE_JOIN
)
1342 /* Scan join output column to add references to join inputs */
1345 /* We must make the context appropriate for join's level */
1346 save_rtables
= context
->rtables
;
1347 context
->rtables
= list_copy_tail(context
->rtables
,
1349 if (var
->varattno
<= 0 ||
1350 var
->varattno
> list_length(rte
->joinaliasvars
))
1351 elog(ERROR
, "invalid varattno %d", var
->varattno
);
1352 find_expr_references_walker((Node
*) list_nth(rte
->joinaliasvars
,
1355 list_free(context
->rtables
);
1356 context
->rtables
= save_rtables
;
1360 else if (IsA(node
, Const
))
1362 Const
*con
= (Const
*) node
;
1365 /* A constant must depend on the constant's datatype */
1366 add_object_address(OCLASS_TYPE
, con
->consttype
, 0,
1370 * If it's a regclass or similar literal referring to an existing
1371 * object, add a reference to that object. (Currently, only the
1372 * regclass and regconfig cases have any likely use, but we may as
1373 * well handle all the OID-alias datatypes consistently.)
1375 if (!con
->constisnull
)
1377 switch (con
->consttype
)
1380 case REGPROCEDUREOID
:
1381 objoid
= DatumGetObjectId(con
->constvalue
);
1382 if (SearchSysCacheExists(PROCOID
,
1383 ObjectIdGetDatum(objoid
),
1385 add_object_address(OCLASS_PROC
, objoid
, 0,
1389 case REGOPERATOROID
:
1390 objoid
= DatumGetObjectId(con
->constvalue
);
1391 if (SearchSysCacheExists(OPEROID
,
1392 ObjectIdGetDatum(objoid
),
1394 add_object_address(OCLASS_OPERATOR
, objoid
, 0,
1398 objoid
= DatumGetObjectId(con
->constvalue
);
1399 if (SearchSysCacheExists(RELOID
,
1400 ObjectIdGetDatum(objoid
),
1402 add_object_address(OCLASS_CLASS
, objoid
, 0,
1406 objoid
= DatumGetObjectId(con
->constvalue
);
1407 if (SearchSysCacheExists(TYPEOID
,
1408 ObjectIdGetDatum(objoid
),
1410 add_object_address(OCLASS_TYPE
, objoid
, 0,
1414 objoid
= DatumGetObjectId(con
->constvalue
);
1415 if (SearchSysCacheExists(TSCONFIGOID
,
1416 ObjectIdGetDatum(objoid
),
1418 add_object_address(OCLASS_TSCONFIG
, objoid
, 0,
1421 case REGDICTIONARYOID
:
1422 objoid
= DatumGetObjectId(con
->constvalue
);
1423 if (SearchSysCacheExists(TSDICTOID
,
1424 ObjectIdGetDatum(objoid
),
1426 add_object_address(OCLASS_TSDICT
, objoid
, 0,
1433 else if (IsA(node
, Param
))
1435 Param
*param
= (Param
*) node
;
1437 /* A parameter must depend on the parameter's datatype */
1438 add_object_address(OCLASS_TYPE
, param
->paramtype
, 0,
1441 else if (IsA(node
, FuncExpr
))
1443 FuncExpr
*funcexpr
= (FuncExpr
*) node
;
1445 add_object_address(OCLASS_PROC
, funcexpr
->funcid
, 0,
1447 /* fall through to examine arguments */
1449 else if (IsA(node
, OpExpr
))
1451 OpExpr
*opexpr
= (OpExpr
*) node
;
1453 add_object_address(OCLASS_OPERATOR
, opexpr
->opno
, 0,
1455 /* fall through to examine arguments */
1457 else if (IsA(node
, DistinctExpr
))
1459 DistinctExpr
*distinctexpr
= (DistinctExpr
*) node
;
1461 add_object_address(OCLASS_OPERATOR
, distinctexpr
->opno
, 0,
1463 /* fall through to examine arguments */
1465 else if (IsA(node
, ScalarArrayOpExpr
))
1467 ScalarArrayOpExpr
*opexpr
= (ScalarArrayOpExpr
*) node
;
1469 add_object_address(OCLASS_OPERATOR
, opexpr
->opno
, 0,
1471 /* fall through to examine arguments */
1473 else if (IsA(node
, NullIfExpr
))
1475 NullIfExpr
*nullifexpr
= (NullIfExpr
*) node
;
1477 add_object_address(OCLASS_OPERATOR
, nullifexpr
->opno
, 0,
1479 /* fall through to examine arguments */
1481 else if (IsA(node
, Aggref
))
1483 Aggref
*aggref
= (Aggref
*) node
;
1485 add_object_address(OCLASS_PROC
, aggref
->aggfnoid
, 0,
1487 /* fall through to examine arguments */
1489 else if (IsA(node
, WindowFunc
))
1491 WindowFunc
*wfunc
= (WindowFunc
*) node
;
1493 add_object_address(OCLASS_PROC
, wfunc
->winfnoid
, 0,
1495 /* fall through to examine arguments */
1497 else if (IsA(node
, SubPlan
))
1499 /* Extra work needed here if we ever need this case */
1500 elog(ERROR
, "already-planned subqueries not supported");
1502 else if (IsA(node
, RelabelType
))
1504 RelabelType
*relab
= (RelabelType
*) node
;
1506 /* since there is no function dependency, need to depend on type */
1507 add_object_address(OCLASS_TYPE
, relab
->resulttype
, 0,
1510 else if (IsA(node
, CoerceViaIO
))
1512 CoerceViaIO
*iocoerce
= (CoerceViaIO
*) node
;
1514 /* since there is no exposed function, need to depend on type */
1515 add_object_address(OCLASS_TYPE
, iocoerce
->resulttype
, 0,
1518 else if (IsA(node
, ArrayCoerceExpr
))
1520 ArrayCoerceExpr
*acoerce
= (ArrayCoerceExpr
*) node
;
1522 if (OidIsValid(acoerce
->elemfuncid
))
1523 add_object_address(OCLASS_PROC
, acoerce
->elemfuncid
, 0,
1525 add_object_address(OCLASS_TYPE
, acoerce
->resulttype
, 0,
1527 /* fall through to examine arguments */
1529 else if (IsA(node
, ConvertRowtypeExpr
))
1531 ConvertRowtypeExpr
*cvt
= (ConvertRowtypeExpr
*) node
;
1533 /* since there is no function dependency, need to depend on type */
1534 add_object_address(OCLASS_TYPE
, cvt
->resulttype
, 0,
1537 else if (IsA(node
, RowExpr
))
1539 RowExpr
*rowexpr
= (RowExpr
*) node
;
1541 add_object_address(OCLASS_TYPE
, rowexpr
->row_typeid
, 0,
1544 else if (IsA(node
, RowCompareExpr
))
1546 RowCompareExpr
*rcexpr
= (RowCompareExpr
*) node
;
1549 foreach(l
, rcexpr
->opnos
)
1551 add_object_address(OCLASS_OPERATOR
, lfirst_oid(l
), 0,
1554 foreach(l
, rcexpr
->opfamilies
)
1556 add_object_address(OCLASS_OPFAMILY
, lfirst_oid(l
), 0,
1559 /* fall through to examine arguments */
1561 else if (IsA(node
, CoerceToDomain
))
1563 CoerceToDomain
*cd
= (CoerceToDomain
*) node
;
1565 add_object_address(OCLASS_TYPE
, cd
->resulttype
, 0,
1568 else if (IsA(node
, SortGroupClause
))
1570 SortGroupClause
*sgc
= (SortGroupClause
*) node
;
1572 add_object_address(OCLASS_OPERATOR
, sgc
->eqop
, 0,
1574 if (OidIsValid(sgc
->sortop
))
1575 add_object_address(OCLASS_OPERATOR
, sgc
->sortop
, 0,
1579 else if (IsA(node
, Query
))
1581 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1582 Query
*query
= (Query
*) node
;
1587 * Add whole-relation refs for each plain relation mentioned in the
1588 * subquery's rtable, as well as datatype refs for any datatypes used
1589 * as a RECORD function's output. (Note: query_tree_walker takes care
1590 * of recursing into RTE_FUNCTION RTEs, subqueries, etc, so no need to
1591 * do that here. But keep it from looking at join alias lists.)
1593 foreach(rtable
, query
->rtable
)
1595 RangeTblEntry
*rte
= (RangeTblEntry
*) lfirst(rtable
);
1598 switch (rte
->rtekind
)
1601 add_object_address(OCLASS_CLASS
, rte
->relid
, 0,
1605 foreach(ct
, rte
->funccoltypes
)
1607 add_object_address(OCLASS_TYPE
, lfirst_oid(ct
), 0,
1616 /* query_tree_walker ignores ORDER BY etc, but we need those opers */
1617 find_expr_references_walker((Node
*) query
->sortClause
, context
);
1618 find_expr_references_walker((Node
*) query
->groupClause
, context
);
1619 find_expr_references_walker((Node
*) query
->windowClause
, context
);
1620 find_expr_references_walker((Node
*) query
->distinctClause
, context
);
1622 /* Examine substructure of query */
1623 context
->rtables
= lcons(query
->rtable
, context
->rtables
);
1624 result
= query_tree_walker(query
,
1625 find_expr_references_walker
,
1627 QTW_IGNORE_JOINALIASES
);
1628 context
->rtables
= list_delete_first(context
->rtables
);
1631 else if (IsA(node
, SetOperationStmt
))
1633 SetOperationStmt
*setop
= (SetOperationStmt
*) node
;
1635 /* we need to look at the groupClauses for operator references */
1636 find_expr_references_walker((Node
*) setop
->groupClauses
, context
);
1637 /* fall through to examine child nodes */
1640 return expression_tree_walker(node
, find_expr_references_walker
,
1645 * Given an array of dependency references, eliminate any duplicates.
1648 eliminate_duplicate_dependencies(ObjectAddresses
*addrs
)
1650 ObjectAddress
*priorobj
;
1655 * We can't sort if the array has "extra" data, because there's no way to
1656 * keep it in sync. Fortunately that combination of features is not
1659 Assert(!addrs
->extras
);
1661 if (addrs
->numrefs
<= 1)
1662 return; /* nothing to do */
1664 /* Sort the refs so that duplicates are adjacent */
1665 qsort((void *) addrs
->refs
, addrs
->numrefs
, sizeof(ObjectAddress
),
1666 object_address_comparator
);
1669 priorobj
= addrs
->refs
;
1671 for (oldref
= 1; oldref
< addrs
->numrefs
; oldref
++)
1673 ObjectAddress
*thisobj
= addrs
->refs
+ oldref
;
1675 if (priorobj
->classId
== thisobj
->classId
&&
1676 priorobj
->objectId
== thisobj
->objectId
)
1678 if (priorobj
->objectSubId
== thisobj
->objectSubId
)
1679 continue; /* identical, so drop thisobj */
1682 * If we have a whole-object reference and a reference to a part
1683 * of the same object, we don't need the whole-object reference
1684 * (for example, we don't need to reference both table foo and
1685 * column foo.bar). The whole-object reference will always appear
1686 * first in the sorted list.
1688 if (priorobj
->objectSubId
== 0)
1690 /* replace whole ref with partial */
1691 priorobj
->objectSubId
= thisobj
->objectSubId
;
1695 /* Not identical, so add thisobj to output set */
1697 *priorobj
= *thisobj
;
1701 addrs
->numrefs
= newrefs
;
1705 * qsort comparator for ObjectAddress items
1708 object_address_comparator(const void *a
, const void *b
)
1710 const ObjectAddress
*obja
= (const ObjectAddress
*) a
;
1711 const ObjectAddress
*objb
= (const ObjectAddress
*) b
;
1713 if (obja
->classId
< objb
->classId
)
1715 if (obja
->classId
> objb
->classId
)
1717 if (obja
->objectId
< objb
->objectId
)
1719 if (obja
->objectId
> objb
->objectId
)
1723 * We sort the subId as an unsigned int so that 0 will come first. See
1724 * logic in eliminate_duplicate_dependencies.
1726 if ((unsigned int) obja
->objectSubId
< (unsigned int) objb
->objectSubId
)
1728 if ((unsigned int) obja
->objectSubId
> (unsigned int) objb
->objectSubId
)
1734 * Routines for handling an expansible array of ObjectAddress items.
1736 * new_object_addresses: create a new ObjectAddresses array.
1739 new_object_addresses(void)
1741 ObjectAddresses
*addrs
;
1743 addrs
= palloc(sizeof(ObjectAddresses
));
1746 addrs
->maxrefs
= 32;
1747 addrs
->refs
= (ObjectAddress
*)
1748 palloc(addrs
->maxrefs
* sizeof(ObjectAddress
));
1749 addrs
->extras
= NULL
; /* until/unless needed */
1755 * Add an entry to an ObjectAddresses array.
1757 * It is convenient to specify the class by ObjectClass rather than directly
1761 add_object_address(ObjectClass oclass
, Oid objectId
, int32 subId
,
1762 ObjectAddresses
*addrs
)
1764 ObjectAddress
*item
;
1766 /* enlarge array if needed */
1767 if (addrs
->numrefs
>= addrs
->maxrefs
)
1769 addrs
->maxrefs
*= 2;
1770 addrs
->refs
= (ObjectAddress
*)
1771 repalloc(addrs
->refs
, addrs
->maxrefs
* sizeof(ObjectAddress
));
1772 Assert(!addrs
->extras
);
1774 /* record this item */
1775 item
= addrs
->refs
+ addrs
->numrefs
;
1776 item
->classId
= object_classes
[oclass
];
1777 item
->objectId
= objectId
;
1778 item
->objectSubId
= subId
;
1783 * Add an entry to an ObjectAddresses array.
1785 * As above, but specify entry exactly.
1788 add_exact_object_address(const ObjectAddress
*object
,
1789 ObjectAddresses
*addrs
)
1791 ObjectAddress
*item
;
1793 /* enlarge array if needed */
1794 if (addrs
->numrefs
>= addrs
->maxrefs
)
1796 addrs
->maxrefs
*= 2;
1797 addrs
->refs
= (ObjectAddress
*)
1798 repalloc(addrs
->refs
, addrs
->maxrefs
* sizeof(ObjectAddress
));
1799 Assert(!addrs
->extras
);
1801 /* record this item */
1802 item
= addrs
->refs
+ addrs
->numrefs
;
1808 * Add an entry to an ObjectAddresses array.
1810 * As above, but specify entry exactly and provide some "extra" data too.
1813 add_exact_object_address_extra(const ObjectAddress
*object
,
1814 const ObjectAddressExtra
*extra
,
1815 ObjectAddresses
*addrs
)
1817 ObjectAddress
*item
;
1818 ObjectAddressExtra
*itemextra
;
1820 /* allocate extra space if first time */
1822 addrs
->extras
= (ObjectAddressExtra
*)
1823 palloc(addrs
->maxrefs
* sizeof(ObjectAddressExtra
));
1825 /* enlarge array if needed */
1826 if (addrs
->numrefs
>= addrs
->maxrefs
)
1828 addrs
->maxrefs
*= 2;
1829 addrs
->refs
= (ObjectAddress
*)
1830 repalloc(addrs
->refs
, addrs
->maxrefs
* sizeof(ObjectAddress
));
1831 addrs
->extras
= (ObjectAddressExtra
*)
1832 repalloc(addrs
->extras
, addrs
->maxrefs
* sizeof(ObjectAddressExtra
));
1834 /* record this item */
1835 item
= addrs
->refs
+ addrs
->numrefs
;
1837 itemextra
= addrs
->extras
+ addrs
->numrefs
;
1838 *itemextra
= *extra
;
1843 * Test whether an object is present in an ObjectAddresses array.
1845 * We return "true" if object is a subobject of something in the array, too.
1848 object_address_present(const ObjectAddress
*object
,
1849 const ObjectAddresses
*addrs
)
1853 for (i
= addrs
->numrefs
- 1; i
>= 0; i
--)
1855 const ObjectAddress
*thisobj
= addrs
->refs
+ i
;
1857 if (object
->classId
== thisobj
->classId
&&
1858 object
->objectId
== thisobj
->objectId
)
1860 if (object
->objectSubId
== thisobj
->objectSubId
||
1861 thisobj
->objectSubId
== 0)
1870 * As above, except that if the object is present then also OR the given
1871 * flags into its associated extra data (which must exist).
1874 object_address_present_add_flags(const ObjectAddress
*object
,
1876 ObjectAddresses
*addrs
)
1880 for (i
= addrs
->numrefs
- 1; i
>= 0; i
--)
1882 ObjectAddress
*thisobj
= addrs
->refs
+ i
;
1884 if (object
->classId
== thisobj
->classId
&&
1885 object
->objectId
== thisobj
->objectId
)
1887 if (object
->objectSubId
== thisobj
->objectSubId
)
1889 ObjectAddressExtra
*thisextra
= addrs
->extras
+ i
;
1891 thisextra
->flags
|= flags
;
1894 if (thisobj
->objectSubId
== 0)
1897 * We get here if we find a need to delete a column after
1898 * having already decided to drop its whole table. Obviously
1899 * we no longer need to drop the column. But don't plaster
1900 * its flags on the table.
1911 * Record multiple dependencies from an ObjectAddresses array, after first
1912 * removing any duplicates.
1915 record_object_address_dependencies(const ObjectAddress
*depender
,
1916 ObjectAddresses
*referenced
,
1917 DependencyType behavior
)
1919 eliminate_duplicate_dependencies(referenced
);
1920 recordMultipleDependencies(depender
,
1921 referenced
->refs
, referenced
->numrefs
,
1926 * Clean up when done with an ObjectAddresses array.
1929 free_object_addresses(ObjectAddresses
*addrs
)
1933 pfree(addrs
->extras
);
1938 * Determine the class of a given object identified by objectAddress.
1940 * This function is essentially the reverse mapping for the object_classes[]
1941 * table. We implement it as a function because the OIDs aren't consecutive.
1944 getObjectClass(const ObjectAddress
*object
)
1946 switch (object
->classId
)
1948 case RelationRelationId
:
1949 /* caller must check objectSubId */
1950 return OCLASS_CLASS
;
1952 case ProcedureRelationId
:
1953 Assert(object
->objectSubId
== 0);
1956 case TypeRelationId
:
1957 Assert(object
->objectSubId
== 0);
1960 case CastRelationId
:
1961 Assert(object
->objectSubId
== 0);
1964 case ConstraintRelationId
:
1965 Assert(object
->objectSubId
== 0);
1966 return OCLASS_CONSTRAINT
;
1968 case ConversionRelationId
:
1969 Assert(object
->objectSubId
== 0);
1970 return OCLASS_CONVERSION
;
1972 case AttrDefaultRelationId
:
1973 Assert(object
->objectSubId
== 0);
1974 return OCLASS_DEFAULT
;
1976 case LanguageRelationId
:
1977 Assert(object
->objectSubId
== 0);
1978 return OCLASS_LANGUAGE
;
1980 case OperatorRelationId
:
1981 Assert(object
->objectSubId
== 0);
1982 return OCLASS_OPERATOR
;
1984 case OperatorClassRelationId
:
1985 Assert(object
->objectSubId
== 0);
1986 return OCLASS_OPCLASS
;
1988 case OperatorFamilyRelationId
:
1989 Assert(object
->objectSubId
== 0);
1990 return OCLASS_OPFAMILY
;
1992 case AccessMethodOperatorRelationId
:
1993 Assert(object
->objectSubId
== 0);
1996 case AccessMethodProcedureRelationId
:
1997 Assert(object
->objectSubId
== 0);
1998 return OCLASS_AMPROC
;
2000 case RewriteRelationId
:
2001 Assert(object
->objectSubId
== 0);
2002 return OCLASS_REWRITE
;
2004 case TriggerRelationId
:
2005 Assert(object
->objectSubId
== 0);
2006 return OCLASS_TRIGGER
;
2008 case NamespaceRelationId
:
2009 Assert(object
->objectSubId
== 0);
2010 return OCLASS_SCHEMA
;
2012 case TSParserRelationId
:
2013 Assert(object
->objectSubId
== 0);
2014 return OCLASS_TSPARSER
;
2016 case TSDictionaryRelationId
:
2017 Assert(object
->objectSubId
== 0);
2018 return OCLASS_TSDICT
;
2020 case TSTemplateRelationId
:
2021 Assert(object
->objectSubId
== 0);
2022 return OCLASS_TSTEMPLATE
;
2024 case TSConfigRelationId
:
2025 Assert(object
->objectSubId
== 0);
2026 return OCLASS_TSCONFIG
;
2028 case AuthIdRelationId
:
2029 Assert(object
->objectSubId
== 0);
2032 case DatabaseRelationId
:
2033 Assert(object
->objectSubId
== 0);
2034 return OCLASS_DATABASE
;
2036 case TableSpaceRelationId
:
2037 Assert(object
->objectSubId
== 0);
2038 return OCLASS_TBLSPACE
;
2040 case ForeignDataWrapperRelationId
:
2041 Assert(object
->objectSubId
== 0);
2044 case ForeignServerRelationId
:
2045 Assert(object
->objectSubId
== 0);
2046 return OCLASS_FOREIGN_SERVER
;
2048 case UserMappingRelationId
:
2049 Assert(object
->objectSubId
== 0);
2050 return OCLASS_USER_MAPPING
;
2053 /* shouldn't get here */
2054 elog(ERROR
, "unrecognized object class: %u", object
->classId
);
2055 return OCLASS_CLASS
; /* keep compiler quiet */
2059 * getObjectDescription: build an object description for messages
2061 * The result is a palloc'd string.
2064 getObjectDescription(const ObjectAddress
*object
)
2066 StringInfoData buffer
;
2068 initStringInfo(&buffer
);
2070 switch (getObjectClass(object
))
2073 getRelationDescription(&buffer
, object
->objectId
);
2074 if (object
->objectSubId
!= 0)
2075 appendStringInfo(&buffer
, _(" column %s"),
2076 get_relid_attribute_name(object
->objectId
,
2077 object
->objectSubId
));
2081 appendStringInfo(&buffer
, _("function %s"),
2082 format_procedure(object
->objectId
));
2086 appendStringInfo(&buffer
, _("type %s"),
2087 format_type_be(object
->objectId
));
2093 ScanKeyData skey
[1];
2096 Form_pg_cast castForm
;
2098 castDesc
= heap_open(CastRelationId
, AccessShareLock
);
2100 ScanKeyInit(&skey
[0],
2101 ObjectIdAttributeNumber
,
2102 BTEqualStrategyNumber
, F_OIDEQ
,
2103 ObjectIdGetDatum(object
->objectId
));
2105 rcscan
= systable_beginscan(castDesc
, CastOidIndexId
, true,
2106 SnapshotNow
, 1, skey
);
2108 tup
= systable_getnext(rcscan
);
2110 if (!HeapTupleIsValid(tup
))
2111 elog(ERROR
, "could not find tuple for cast %u",
2114 castForm
= (Form_pg_cast
) GETSTRUCT(tup
);
2116 appendStringInfo(&buffer
, _("cast from %s to %s"),
2117 format_type_be(castForm
->castsource
),
2118 format_type_be(castForm
->casttarget
));
2120 systable_endscan(rcscan
);
2121 heap_close(castDesc
, AccessShareLock
);
2125 case OCLASS_CONSTRAINT
:
2128 Form_pg_constraint con
;
2130 conTup
= SearchSysCache(CONSTROID
,
2131 ObjectIdGetDatum(object
->objectId
),
2133 if (!HeapTupleIsValid(conTup
))
2134 elog(ERROR
, "cache lookup failed for constraint %u",
2136 con
= (Form_pg_constraint
) GETSTRUCT(conTup
);
2138 if (OidIsValid(con
->conrelid
))
2142 initStringInfo(&rel
);
2143 getRelationDescription(&rel
, con
->conrelid
);
2144 appendStringInfo(&buffer
, _("constraint %s on %s"),
2145 NameStr(con
->conname
), rel
.data
);
2150 appendStringInfo(&buffer
, _("constraint %s"),
2151 NameStr(con
->conname
));
2154 ReleaseSysCache(conTup
);
2158 case OCLASS_CONVERSION
:
2162 conTup
= SearchSysCache(CONVOID
,
2163 ObjectIdGetDatum(object
->objectId
),
2165 if (!HeapTupleIsValid(conTup
))
2166 elog(ERROR
, "cache lookup failed for conversion %u",
2168 appendStringInfo(&buffer
, _("conversion %s"),
2169 NameStr(((Form_pg_conversion
) GETSTRUCT(conTup
))->conname
));
2170 ReleaseSysCache(conTup
);
2174 case OCLASS_DEFAULT
:
2176 Relation attrdefDesc
;
2177 ScanKeyData skey
[1];
2180 Form_pg_attrdef attrdef
;
2181 ObjectAddress colobject
;
2183 attrdefDesc
= heap_open(AttrDefaultRelationId
, AccessShareLock
);
2185 ScanKeyInit(&skey
[0],
2186 ObjectIdAttributeNumber
,
2187 BTEqualStrategyNumber
, F_OIDEQ
,
2188 ObjectIdGetDatum(object
->objectId
));
2190 adscan
= systable_beginscan(attrdefDesc
, AttrDefaultOidIndexId
,
2191 true, SnapshotNow
, 1, skey
);
2193 tup
= systable_getnext(adscan
);
2195 if (!HeapTupleIsValid(tup
))
2196 elog(ERROR
, "could not find tuple for attrdef %u",
2199 attrdef
= (Form_pg_attrdef
) GETSTRUCT(tup
);
2201 colobject
.classId
= RelationRelationId
;
2202 colobject
.objectId
= attrdef
->adrelid
;
2203 colobject
.objectSubId
= attrdef
->adnum
;
2205 appendStringInfo(&buffer
, _("default for %s"),
2206 getObjectDescription(&colobject
));
2208 systable_endscan(adscan
);
2209 heap_close(attrdefDesc
, AccessShareLock
);
2213 case OCLASS_LANGUAGE
:
2217 langTup
= SearchSysCache(LANGOID
,
2218 ObjectIdGetDatum(object
->objectId
),
2220 if (!HeapTupleIsValid(langTup
))
2221 elog(ERROR
, "cache lookup failed for language %u",
2223 appendStringInfo(&buffer
, _("language %s"),
2224 NameStr(((Form_pg_language
) GETSTRUCT(langTup
))->lanname
));
2225 ReleaseSysCache(langTup
);
2229 case OCLASS_OPERATOR
:
2230 appendStringInfo(&buffer
, _("operator %s"),
2231 format_operator(object
->objectId
));
2234 case OCLASS_OPCLASS
:
2237 Form_pg_opclass opcForm
;
2242 opcTup
= SearchSysCache(CLAOID
,
2243 ObjectIdGetDatum(object
->objectId
),
2245 if (!HeapTupleIsValid(opcTup
))
2246 elog(ERROR
, "cache lookup failed for opclass %u",
2248 opcForm
= (Form_pg_opclass
) GETSTRUCT(opcTup
);
2250 amTup
= SearchSysCache(AMOID
,
2251 ObjectIdGetDatum(opcForm
->opcmethod
),
2253 if (!HeapTupleIsValid(amTup
))
2254 elog(ERROR
, "cache lookup failed for access method %u",
2255 opcForm
->opcmethod
);
2256 amForm
= (Form_pg_am
) GETSTRUCT(amTup
);
2258 /* Qualify the name if not visible in search path */
2259 if (OpclassIsVisible(object
->objectId
))
2262 nspname
= get_namespace_name(opcForm
->opcnamespace
);
2264 appendStringInfo(&buffer
, _("operator class %s for access method %s"),
2265 quote_qualified_identifier(nspname
,
2266 NameStr(opcForm
->opcname
)),
2267 NameStr(amForm
->amname
));
2269 ReleaseSysCache(amTup
);
2270 ReleaseSysCache(opcTup
);
2274 case OCLASS_OPFAMILY
:
2275 getOpFamilyDescription(&buffer
, object
->objectId
);
2281 ScanKeyData skey
[1];
2284 Form_pg_amop amopForm
;
2285 StringInfoData opfam
;
2287 amopDesc
= heap_open(AccessMethodOperatorRelationId
,
2290 ScanKeyInit(&skey
[0],
2291 ObjectIdAttributeNumber
,
2292 BTEqualStrategyNumber
, F_OIDEQ
,
2293 ObjectIdGetDatum(object
->objectId
));
2295 amscan
= systable_beginscan(amopDesc
, AccessMethodOperatorOidIndexId
, true,
2296 SnapshotNow
, 1, skey
);
2298 tup
= systable_getnext(amscan
);
2300 if (!HeapTupleIsValid(tup
))
2301 elog(ERROR
, "could not find tuple for amop entry %u",
2304 amopForm
= (Form_pg_amop
) GETSTRUCT(tup
);
2306 initStringInfo(&opfam
);
2307 getOpFamilyDescription(&opfam
, amopForm
->amopfamily
);
2310 * translator: %d is the operator strategy (a number), the
2311 * first %s is the textual form of the operator, and the
2312 * second %s is the description of the operator family.
2314 appendStringInfo(&buffer
, _("operator %d %s of %s"),
2315 amopForm
->amopstrategy
,
2316 format_operator(amopForm
->amopopr
),
2320 systable_endscan(amscan
);
2321 heap_close(amopDesc
, AccessShareLock
);
2327 Relation amprocDesc
;
2328 ScanKeyData skey
[1];
2331 Form_pg_amproc amprocForm
;
2332 StringInfoData opfam
;
2334 amprocDesc
= heap_open(AccessMethodProcedureRelationId
,
2337 ScanKeyInit(&skey
[0],
2338 ObjectIdAttributeNumber
,
2339 BTEqualStrategyNumber
, F_OIDEQ
,
2340 ObjectIdGetDatum(object
->objectId
));
2342 amscan
= systable_beginscan(amprocDesc
, AccessMethodProcedureOidIndexId
, true,
2343 SnapshotNow
, 1, skey
);
2345 tup
= systable_getnext(amscan
);
2347 if (!HeapTupleIsValid(tup
))
2348 elog(ERROR
, "could not find tuple for amproc entry %u",
2351 amprocForm
= (Form_pg_amproc
) GETSTRUCT(tup
);
2353 initStringInfo(&opfam
);
2354 getOpFamilyDescription(&opfam
, amprocForm
->amprocfamily
);
2357 * translator: %d is the function number, the first %s is the
2358 * textual form of the function with arguments, and the second
2359 * %s is the description of the operator family.
2361 appendStringInfo(&buffer
, _("function %d %s of %s"),
2362 amprocForm
->amprocnum
,
2363 format_procedure(amprocForm
->amproc
),
2367 systable_endscan(amscan
);
2368 heap_close(amprocDesc
, AccessShareLock
);
2372 case OCLASS_REWRITE
:
2375 ScanKeyData skey
[1];
2378 Form_pg_rewrite rule
;
2380 ruleDesc
= heap_open(RewriteRelationId
, AccessShareLock
);
2382 ScanKeyInit(&skey
[0],
2383 ObjectIdAttributeNumber
,
2384 BTEqualStrategyNumber
, F_OIDEQ
,
2385 ObjectIdGetDatum(object
->objectId
));
2387 rcscan
= systable_beginscan(ruleDesc
, RewriteOidIndexId
, true,
2388 SnapshotNow
, 1, skey
);
2390 tup
= systable_getnext(rcscan
);
2392 if (!HeapTupleIsValid(tup
))
2393 elog(ERROR
, "could not find tuple for rule %u",
2396 rule
= (Form_pg_rewrite
) GETSTRUCT(tup
);
2398 appendStringInfo(&buffer
, _("rule %s on "),
2399 NameStr(rule
->rulename
));
2400 getRelationDescription(&buffer
, rule
->ev_class
);
2402 systable_endscan(rcscan
);
2403 heap_close(ruleDesc
, AccessShareLock
);
2407 case OCLASS_TRIGGER
:
2410 ScanKeyData skey
[1];
2413 Form_pg_trigger trig
;
2415 trigDesc
= heap_open(TriggerRelationId
, AccessShareLock
);
2417 ScanKeyInit(&skey
[0],
2418 ObjectIdAttributeNumber
,
2419 BTEqualStrategyNumber
, F_OIDEQ
,
2420 ObjectIdGetDatum(object
->objectId
));
2422 tgscan
= systable_beginscan(trigDesc
, TriggerOidIndexId
, true,
2423 SnapshotNow
, 1, skey
);
2425 tup
= systable_getnext(tgscan
);
2427 if (!HeapTupleIsValid(tup
))
2428 elog(ERROR
, "could not find tuple for trigger %u",
2431 trig
= (Form_pg_trigger
) GETSTRUCT(tup
);
2433 appendStringInfo(&buffer
, _("trigger %s on "),
2434 NameStr(trig
->tgname
));
2435 getRelationDescription(&buffer
, trig
->tgrelid
);
2437 systable_endscan(tgscan
);
2438 heap_close(trigDesc
, AccessShareLock
);
2446 nspname
= get_namespace_name(object
->objectId
);
2448 elog(ERROR
, "cache lookup failed for namespace %u",
2450 appendStringInfo(&buffer
, _("schema %s"), nspname
);
2454 case OCLASS_TSPARSER
:
2458 tup
= SearchSysCache(TSPARSEROID
,
2459 ObjectIdGetDatum(object
->objectId
),
2461 if (!HeapTupleIsValid(tup
))
2462 elog(ERROR
, "cache lookup failed for text search parser %u",
2464 appendStringInfo(&buffer
, _("text search parser %s"),
2465 NameStr(((Form_pg_ts_parser
) GETSTRUCT(tup
))->prsname
));
2466 ReleaseSysCache(tup
);
2474 tup
= SearchSysCache(TSDICTOID
,
2475 ObjectIdGetDatum(object
->objectId
),
2477 if (!HeapTupleIsValid(tup
))
2478 elog(ERROR
, "cache lookup failed for text search dictionary %u",
2480 appendStringInfo(&buffer
, _("text search dictionary %s"),
2481 NameStr(((Form_pg_ts_dict
) GETSTRUCT(tup
))->dictname
));
2482 ReleaseSysCache(tup
);
2486 case OCLASS_TSTEMPLATE
:
2490 tup
= SearchSysCache(TSTEMPLATEOID
,
2491 ObjectIdGetDatum(object
->objectId
),
2493 if (!HeapTupleIsValid(tup
))
2494 elog(ERROR
, "cache lookup failed for text search template %u",
2496 appendStringInfo(&buffer
, _("text search template %s"),
2497 NameStr(((Form_pg_ts_template
) GETSTRUCT(tup
))->tmplname
));
2498 ReleaseSysCache(tup
);
2502 case OCLASS_TSCONFIG
:
2506 tup
= SearchSysCache(TSCONFIGOID
,
2507 ObjectIdGetDatum(object
->objectId
),
2509 if (!HeapTupleIsValid(tup
))
2510 elog(ERROR
, "cache lookup failed for text search configuration %u",
2512 appendStringInfo(&buffer
, _("text search configuration %s"),
2513 NameStr(((Form_pg_ts_config
) GETSTRUCT(tup
))->cfgname
));
2514 ReleaseSysCache(tup
);
2520 appendStringInfo(&buffer
, _("role %s"),
2521 GetUserNameFromId(object
->objectId
));
2525 case OCLASS_DATABASE
:
2529 datname
= get_database_name(object
->objectId
);
2531 elog(ERROR
, "cache lookup failed for database %u",
2533 appendStringInfo(&buffer
, _("database %s"), datname
);
2537 case OCLASS_TBLSPACE
:
2541 tblspace
= get_tablespace_name(object
->objectId
);
2543 elog(ERROR
, "cache lookup failed for tablespace %u",
2545 appendStringInfo(&buffer
, _("tablespace %s"), tblspace
);
2551 ForeignDataWrapper
*fdw
;
2553 fdw
= GetForeignDataWrapper(object
->objectId
);
2554 appendStringInfo(&buffer
, _("foreign-data wrapper %s"), fdw
->fdwname
);
2558 case OCLASS_FOREIGN_SERVER
:
2562 srv
= GetForeignServer(object
->objectId
);
2563 appendStringInfo(&buffer
, _("server %s"), srv
->servername
);
2567 case OCLASS_USER_MAPPING
:
2573 tup
= SearchSysCache(USERMAPPINGOID
,
2574 ObjectIdGetDatum(object
->objectId
),
2576 if (!HeapTupleIsValid(tup
))
2577 elog(ERROR
, "cache lookup failed for user mapping %u",
2580 useid
= ((Form_pg_user_mapping
) GETSTRUCT(tup
))->umuser
;
2582 ReleaseSysCache(tup
);
2584 if (OidIsValid(useid
))
2585 usename
= GetUserNameFromId(useid
);
2589 appendStringInfo(&buffer
, _("user mapping for %s"), usename
);
2594 appendStringInfo(&buffer
, "unrecognized object %u %u %d",
2597 object
->objectSubId
);
2605 * subroutine for getObjectDescription: describe a relation
2608 getRelationDescription(StringInfo buffer
, Oid relid
)
2611 Form_pg_class relForm
;
2615 relTup
= SearchSysCache(RELOID
,
2616 ObjectIdGetDatum(relid
),
2618 if (!HeapTupleIsValid(relTup
))
2619 elog(ERROR
, "cache lookup failed for relation %u", relid
);
2620 relForm
= (Form_pg_class
) GETSTRUCT(relTup
);
2622 /* Qualify the name if not visible in search path */
2623 if (RelationIsVisible(relid
))
2626 nspname
= get_namespace_name(relForm
->relnamespace
);
2628 relname
= quote_qualified_identifier(nspname
, NameStr(relForm
->relname
));
2630 switch (relForm
->relkind
)
2632 case RELKIND_RELATION
:
2633 appendStringInfo(buffer
, _("table %s"),
2637 appendStringInfo(buffer
, _("index %s"),
2640 case RELKIND_SEQUENCE
:
2641 appendStringInfo(buffer
, _("sequence %s"),
2644 case RELKIND_UNCATALOGED
:
2645 appendStringInfo(buffer
, _("uncataloged table %s"),
2648 case RELKIND_TOASTVALUE
:
2649 appendStringInfo(buffer
, _("toast table %s"),
2653 appendStringInfo(buffer
, _("view %s"),
2656 case RELKIND_COMPOSITE_TYPE
:
2657 appendStringInfo(buffer
, _("composite type %s"),
2661 /* shouldn't get here */
2662 appendStringInfo(buffer
, _("relation %s"),
2667 ReleaseSysCache(relTup
);
2671 * subroutine for getObjectDescription: describe an operator family
2674 getOpFamilyDescription(StringInfo buffer
, Oid opfid
)
2677 Form_pg_opfamily opfForm
;
2682 opfTup
= SearchSysCache(OPFAMILYOID
,
2683 ObjectIdGetDatum(opfid
),
2685 if (!HeapTupleIsValid(opfTup
))
2686 elog(ERROR
, "cache lookup failed for opfamily %u", opfid
);
2687 opfForm
= (Form_pg_opfamily
) GETSTRUCT(opfTup
);
2689 amTup
= SearchSysCache(AMOID
,
2690 ObjectIdGetDatum(opfForm
->opfmethod
),
2692 if (!HeapTupleIsValid(amTup
))
2693 elog(ERROR
, "cache lookup failed for access method %u",
2694 opfForm
->opfmethod
);
2695 amForm
= (Form_pg_am
) GETSTRUCT(amTup
);
2697 /* Qualify the name if not visible in search path */
2698 if (OpfamilyIsVisible(opfid
))
2701 nspname
= get_namespace_name(opfForm
->opfnamespace
);
2703 appendStringInfo(buffer
, _("operator family %s for access method %s"),
2704 quote_qualified_identifier(nspname
,
2705 NameStr(opfForm
->opfname
)),
2706 NameStr(amForm
->amname
));
2708 ReleaseSysCache(amTup
);
2709 ReleaseSysCache(opfTup
);