]> granicus.if.org Git - postgresql/blob - src/backend/catalog/dependency.c
Reduce the need for frontend programs to include "postgres.h" by refactoring
[postgresql] / src / backend / catalog / dependency.c
1 /*-------------------------------------------------------------------------
2  *
3  * dependency.c
4  *        Routines to support inter-object dependencies.
5  *
6  *
7  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.71 2008/03/27 03:57:33 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "access/xact.h"
20 #include "catalog/dependency.h"
21 #include "catalog/heap.h"
22 #include "catalog/index.h"
23 #include "catalog/indexing.h"
24 #include "catalog/namespace.h"
25 #include "catalog/pg_amop.h"
26 #include "catalog/pg_amproc.h"
27 #include "catalog/pg_attrdef.h"
28 #include "catalog/pg_authid.h"
29 #include "catalog/pg_cast.h"
30 #include "catalog/pg_constraint.h"
31 #include "catalog/pg_conversion.h"
32 #include "catalog/pg_conversion_fn.h"
33 #include "catalog/pg_database.h"
34 #include "catalog/pg_depend.h"
35 #include "catalog/pg_language.h"
36 #include "catalog/pg_namespace.h"
37 #include "catalog/pg_opclass.h"
38 #include "catalog/pg_operator.h"
39 #include "catalog/pg_opfamily.h"
40 #include "catalog/pg_proc.h"
41 #include "catalog/pg_rewrite.h"
42 #include "catalog/pg_tablespace.h"
43 #include "catalog/pg_trigger.h"
44 #include "catalog/pg_ts_config.h"
45 #include "catalog/pg_ts_dict.h"
46 #include "catalog/pg_ts_parser.h"
47 #include "catalog/pg_ts_template.h"
48 #include "catalog/pg_type.h"
49 #include "commands/comment.h"
50 #include "commands/dbcommands.h"
51 #include "commands/defrem.h"
52 #include "commands/proclang.h"
53 #include "commands/schemacmds.h"
54 #include "commands/tablespace.h"
55 #include "commands/trigger.h"
56 #include "commands/typecmds.h"
57 #include "miscadmin.h"
58 #include "optimizer/clauses.h"
59 #include "parser/parsetree.h"
60 #include "rewrite/rewriteRemove.h"
61 #include "utils/builtins.h"
62 #include "utils/fmgroids.h"
63 #include "utils/lsyscache.h"
64 #include "utils/syscache.h"
65 #include "utils/tqual.h"
66
67
68 /* expansible list of ObjectAddresses */
69 struct ObjectAddresses
70 {
71         ObjectAddress *refs;            /* => palloc'd array */
72         int                     numrefs;                /* current number of references */
73         int                     maxrefs;                /* current size of palloc'd array */
74 };
75
76 /* typedef ObjectAddresses appears in dependency.h */
77
78 /* for find_expr_references_walker */
79 typedef struct
80 {
81         ObjectAddresses *addrs;         /* addresses being accumulated */
82         List       *rtables;            /* list of rangetables to resolve Vars */
83 } find_expr_references_context;
84
85 /*
86  * This constant table maps ObjectClasses to the corresponding catalog OIDs.
87  * See also getObjectClass().
88  */
89 static const Oid object_classes[MAX_OCLASS] = {
90         RelationRelationId,                     /* OCLASS_CLASS */
91         ProcedureRelationId,            /* OCLASS_PROC */
92         TypeRelationId,                         /* OCLASS_TYPE */
93         CastRelationId,                         /* OCLASS_CAST */
94         ConstraintRelationId,           /* OCLASS_CONSTRAINT */
95         ConversionRelationId,           /* OCLASS_CONVERSION */
96         AttrDefaultRelationId,          /* OCLASS_DEFAULT */
97         LanguageRelationId,                     /* OCLASS_LANGUAGE */
98         OperatorRelationId,                     /* OCLASS_OPERATOR */
99         OperatorClassRelationId,        /* OCLASS_OPCLASS */
100         OperatorFamilyRelationId,       /* OCLASS_OPFAMILY */
101         AccessMethodOperatorRelationId,         /* OCLASS_AMOP */
102         AccessMethodProcedureRelationId,        /* OCLASS_AMPROC */
103         RewriteRelationId,                      /* OCLASS_REWRITE */
104         TriggerRelationId,                      /* OCLASS_TRIGGER */
105         NamespaceRelationId,            /* OCLASS_SCHEMA */
106         TSParserRelationId,                     /* OCLASS_TSPARSER */
107         TSDictionaryRelationId,         /* OCLASS_TSDICT */
108         TSTemplateRelationId,           /* OCLASS_TSTEMPLATE */
109         TSConfigRelationId,                     /* OCLASS_TSCONFIG */
110         AuthIdRelationId,                       /* OCLASS_ROLE */
111         DatabaseRelationId,                     /* OCLASS_DATABASE */
112         TableSpaceRelationId            /* OCLASS_TBLSPACE */
113 };
114
115
116 static void performDeletionWithList(const ObjectAddress *object,
117                                                 ObjectAddresses *oktodelete,
118                                                 DropBehavior behavior,
119                                                 ObjectAddresses *alreadyDeleted);
120 static void findAutoDeletableObjects(const ObjectAddress *object,
121                                                  ObjectAddresses *oktodelete,
122                                                  Relation depRel, bool addself);
123 static bool recursiveDeletion(const ObjectAddress *object,
124                                   DropBehavior behavior,
125                                   int msglevel,
126                                   const ObjectAddress *callingObject,
127                                   ObjectAddresses *oktodelete,
128                                   Relation depRel,
129                                   ObjectAddresses *alreadyDeleted);
130 static bool deleteDependentObjects(const ObjectAddress *object,
131                                            const char *objDescription,
132                                            DropBehavior behavior,
133                                            int msglevel,
134                                            ObjectAddresses *oktodelete,
135                                            Relation depRel);
136 static void doDeletion(const ObjectAddress *object);
137 static bool find_expr_references_walker(Node *node,
138                                                         find_expr_references_context *context);
139 static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
140 static int      object_address_comparator(const void *a, const void *b);
141 static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
142                                    ObjectAddresses *addrs);
143 static void getRelationDescription(StringInfo buffer, Oid relid);
144 static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
145
146
147 /*
148  * performDeletion: attempt to drop the specified object.  If CASCADE
149  * behavior is specified, also drop any dependent objects (recursively).
150  * If RESTRICT behavior is specified, error out if there are any dependent
151  * objects, except for those that should be implicitly dropped anyway
152  * according to the dependency type.
153  *
154  * This is the outer control routine for all forms of DROP that drop objects
155  * that can participate in dependencies.
156  */
157 void
158 performDeletion(const ObjectAddress *object,
159                                 DropBehavior behavior)
160 {
161         char       *objDescription;
162         Relation        depRel;
163         ObjectAddresses *oktodelete;
164
165         /*
166          * Get object description for possible use in failure message. Must do
167          * this before deleting it ...
168          */
169         objDescription = getObjectDescription(object);
170
171         /*
172          * We save some cycles by opening pg_depend just once and passing the
173          * Relation pointer down to all the recursive deletion steps.
174          */
175         depRel = heap_open(DependRelationId, RowExclusiveLock);
176
177         /*
178          * Construct a list of objects that are reachable by AUTO or INTERNAL
179          * dependencies from the target object.  These should be deleted silently,
180          * even if the actual deletion pass first reaches one of them via a
181          * non-auto dependency.
182          */
183         oktodelete = new_object_addresses();
184
185         findAutoDeletableObjects(object, oktodelete, depRel, true);
186
187         if (!recursiveDeletion(object, behavior, NOTICE,
188                                                    NULL, oktodelete, depRel, NULL))
189                 ereport(ERROR,
190                                 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
191                                  errmsg("cannot drop %s because other objects depend on it",
192                                                 objDescription),
193                 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
194
195         free_object_addresses(oktodelete);
196
197         heap_close(depRel, RowExclusiveLock);
198
199         pfree(objDescription);
200 }
201
202
203 /*
204  * performDeletionWithList: As above, but the oktodelete list may have already
205  * filled with some objects.  Also, the deleted objects are saved in the
206  * alreadyDeleted list.
207  *
208  * XXX performDeletion could be refactored to be a thin wrapper around this
209  * function.
210  */
211 static void
212 performDeletionWithList(const ObjectAddress *object,
213                                                 ObjectAddresses *oktodelete,
214                                                 DropBehavior behavior,
215                                                 ObjectAddresses *alreadyDeleted)
216 {
217         char       *objDescription;
218         Relation        depRel;
219
220         /*
221          * Get object description for possible use in failure message. Must do
222          * this before deleting it ...
223          */
224         objDescription = getObjectDescription(object);
225
226         /*
227          * We save some cycles by opening pg_depend just once and passing the
228          * Relation pointer down to all the recursive deletion steps.
229          */
230         depRel = heap_open(DependRelationId, RowExclusiveLock);
231
232         /*
233          * Construct a list of objects that are reachable by AUTO or INTERNAL
234          * dependencies from the target object.  These should be deleted silently,
235          * even if the actual deletion pass first reaches one of them via a
236          * non-auto dependency.
237          */
238         findAutoDeletableObjects(object, oktodelete, depRel, true);
239
240         if (!recursiveDeletion(object, behavior, NOTICE,
241                                                    NULL, oktodelete, depRel, alreadyDeleted))
242                 ereport(ERROR,
243                                 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
244                                  errmsg("cannot drop %s because other objects depend on it",
245                                                 objDescription),
246                 errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
247
248         heap_close(depRel, RowExclusiveLock);
249
250         pfree(objDescription);
251 }
252
253 /*
254  * performMultipleDeletion: Similar to performDeletion, but act on multiple
255  * objects at once.
256  *
257  * The main difference from issuing multiple performDeletion calls is that the
258  * list of objects that would be implicitly dropped, for each object to be
259  * dropped, is the union of the implicit-object list for all objects.  This
260  * makes each check be more relaxed.
261  */
262 void
263 performMultipleDeletions(const ObjectAddresses *objects,
264                                                  DropBehavior behavior)
265 {
266         ObjectAddresses *implicit;
267         ObjectAddresses *alreadyDeleted;
268         Relation        depRel;
269         int                     i;
270
271         implicit = new_object_addresses();
272         alreadyDeleted = new_object_addresses();
273
274         depRel = heap_open(DependRelationId, RowExclusiveLock);
275
276         /*
277          * Get the list of all objects that would be deleted after deleting the
278          * whole "objects" list.  We do this by creating a list of all implicit
279          * (INTERNAL and AUTO) dependencies for each object we collected above.
280          * Note that we must exclude the objects themselves from this list!
281          */
282         for (i = 0; i < objects->numrefs; i++)
283         {
284                 ObjectAddress obj = objects->refs[i];
285
286                 /*
287                  * If it's in the implicit list, we don't need to delete it explicitly
288                  * nor follow the dependencies, because that was already done in a
289                  * previous iteration.
290                  */
291                 if (object_address_present(&obj, implicit))
292                         continue;
293
294                 /*
295                  * Add the objects dependent on this one to the global list of
296                  * implicit objects.
297                  */
298                 findAutoDeletableObjects(&obj, implicit, depRel, false);
299         }
300
301         /* Do the deletion. */
302         for (i = 0; i < objects->numrefs; i++)
303         {
304                 ObjectAddress obj = objects->refs[i];
305
306                 /*
307                  * Skip this object if it was already deleted in a previous iteration.
308                  */
309                 if (object_address_present(&obj, alreadyDeleted))
310                         continue;
311
312                 /*
313                  * Skip this object if it's also present in the list of implicit
314                  * objects --- it will be deleted later.
315                  */
316                 if (object_address_present(&obj, implicit))
317                         continue;
318
319                 /* delete it */
320                 performDeletionWithList(&obj, implicit, behavior, alreadyDeleted);
321         }
322
323         heap_close(depRel, RowExclusiveLock);
324
325         free_object_addresses(implicit);
326         free_object_addresses(alreadyDeleted);
327 }
328
329 /*
330  * deleteWhatDependsOn: attempt to drop everything that depends on the
331  * specified object, though not the object itself.      Behavior is always
332  * CASCADE.
333  *
334  * This is currently used only to clean out the contents of a schema
335  * (namespace): the passed object is a namespace.  We normally want this
336  * to be done silently, so there's an option to suppress NOTICE messages.
337  */
338 void
339 deleteWhatDependsOn(const ObjectAddress *object,
340                                         bool showNotices)
341 {
342         char       *objDescription;
343         Relation        depRel;
344         ObjectAddresses *oktodelete;
345
346         /*
347          * Get object description for possible use in failure messages
348          */
349         objDescription = getObjectDescription(object);
350
351         /*
352          * We save some cycles by opening pg_depend just once and passing the
353          * Relation pointer down to all the recursive deletion steps.
354          */
355         depRel = heap_open(DependRelationId, RowExclusiveLock);
356
357         /*
358          * Construct a list of objects that are reachable by AUTO or INTERNAL
359          * dependencies from the target object.  These should be deleted silently,
360          * even if the actual deletion pass first reaches one of them via a
361          * non-auto dependency.
362          */
363         oktodelete = new_object_addresses();
364
365         findAutoDeletableObjects(object, oktodelete, depRel, true);
366
367         /*
368          * Now invoke only step 2 of recursiveDeletion: just recurse to the stuff
369          * dependent on the given object.
370          */
371         if (!deleteDependentObjects(object, objDescription,
372                                                                 DROP_CASCADE,
373                                                                 showNotices ? NOTICE : DEBUG2,
374                                                                 oktodelete, depRel))
375                 ereport(ERROR,
376                                 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
377                                  errmsg("failed to drop all objects depending on %s",
378                                                 objDescription)));
379
380         /*
381          * We do not need CommandCounterIncrement here, since if step 2 did
382          * anything then each recursive call will have ended with one.
383          */
384
385         free_object_addresses(oktodelete);
386
387         heap_close(depRel, RowExclusiveLock);
388
389         pfree(objDescription);
390 }
391
392
393 /*
394  * findAutoDeletableObjects: find all objects that are reachable by AUTO or
395  * INTERNAL dependency paths from the given object.  Add them all to the
396  * oktodelete list.  If addself is true, the originally given object will also
397  * be added to the list.
398  *
399  * depRel is the already-open pg_depend relation.
400  */
401 static void
402 findAutoDeletableObjects(const ObjectAddress *object,
403                                                  ObjectAddresses *oktodelete,
404                                                  Relation depRel, bool addself)
405 {
406         ScanKeyData key[3];
407         int                     nkeys;
408         SysScanDesc scan;
409         HeapTuple       tup;
410         ObjectAddress otherObject;
411
412         /*
413          * If this object is already in oktodelete, then we already visited it;
414          * don't do so again (this prevents infinite recursion if there's a loop
415          * in pg_depend).  Otherwise, add it.
416          */
417         if (object_address_present(object, oktodelete))
418                 return;
419         if (addself)
420                 add_exact_object_address(object, oktodelete);
421
422         /*
423          * Scan pg_depend records that link to this object, showing the things
424          * that depend on it.  For each one that is AUTO or INTERNAL, visit the
425          * referencing object.
426          *
427          * When dropping a whole object (subId = 0), find pg_depend records for
428          * its sub-objects too.
429          */
430         ScanKeyInit(&key[0],
431                                 Anum_pg_depend_refclassid,
432                                 BTEqualStrategyNumber, F_OIDEQ,
433                                 ObjectIdGetDatum(object->classId));
434         ScanKeyInit(&key[1],
435                                 Anum_pg_depend_refobjid,
436                                 BTEqualStrategyNumber, F_OIDEQ,
437                                 ObjectIdGetDatum(object->objectId));
438         if (object->objectSubId != 0)
439         {
440                 ScanKeyInit(&key[2],
441                                         Anum_pg_depend_refobjsubid,
442                                         BTEqualStrategyNumber, F_INT4EQ,
443                                         Int32GetDatum(object->objectSubId));
444                 nkeys = 3;
445         }
446         else
447                 nkeys = 2;
448
449         scan = systable_beginscan(depRel, DependReferenceIndexId, true,
450                                                           SnapshotNow, nkeys, key);
451
452         while (HeapTupleIsValid(tup = systable_getnext(scan)))
453         {
454                 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
455
456                 switch (foundDep->deptype)
457                 {
458                         case DEPENDENCY_NORMAL:
459                                 /* ignore */
460                                 break;
461                         case DEPENDENCY_AUTO:
462                         case DEPENDENCY_INTERNAL:
463                                 /* recurse */
464                                 otherObject.classId = foundDep->classid;
465                                 otherObject.objectId = foundDep->objid;
466                                 otherObject.objectSubId = foundDep->objsubid;
467                                 findAutoDeletableObjects(&otherObject, oktodelete, depRel, true);
468                                 break;
469                         case DEPENDENCY_PIN:
470
471                                 /*
472                                  * For a PIN dependency we just ereport immediately; there
473                                  * won't be any others to examine, and we aren't ever going to
474                                  * let the user delete it.
475                                  */
476                                 ereport(ERROR,
477                                                 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
478                                                  errmsg("cannot drop %s because it is required by the database system",
479                                                                 getObjectDescription(object))));
480                                 break;
481                         default:
482                                 elog(ERROR, "unrecognized dependency type '%c' for %s",
483                                          foundDep->deptype, getObjectDescription(object));
484                                 break;
485                 }
486         }
487
488         systable_endscan(scan);
489 }
490
491
492 /*
493  * recursiveDeletion: delete a single object for performDeletion, plus
494  * (recursively) anything that depends on it.
495  *
496  * Returns TRUE if successful, FALSE if not.
497  *
498  * callingObject is NULL at the outer level, else identifies the object that
499  * we recursed from (the reference object that someone else needs to delete).
500  *
501  * oktodelete is a list of objects verified deletable (ie, reachable by one
502  * or more AUTO or INTERNAL dependencies from the original target).
503  *
504  * depRel is the already-open pg_depend relation.
505  *
506  *
507  * In RESTRICT mode, we perform all the deletions anyway, but ereport a message
508  * and return FALSE if we find a restriction violation.  performDeletion
509  * will then abort the transaction to nullify the deletions.  We have to
510  * do it this way to (a) report all the direct and indirect dependencies
511  * while (b) not going into infinite recursion if there's a cycle.
512  *
513  * This is even more complex than one could wish, because it is possible for
514  * the same pair of objects to be related by both NORMAL and AUTO/INTERNAL
515  * dependencies.  Also, we might have a situation where we've been asked to
516  * delete object A, and objects B and C both have AUTO dependencies on A,
517  * but B also has a NORMAL dependency on C.  (Since any of these paths might
518  * be indirect, we can't prevent these scenarios, but must cope instead.)
519  * If we visit C before B then we would mistakenly decide that the B->C link
520  * should prevent the restricted drop from occurring.  To handle this, we make
521  * a pre-scan to find all the objects that are auto-deletable from A.  If we
522  * visit C first, but B is present in the oktodelete list, then we make no
523  * complaint but recurse to delete B anyway.  (Note that in general we must
524  * delete B before deleting C; the drop routine for B may try to access C.)
525  *
526  * Note: in the case where the path to B is traversed first, we will not
527  * see the NORMAL dependency when we reach C, because of the pg_depend
528  * removals done in step 1.  The oktodelete list is necessary just
529  * to make the behavior independent of the order in which pg_depend
530  * entries are visited.
531  */
532 static bool
533 recursiveDeletion(const ObjectAddress *object,
534                                   DropBehavior behavior,
535                                   int msglevel,
536                                   const ObjectAddress *callingObject,
537                                   ObjectAddresses *oktodelete,
538                                   Relation depRel,
539                                   ObjectAddresses *alreadyDeleted)
540 {
541         bool            ok = true;
542         char       *objDescription;
543         ScanKeyData key[3];
544         int                     nkeys;
545         SysScanDesc scan;
546         HeapTuple       tup;
547         ObjectAddress otherObject;
548         ObjectAddress owningObject;
549         bool            amOwned = false;
550
551         /*
552          * Get object description for possible use in messages.  Must do this
553          * before deleting it ...
554          */
555         objDescription = getObjectDescription(object);
556
557         /*
558          * Step 1: find and remove pg_depend records that link from this object to
559          * others.      We have to do this anyway, and doing it first ensures that we
560          * avoid infinite recursion in the case of cycles. Also, some dependency
561          * types require extra processing here.
562          *
563          * When dropping a whole object (subId = 0), remove all pg_depend records
564          * for its sub-objects too.
565          */
566         ScanKeyInit(&key[0],
567                                 Anum_pg_depend_classid,
568                                 BTEqualStrategyNumber, F_OIDEQ,
569                                 ObjectIdGetDatum(object->classId));
570         ScanKeyInit(&key[1],
571                                 Anum_pg_depend_objid,
572                                 BTEqualStrategyNumber, F_OIDEQ,
573                                 ObjectIdGetDatum(object->objectId));
574         if (object->objectSubId != 0)
575         {
576                 ScanKeyInit(&key[2],
577                                         Anum_pg_depend_objsubid,
578                                         BTEqualStrategyNumber, F_INT4EQ,
579                                         Int32GetDatum(object->objectSubId));
580                 nkeys = 3;
581         }
582         else
583                 nkeys = 2;
584
585         scan = systable_beginscan(depRel, DependDependerIndexId, true,
586                                                           SnapshotNow, nkeys, key);
587
588         while (HeapTupleIsValid(tup = systable_getnext(scan)))
589         {
590                 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
591
592                 otherObject.classId = foundDep->refclassid;
593                 otherObject.objectId = foundDep->refobjid;
594                 otherObject.objectSubId = foundDep->refobjsubid;
595
596                 switch (foundDep->deptype)
597                 {
598                         case DEPENDENCY_NORMAL:
599                         case DEPENDENCY_AUTO:
600                                 /* no problem */
601                                 break;
602                         case DEPENDENCY_INTERNAL:
603
604                                 /*
605                                  * This object is part of the internal implementation of
606                                  * another object.      We have three cases:
607                                  *
608                                  * 1. At the outermost recursion level, disallow the DROP. (We
609                                  * just ereport here, rather than proceeding, since no other
610                                  * dependencies are likely to be interesting.)
611                                  */
612                                 if (callingObject == NULL)
613                                 {
614                                         char       *otherObjDesc = getObjectDescription(&otherObject);
615
616                                         ereport(ERROR,
617                                                         (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
618                                                          errmsg("cannot drop %s because %s requires it",
619                                                                         objDescription, otherObjDesc),
620                                                          errhint("You can drop %s instead.",
621                                                                          otherObjDesc)));
622                                 }
623
624                                 /*
625                                  * 2. When recursing from the other end of this dependency,
626                                  * it's okay to continue with the deletion. This holds when
627                                  * recursing from a whole object that includes the nominal
628                                  * other end as a component, too.
629                                  */
630                                 if (callingObject->classId == otherObject.classId &&
631                                         callingObject->objectId == otherObject.objectId &&
632                                         (callingObject->objectSubId == otherObject.objectSubId ||
633                                          callingObject->objectSubId == 0))
634                                         break;
635
636                                 /*
637                                  * 3. When recursing from anyplace else, transform this
638                                  * deletion request into a delete of the other object. (This
639                                  * will be an error condition iff RESTRICT mode.) In this case
640                                  * we finish deleting my dependencies except for the INTERNAL
641                                  * link, which will be needed to cause the owning object to
642                                  * recurse back to me.
643                                  */
644                                 if (amOwned)    /* shouldn't happen */
645                                         elog(ERROR, "multiple INTERNAL dependencies for %s",
646                                                  objDescription);
647                                 owningObject = otherObject;
648                                 amOwned = true;
649                                 /* "continue" bypasses the simple_heap_delete call below */
650                                 continue;
651                         case DEPENDENCY_PIN:
652
653                                 /*
654                                  * Should not happen; PIN dependencies should have zeroes in
655                                  * the depender fields...
656                                  */
657                                 elog(ERROR, "incorrect use of PIN dependency with %s",
658                                          objDescription);
659                                 break;
660                         default:
661                                 elog(ERROR, "unrecognized dependency type '%c' for %s",
662                                          foundDep->deptype, objDescription);
663                                 break;
664                 }
665
666                 /* delete the pg_depend tuple */
667                 simple_heap_delete(depRel, &tup->t_self);
668         }
669
670         systable_endscan(scan);
671
672         /*
673          * CommandCounterIncrement here to ensure that preceding changes are all
674          * visible; in particular, that the above deletions of pg_depend entries
675          * are visible.  That prevents infinite recursion in case of a dependency
676          * loop (which is perfectly legal).
677          */
678         CommandCounterIncrement();
679
680         /*
681          * If we found we are owned by another object, ask it to delete itself
682          * instead of proceeding.  Complain if RESTRICT mode, unless the other
683          * object is in oktodelete.
684          */
685         if (amOwned)
686         {
687                 if (object_address_present(&owningObject, oktodelete))
688                         ereport(DEBUG2,
689                                         (errmsg("drop auto-cascades to %s",
690                                                         getObjectDescription(&owningObject))));
691                 else if (behavior == DROP_RESTRICT)
692                 {
693                         ereport(msglevel,
694                                         (errmsg("%s depends on %s",
695                                                         getObjectDescription(&owningObject),
696                                                         objDescription)));
697                         ok = false;
698                 }
699                 else
700                         ereport(msglevel,
701                                         (errmsg("drop cascades to %s",
702                                                         getObjectDescription(&owningObject))));
703
704                 if (!recursiveDeletion(&owningObject, behavior, msglevel,
705                                                            object, oktodelete, depRel, alreadyDeleted))
706                         ok = false;
707
708                 pfree(objDescription);
709
710                 return ok;
711         }
712
713         /*
714          * Step 2: scan pg_depend records that link to this object, showing the
715          * things that depend on it.  Recursively delete those things. Note it's
716          * important to delete the dependent objects before the referenced one,
717          * since the deletion routines might do things like try to update the
718          * pg_class record when deleting a check constraint.
719          */
720         if (!deleteDependentObjects(object, objDescription,
721                                                                 behavior, msglevel,
722                                                                 oktodelete, depRel))
723                 ok = false;
724
725         /*
726          * We do not need CommandCounterIncrement here, since if step 2 did
727          * anything then each recursive call will have ended with one.
728          */
729
730         /*
731          * Step 3: delete the object itself, and save it to the list of deleted
732          * objects if appropiate.
733          */
734         doDeletion(object);
735         if (alreadyDeleted != NULL)
736         {
737                 if (!object_address_present(object, alreadyDeleted))
738                         add_exact_object_address(object, alreadyDeleted);
739         }
740
741         /*
742          * Delete any comments associated with this object.  (This is a convenient
743          * place to do it instead of having every object type know to do it.)
744          */
745         DeleteComments(object->objectId, object->classId, object->objectSubId);
746
747         /*
748          * Delete shared dependency references related to this object. Sub-objects
749          * (columns) don't have dependencies on global objects, so skip them.
750          */
751         if (object->objectSubId == 0)
752                 deleteSharedDependencyRecordsFor(object->classId, object->objectId);
753
754         /*
755          * CommandCounterIncrement here to ensure that preceding changes are all
756          * visible.
757          */
758         CommandCounterIncrement();
759
760         /*
761          * And we're done!
762          */
763         pfree(objDescription);
764
765         return ok;
766 }
767
768
769 /*
770  * deleteDependentObjects - find and delete objects that depend on 'object'
771  *
772  * Scan pg_depend records that link to the given object, showing
773  * the things that depend on it.  Recursively delete those things. (We
774  * don't delete the pg_depend records here, as the recursive call will
775  * do that.)  Note it's important to delete the dependent objects
776  * before the referenced one, since the deletion routines might do
777  * things like try to update the pg_class record when deleting a check
778  * constraint.
779  *
780  * When dropping a whole object (subId = 0), find pg_depend records for
781  * its sub-objects too.
782  *
783  *      object: the object to find dependencies on
784  *      objDescription: description of object (only used for error messages)
785  *      behavior: desired drop behavior
786  *      oktodelete: stuff that's AUTO-deletable
787  *      depRel: already opened pg_depend relation
788  *
789  * Returns TRUE if all is well, false if any problem found.
790  *
791  * NOTE: because we are using SnapshotNow, if a recursive call deletes
792  * any pg_depend tuples that our scan hasn't yet visited, we will not
793  * see them as good when we do visit them.      This is essential for
794  * correct behavior if there are multiple dependency paths between two
795  * objects --- else we might try to delete an already-deleted object.
796  */
797 static bool
798 deleteDependentObjects(const ObjectAddress *object,
799                                            const char *objDescription,
800                                            DropBehavior behavior,
801                                            int msglevel,
802                                            ObjectAddresses *oktodelete,
803                                            Relation depRel)
804 {
805         bool            ok = true;
806         ScanKeyData key[3];
807         int                     nkeys;
808         SysScanDesc scan;
809         HeapTuple       tup;
810         ObjectAddress otherObject;
811
812         ScanKeyInit(&key[0],
813                                 Anum_pg_depend_refclassid,
814                                 BTEqualStrategyNumber, F_OIDEQ,
815                                 ObjectIdGetDatum(object->classId));
816         ScanKeyInit(&key[1],
817                                 Anum_pg_depend_refobjid,
818                                 BTEqualStrategyNumber, F_OIDEQ,
819                                 ObjectIdGetDatum(object->objectId));
820         if (object->objectSubId != 0)
821         {
822                 ScanKeyInit(&key[2],
823                                         Anum_pg_depend_refobjsubid,
824                                         BTEqualStrategyNumber, F_INT4EQ,
825                                         Int32GetDatum(object->objectSubId));
826                 nkeys = 3;
827         }
828         else
829                 nkeys = 2;
830
831         scan = systable_beginscan(depRel, DependReferenceIndexId, true,
832                                                           SnapshotNow, nkeys, key);
833
834         while (HeapTupleIsValid(tup = systable_getnext(scan)))
835         {
836                 Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
837
838                 otherObject.classId = foundDep->classid;
839                 otherObject.objectId = foundDep->objid;
840                 otherObject.objectSubId = foundDep->objsubid;
841
842                 switch (foundDep->deptype)
843                 {
844                         case DEPENDENCY_NORMAL:
845
846                                 /*
847                                  * Perhaps there was another dependency path that would have
848                                  * allowed silent deletion of the otherObject, had we only
849                                  * taken that path first. In that case, act like this link is
850                                  * AUTO, too.
851                                  */
852                                 if (object_address_present(&otherObject, oktodelete))
853                                         ereport(DEBUG2,
854                                                         (errmsg("drop auto-cascades to %s",
855                                                                         getObjectDescription(&otherObject))));
856                                 else if (behavior == DROP_RESTRICT)
857                                 {
858                                         ereport(msglevel,
859                                                         (errmsg("%s depends on %s",
860                                                                         getObjectDescription(&otherObject),
861                                                                         objDescription)));
862                                         ok = false;
863                                 }
864                                 else
865                                         ereport(msglevel,
866                                                         (errmsg("drop cascades to %s",
867                                                                         getObjectDescription(&otherObject))));
868
869                                 if (!recursiveDeletion(&otherObject, behavior, msglevel,
870                                                                            object, oktodelete, depRel, NULL))
871                                         ok = false;
872                                 break;
873                         case DEPENDENCY_AUTO:
874                         case DEPENDENCY_INTERNAL:
875
876                                 /*
877                                  * We propagate the DROP without complaint even in the
878                                  * RESTRICT case.  (However, normal dependencies on the
879                                  * component object could still cause failure.)
880                                  */
881                                 ereport(DEBUG2,
882                                                 (errmsg("drop auto-cascades to %s",
883                                                                 getObjectDescription(&otherObject))));
884
885                                 if (!recursiveDeletion(&otherObject, behavior, msglevel,
886                                                                            object, oktodelete, depRel, NULL))
887                                         ok = false;
888                                 break;
889                         case DEPENDENCY_PIN:
890
891                                 /*
892                                  * For a PIN dependency we just ereport immediately; there
893                                  * won't be any others to report.
894                                  */
895                                 ereport(ERROR,
896                                                 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
897                                                  errmsg("cannot drop %s because it is required by the database system",
898                                                                 objDescription)));
899                                 break;
900                         default:
901                                 elog(ERROR, "unrecognized dependency type '%c' for %s",
902                                          foundDep->deptype, objDescription);
903                                 break;
904                 }
905         }
906
907         systable_endscan(scan);
908
909         return ok;
910 }
911
912
913 /*
914  * doDeletion: actually delete a single object
915  */
916 static void
917 doDeletion(const ObjectAddress *object)
918 {
919         switch (getObjectClass(object))
920         {
921                 case OCLASS_CLASS:
922                         {
923                                 char            relKind = get_rel_relkind(object->objectId);
924
925                                 if (relKind == RELKIND_INDEX)
926                                 {
927                                         Assert(object->objectSubId == 0);
928                                         index_drop(object->objectId);
929                                 }
930                                 else
931                                 {
932                                         if (object->objectSubId != 0)
933                                                 RemoveAttributeById(object->objectId,
934                                                                                         object->objectSubId);
935                                         else
936                                                 heap_drop_with_catalog(object->objectId);
937                                 }
938                                 break;
939                         }
940
941                 case OCLASS_PROC:
942                         RemoveFunctionById(object->objectId);
943                         break;
944
945                 case OCLASS_TYPE:
946                         RemoveTypeById(object->objectId);
947                         break;
948
949                 case OCLASS_CAST:
950                         DropCastById(object->objectId);
951                         break;
952
953                 case OCLASS_CONSTRAINT:
954                         RemoveConstraintById(object->objectId);
955                         break;
956
957                 case OCLASS_CONVERSION:
958                         RemoveConversionById(object->objectId);
959                         break;
960
961                 case OCLASS_DEFAULT:
962                         RemoveAttrDefaultById(object->objectId);
963                         break;
964
965                 case OCLASS_LANGUAGE:
966                         DropProceduralLanguageById(object->objectId);
967                         break;
968
969                 case OCLASS_OPERATOR:
970                         RemoveOperatorById(object->objectId);
971                         break;
972
973                 case OCLASS_OPCLASS:
974                         RemoveOpClassById(object->objectId);
975                         break;
976
977                 case OCLASS_OPFAMILY:
978                         RemoveOpFamilyById(object->objectId);
979                         break;
980
981                 case OCLASS_AMOP:
982                         RemoveAmOpEntryById(object->objectId);
983                         break;
984
985                 case OCLASS_AMPROC:
986                         RemoveAmProcEntryById(object->objectId);
987                         break;
988
989                 case OCLASS_REWRITE:
990                         RemoveRewriteRuleById(object->objectId);
991                         break;
992
993                 case OCLASS_TRIGGER:
994                         RemoveTriggerById(object->objectId);
995                         break;
996
997                 case OCLASS_SCHEMA:
998                         RemoveSchemaById(object->objectId);
999                         break;
1000
1001                 case OCLASS_TSPARSER:
1002                         RemoveTSParserById(object->objectId);
1003                         break;
1004
1005                 case OCLASS_TSDICT:
1006                         RemoveTSDictionaryById(object->objectId);
1007                         break;
1008
1009                 case OCLASS_TSTEMPLATE:
1010                         RemoveTSTemplateById(object->objectId);
1011                         break;
1012
1013                 case OCLASS_TSCONFIG:
1014                         RemoveTSConfigurationById(object->objectId);
1015                         break;
1016
1017                         /* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
1018
1019                 default:
1020                         elog(ERROR, "unrecognized object class: %u",
1021                                  object->classId);
1022         }
1023 }
1024
1025 /*
1026  * recordDependencyOnExpr - find expression dependencies
1027  *
1028  * This is used to find the dependencies of rules, constraint expressions,
1029  * etc.
1030  *
1031  * Given an expression or query in node-tree form, find all the objects
1032  * it refers to (tables, columns, operators, functions, etc).  Record
1033  * a dependency of the specified type from the given depender object
1034  * to each object mentioned in the expression.
1035  *
1036  * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
1037  * It can be NIL if no such variables are expected.
1038  */
1039 void
1040 recordDependencyOnExpr(const ObjectAddress *depender,
1041                                            Node *expr, List *rtable,
1042                                            DependencyType behavior)
1043 {
1044         find_expr_references_context context;
1045
1046         context.addrs = new_object_addresses();
1047
1048         /* Set up interpretation for Vars at varlevelsup = 0 */
1049         context.rtables = list_make1(rtable);
1050
1051         /* Scan the expression tree for referenceable objects */
1052         find_expr_references_walker(expr, &context);
1053
1054         /* Remove any duplicates */
1055         eliminate_duplicate_dependencies(context.addrs);
1056
1057         /* And record 'em */
1058         recordMultipleDependencies(depender,
1059                                                            context.addrs->refs, context.addrs->numrefs,
1060                                                            behavior);
1061
1062         free_object_addresses(context.addrs);
1063 }
1064
1065 /*
1066  * recordDependencyOnSingleRelExpr - find expression dependencies
1067  *
1068  * As above, but only one relation is expected to be referenced (with
1069  * varno = 1 and varlevelsup = 0).      Pass the relation OID instead of a
1070  * range table.  An additional frammish is that dependencies on that
1071  * relation (or its component columns) will be marked with 'self_behavior',
1072  * whereas 'behavior' is used for everything else.
1073  */
1074 void
1075 recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
1076                                                                 Node *expr, Oid relId,
1077                                                                 DependencyType behavior,
1078                                                                 DependencyType self_behavior)
1079 {
1080         find_expr_references_context context;
1081         RangeTblEntry rte;
1082
1083         context.addrs = new_object_addresses();
1084
1085         /* We gin up a rather bogus rangetable list to handle Vars */
1086         MemSet(&rte, 0, sizeof(rte));
1087         rte.type = T_RangeTblEntry;
1088         rte.rtekind = RTE_RELATION;
1089         rte.relid = relId;
1090
1091         context.rtables = list_make1(list_make1(&rte));
1092
1093         /* Scan the expression tree for referenceable objects */
1094         find_expr_references_walker(expr, &context);
1095
1096         /* Remove any duplicates */
1097         eliminate_duplicate_dependencies(context.addrs);
1098
1099         /* Separate self-dependencies if necessary */
1100         if (behavior != self_behavior && context.addrs->numrefs > 0)
1101         {
1102                 ObjectAddresses *self_addrs;
1103                 ObjectAddress *outobj;
1104                 int                     oldref,
1105                                         outrefs;
1106
1107                 self_addrs = new_object_addresses();
1108
1109                 outobj = context.addrs->refs;
1110                 outrefs = 0;
1111                 for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
1112                 {
1113                         ObjectAddress *thisobj = context.addrs->refs + oldref;
1114
1115                         if (thisobj->classId == RelationRelationId &&
1116                                 thisobj->objectId == relId)
1117                         {
1118                                 /* Move this ref into self_addrs */
1119                                 add_object_address(OCLASS_CLASS, relId, thisobj->objectSubId,
1120                                                                    self_addrs);
1121                         }
1122                         else
1123                         {
1124                                 /* Keep it in context.addrs */
1125                                 outobj->classId = thisobj->classId;
1126                                 outobj->objectId = thisobj->objectId;
1127                                 outobj->objectSubId = thisobj->objectSubId;
1128                                 outobj++;
1129                                 outrefs++;
1130                         }
1131                 }
1132                 context.addrs->numrefs = outrefs;
1133
1134                 /* Record the self-dependencies */
1135                 recordMultipleDependencies(depender,
1136                                                                    self_addrs->refs, self_addrs->numrefs,
1137                                                                    self_behavior);
1138
1139                 free_object_addresses(self_addrs);
1140         }
1141
1142         /* Record the external dependencies */
1143         recordMultipleDependencies(depender,
1144                                                            context.addrs->refs, context.addrs->numrefs,
1145                                                            behavior);
1146
1147         free_object_addresses(context.addrs);
1148 }
1149
1150 /*
1151  * Recursively search an expression tree for object references.
1152  *
1153  * Note: we avoid creating references to columns of tables that participate
1154  * in an SQL JOIN construct, but are not actually used anywhere in the query.
1155  * To do so, we do not scan the joinaliasvars list of a join RTE while
1156  * scanning the query rangetable, but instead scan each individual entry
1157  * of the alias list when we find a reference to it.
1158  *
1159  * Note: in many cases we do not need to create dependencies on the datatypes
1160  * involved in an expression, because we'll have an indirect dependency via
1161  * some other object.  For instance Var nodes depend on a column which depends
1162  * on the datatype, and OpExpr nodes depend on the operator which depends on
1163  * the datatype.  However we do need a type dependency if there is no such
1164  * indirect dependency, as for example in Const and CoerceToDomain nodes.
1165  */
1166 static bool
1167 find_expr_references_walker(Node *node,
1168                                                         find_expr_references_context *context)
1169 {
1170         if (node == NULL)
1171                 return false;
1172         if (IsA(node, Var))
1173         {
1174                 Var                *var = (Var *) node;
1175                 List       *rtable;
1176                 RangeTblEntry *rte;
1177
1178                 /* Find matching rtable entry, or complain if not found */
1179                 if (var->varlevelsup >= list_length(context->rtables))
1180                         elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
1181                 rtable = (List *) list_nth(context->rtables, var->varlevelsup);
1182                 if (var->varno <= 0 || var->varno > list_length(rtable))
1183                         elog(ERROR, "invalid varno %d", var->varno);
1184                 rte = rt_fetch(var->varno, rtable);
1185
1186                 /*
1187                  * A whole-row Var references no specific columns, so adds no new
1188                  * dependency.
1189                  */
1190                 if (var->varattno == InvalidAttrNumber)
1191                         return false;
1192                 if (rte->rtekind == RTE_RELATION)
1193                 {
1194                         /* If it's a plain relation, reference this column */
1195                         add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
1196                                                            context->addrs);
1197                 }
1198                 else if (rte->rtekind == RTE_JOIN)
1199                 {
1200                         /* Scan join output column to add references to join inputs */
1201                         List       *save_rtables;
1202
1203                         /* We must make the context appropriate for join's level */
1204                         save_rtables = context->rtables;
1205                         context->rtables = list_copy_tail(context->rtables,
1206                                                                                           var->varlevelsup);
1207                         if (var->varattno <= 0 ||
1208                                 var->varattno > list_length(rte->joinaliasvars))
1209                                 elog(ERROR, "invalid varattno %d", var->varattno);
1210                         find_expr_references_walker((Node *) list_nth(rte->joinaliasvars,
1211                                                                                                                   var->varattno - 1),
1212                                                                                 context);
1213                         list_free(context->rtables);
1214                         context->rtables = save_rtables;
1215                 }
1216                 return false;
1217         }
1218         if (IsA(node, Const))
1219         {
1220                 Const      *con = (Const *) node;
1221                 Oid                     objoid;
1222
1223                 /* A constant must depend on the constant's datatype */
1224                 add_object_address(OCLASS_TYPE, con->consttype, 0,
1225                                                    context->addrs);
1226
1227                 /*
1228                  * If it's a regclass or similar literal referring to an existing
1229                  * object, add a reference to that object.      (Currently, only the
1230                  * regclass and regconfig cases have any likely use, but we may as
1231                  * well handle all the OID-alias datatypes consistently.)
1232                  */
1233                 if (!con->constisnull)
1234                 {
1235                         switch (con->consttype)
1236                         {
1237                                 case REGPROCOID:
1238                                 case REGPROCEDUREOID:
1239                                         objoid = DatumGetObjectId(con->constvalue);
1240                                         if (SearchSysCacheExists(PROCOID,
1241                                                                                          ObjectIdGetDatum(objoid),
1242                                                                                          0, 0, 0))
1243                                                 add_object_address(OCLASS_PROC, objoid, 0,
1244                                                                                    context->addrs);
1245                                         break;
1246                                 case REGOPEROID:
1247                                 case REGOPERATOROID:
1248                                         objoid = DatumGetObjectId(con->constvalue);
1249                                         if (SearchSysCacheExists(OPEROID,
1250                                                                                          ObjectIdGetDatum(objoid),
1251                                                                                          0, 0, 0))
1252                                                 add_object_address(OCLASS_OPERATOR, objoid, 0,
1253                                                                                    context->addrs);
1254                                         break;
1255                                 case REGCLASSOID:
1256                                         objoid = DatumGetObjectId(con->constvalue);
1257                                         if (SearchSysCacheExists(RELOID,
1258                                                                                          ObjectIdGetDatum(objoid),
1259                                                                                          0, 0, 0))
1260                                                 add_object_address(OCLASS_CLASS, objoid, 0,
1261                                                                                    context->addrs);
1262                                         break;
1263                                 case REGTYPEOID:
1264                                         objoid = DatumGetObjectId(con->constvalue);
1265                                         if (SearchSysCacheExists(TYPEOID,
1266                                                                                          ObjectIdGetDatum(objoid),
1267                                                                                          0, 0, 0))
1268                                                 add_object_address(OCLASS_TYPE, objoid, 0,
1269                                                                                    context->addrs);
1270                                         break;
1271                                 case REGCONFIGOID:
1272                                         objoid = DatumGetObjectId(con->constvalue);
1273                                         if (SearchSysCacheExists(TSCONFIGOID,
1274                                                                                          ObjectIdGetDatum(objoid),
1275                                                                                          0, 0, 0))
1276                                                 add_object_address(OCLASS_TSCONFIG, objoid, 0,
1277                                                                                    context->addrs);
1278                                         break;
1279                                 case REGDICTIONARYOID:
1280                                         objoid = DatumGetObjectId(con->constvalue);
1281                                         if (SearchSysCacheExists(TSDICTOID,
1282                                                                                          ObjectIdGetDatum(objoid),
1283                                                                                          0, 0, 0))
1284                                                 add_object_address(OCLASS_TSDICT, objoid, 0,
1285                                                                                    context->addrs);
1286                                         break;
1287                         }
1288                 }
1289                 return false;
1290         }
1291         if (IsA(node, Param))
1292         {
1293                 Param      *param = (Param *) node;
1294
1295                 /* A parameter must depend on the parameter's datatype */
1296                 add_object_address(OCLASS_TYPE, param->paramtype, 0,
1297                                                    context->addrs);
1298         }
1299         if (IsA(node, FuncExpr))
1300         {
1301                 FuncExpr   *funcexpr = (FuncExpr *) node;
1302
1303                 add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
1304                                                    context->addrs);
1305                 /* fall through to examine arguments */
1306         }
1307         if (IsA(node, OpExpr))
1308         {
1309                 OpExpr     *opexpr = (OpExpr *) node;
1310
1311                 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1312                                                    context->addrs);
1313                 /* fall through to examine arguments */
1314         }
1315         if (IsA(node, DistinctExpr))
1316         {
1317                 DistinctExpr *distinctexpr = (DistinctExpr *) node;
1318
1319                 add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
1320                                                    context->addrs);
1321                 /* fall through to examine arguments */
1322         }
1323         if (IsA(node, ScalarArrayOpExpr))
1324         {
1325                 ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1326
1327                 add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
1328                                                    context->addrs);
1329                 /* fall through to examine arguments */
1330         }
1331         if (IsA(node, NullIfExpr))
1332         {
1333                 NullIfExpr *nullifexpr = (NullIfExpr *) node;
1334
1335                 add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
1336                                                    context->addrs);
1337                 /* fall through to examine arguments */
1338         }
1339         if (IsA(node, Aggref))
1340         {
1341                 Aggref     *aggref = (Aggref *) node;
1342
1343                 add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
1344                                                    context->addrs);
1345                 /* fall through to examine arguments */
1346         }
1347         if (is_subplan(node))
1348         {
1349                 /* Extra work needed here if we ever need this case */
1350                 elog(ERROR, "already-planned subqueries not supported");
1351         }
1352         if (IsA(node, RelabelType))
1353         {
1354                 RelabelType *relab = (RelabelType *) node;
1355
1356                 /* since there is no function dependency, need to depend on type */
1357                 add_object_address(OCLASS_TYPE, relab->resulttype, 0,
1358                                                    context->addrs);
1359         }
1360         if (IsA(node, CoerceViaIO))
1361         {
1362                 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1363
1364                 /* since there is no exposed function, need to depend on type */
1365                 add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0,
1366                                                    context->addrs);
1367         }
1368         if (IsA(node, ArrayCoerceExpr))
1369         {
1370                 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1371
1372                 if (OidIsValid(acoerce->elemfuncid))
1373                         add_object_address(OCLASS_PROC, acoerce->elemfuncid, 0,
1374                                                            context->addrs);
1375                 add_object_address(OCLASS_TYPE, acoerce->resulttype, 0,
1376                                                    context->addrs);
1377                 /* fall through to examine arguments */
1378         }
1379         if (IsA(node, ConvertRowtypeExpr))
1380         {
1381                 ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
1382
1383                 /* since there is no function dependency, need to depend on type */
1384                 add_object_address(OCLASS_TYPE, cvt->resulttype, 0,
1385                                                    context->addrs);
1386         }
1387         if (IsA(node, RowExpr))
1388         {
1389                 RowExpr    *rowexpr = (RowExpr *) node;
1390
1391                 add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
1392                                                    context->addrs);
1393         }
1394         if (IsA(node, RowCompareExpr))
1395         {
1396                 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1397                 ListCell   *l;
1398
1399                 foreach(l, rcexpr->opnos)
1400                 {
1401                         add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
1402                                                            context->addrs);
1403                 }
1404                 foreach(l, rcexpr->opfamilies)
1405                 {
1406                         add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
1407                                                            context->addrs);
1408                 }
1409                 /* fall through to examine arguments */
1410         }
1411         if (IsA(node, CoerceToDomain))
1412         {
1413                 CoerceToDomain *cd = (CoerceToDomain *) node;
1414
1415                 add_object_address(OCLASS_TYPE, cd->resulttype, 0,
1416                                                    context->addrs);
1417         }
1418         if (IsA(node, Query))
1419         {
1420                 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1421                 Query      *query = (Query *) node;
1422                 ListCell   *rtable;
1423                 bool            result;
1424
1425                 /*
1426                  * Add whole-relation refs for each plain relation mentioned in the
1427                  * subquery's rtable, as well as datatype refs for any datatypes used
1428                  * as a RECORD function's output.  (Note: query_tree_walker takes care
1429                  * of recursing into RTE_FUNCTION and RTE_SUBQUERY RTEs, so no need to
1430                  * do that here.  But keep it from looking at join alias lists.)
1431                  */
1432                 foreach(rtable, query->rtable)
1433                 {
1434                         RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtable);
1435                         ListCell   *ct;
1436
1437                         switch (rte->rtekind)
1438                         {
1439                                 case RTE_RELATION:
1440                                         add_object_address(OCLASS_CLASS, rte->relid, 0,
1441                                                                            context->addrs);
1442                                         break;
1443                                 case RTE_FUNCTION:
1444                                         foreach(ct, rte->funccoltypes)
1445                                         {
1446                                                 add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0,
1447                                                                                    context->addrs);
1448                                         }
1449                                         break;
1450                                 default:
1451                                         break;
1452                         }
1453                 }
1454
1455                 /* Examine substructure of query */
1456                 context->rtables = lcons(query->rtable, context->rtables);
1457                 result = query_tree_walker(query,
1458                                                                    find_expr_references_walker,
1459                                                                    (void *) context,
1460                                                                    QTW_IGNORE_JOINALIASES);
1461                 context->rtables = list_delete_first(context->rtables);
1462                 return result;
1463         }
1464         return expression_tree_walker(node, find_expr_references_walker,
1465                                                                   (void *) context);
1466 }
1467
1468 /*
1469  * Given an array of dependency references, eliminate any duplicates.
1470  */
1471 static void
1472 eliminate_duplicate_dependencies(ObjectAddresses *addrs)
1473 {
1474         ObjectAddress *priorobj;
1475         int                     oldref,
1476                                 newrefs;
1477
1478         if (addrs->numrefs <= 1)
1479                 return;                                 /* nothing to do */
1480
1481         /* Sort the refs so that duplicates are adjacent */
1482         qsort((void *) addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
1483                   object_address_comparator);
1484
1485         /* Remove dups */
1486         priorobj = addrs->refs;
1487         newrefs = 1;
1488         for (oldref = 1; oldref < addrs->numrefs; oldref++)
1489         {
1490                 ObjectAddress *thisobj = addrs->refs + oldref;
1491
1492                 if (priorobj->classId == thisobj->classId &&
1493                         priorobj->objectId == thisobj->objectId)
1494                 {
1495                         if (priorobj->objectSubId == thisobj->objectSubId)
1496                                 continue;               /* identical, so drop thisobj */
1497
1498                         /*
1499                          * If we have a whole-object reference and a reference to a part
1500                          * of the same object, we don't need the whole-object reference
1501                          * (for example, we don't need to reference both table foo and
1502                          * column foo.bar).  The whole-object reference will always appear
1503                          * first in the sorted list.
1504                          */
1505                         if (priorobj->objectSubId == 0)
1506                         {
1507                                 /* replace whole ref with partial */
1508                                 priorobj->objectSubId = thisobj->objectSubId;
1509                                 continue;
1510                         }
1511                 }
1512                 /* Not identical, so add thisobj to output set */
1513                 priorobj++;
1514                 priorobj->classId = thisobj->classId;
1515                 priorobj->objectId = thisobj->objectId;
1516                 priorobj->objectSubId = thisobj->objectSubId;
1517                 newrefs++;
1518         }
1519
1520         addrs->numrefs = newrefs;
1521 }
1522
1523 /*
1524  * qsort comparator for ObjectAddress items
1525  */
1526 static int
1527 object_address_comparator(const void *a, const void *b)
1528 {
1529         const ObjectAddress *obja = (const ObjectAddress *) a;
1530         const ObjectAddress *objb = (const ObjectAddress *) b;
1531
1532         if (obja->classId < objb->classId)
1533                 return -1;
1534         if (obja->classId > objb->classId)
1535                 return 1;
1536         if (obja->objectId < objb->objectId)
1537                 return -1;
1538         if (obja->objectId > objb->objectId)
1539                 return 1;
1540
1541         /*
1542          * We sort the subId as an unsigned int so that 0 will come first. See
1543          * logic in eliminate_duplicate_dependencies.
1544          */
1545         if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
1546                 return -1;
1547         if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
1548                 return 1;
1549         return 0;
1550 }
1551
1552 /*
1553  * Routines for handling an expansible array of ObjectAddress items.
1554  *
1555  * new_object_addresses: create a new ObjectAddresses array.
1556  */
1557 ObjectAddresses *
1558 new_object_addresses(void)
1559 {
1560         ObjectAddresses *addrs;
1561
1562         addrs = palloc(sizeof(ObjectAddresses));
1563
1564         addrs->numrefs = 0;
1565         addrs->maxrefs = 32;
1566         addrs->refs = (ObjectAddress *)
1567                 palloc(addrs->maxrefs * sizeof(ObjectAddress));
1568
1569         return addrs;
1570 }
1571
1572 /*
1573  * Add an entry to an ObjectAddresses array.
1574  *
1575  * It is convenient to specify the class by ObjectClass rather than directly
1576  * by catalog OID.
1577  */
1578 static void
1579 add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
1580                                    ObjectAddresses *addrs)
1581 {
1582         ObjectAddress *item;
1583
1584         /* enlarge array if needed */
1585         if (addrs->numrefs >= addrs->maxrefs)
1586         {
1587                 addrs->maxrefs *= 2;
1588                 addrs->refs = (ObjectAddress *)
1589                         repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1590         }
1591         /* record this item */
1592         item = addrs->refs + addrs->numrefs;
1593         item->classId = object_classes[oclass];
1594         item->objectId = objectId;
1595         item->objectSubId = subId;
1596         addrs->numrefs++;
1597 }
1598
1599 /*
1600  * Add an entry to an ObjectAddresses array.
1601  *
1602  * As above, but specify entry exactly.
1603  */
1604 void
1605 add_exact_object_address(const ObjectAddress *object,
1606                                                  ObjectAddresses *addrs)
1607 {
1608         ObjectAddress *item;
1609
1610         /* enlarge array if needed */
1611         if (addrs->numrefs >= addrs->maxrefs)
1612         {
1613                 addrs->maxrefs *= 2;
1614                 addrs->refs = (ObjectAddress *)
1615                         repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
1616         }
1617         /* record this item */
1618         item = addrs->refs + addrs->numrefs;
1619         *item = *object;
1620         addrs->numrefs++;
1621 }
1622
1623 /*
1624  * Test whether an object is present in an ObjectAddresses array.
1625  *
1626  * We return "true" if object is a subobject of something in the array, too.
1627  */
1628 bool
1629 object_address_present(const ObjectAddress *object,
1630                                            ObjectAddresses *addrs)
1631 {
1632         int                     i;
1633
1634         for (i = addrs->numrefs - 1; i >= 0; i--)
1635         {
1636                 ObjectAddress *thisobj = addrs->refs + i;
1637
1638                 if (object->classId == thisobj->classId &&
1639                         object->objectId == thisobj->objectId)
1640                 {
1641                         if (object->objectSubId == thisobj->objectSubId ||
1642                                 thisobj->objectSubId == 0)
1643                                 return true;
1644                 }
1645         }
1646
1647         return false;
1648 }
1649
1650 /*
1651  * Record multiple dependencies from an ObjectAddresses array, after first
1652  * removing any duplicates.
1653  */
1654 void
1655 record_object_address_dependencies(const ObjectAddress *depender,
1656                                                                    ObjectAddresses *referenced,
1657                                                                    DependencyType behavior)
1658 {
1659         eliminate_duplicate_dependencies(referenced);
1660         recordMultipleDependencies(depender,
1661                                                            referenced->refs, referenced->numrefs,
1662                                                            behavior);
1663 }
1664
1665 /*
1666  * Clean up when done with an ObjectAddresses array.
1667  */
1668 void
1669 free_object_addresses(ObjectAddresses *addrs)
1670 {
1671         pfree(addrs->refs);
1672         pfree(addrs);
1673 }
1674
1675 /*
1676  * Determine the class of a given object identified by objectAddress.
1677  *
1678  * This function is essentially the reverse mapping for the object_classes[]
1679  * table.  We implement it as a function because the OIDs aren't consecutive.
1680  */
1681 ObjectClass
1682 getObjectClass(const ObjectAddress *object)
1683 {
1684         switch (object->classId)
1685         {
1686                 case RelationRelationId:
1687                         /* caller must check objectSubId */
1688                         return OCLASS_CLASS;
1689
1690                 case ProcedureRelationId:
1691                         Assert(object->objectSubId == 0);
1692                         return OCLASS_PROC;
1693
1694                 case TypeRelationId:
1695                         Assert(object->objectSubId == 0);
1696                         return OCLASS_TYPE;
1697
1698                 case CastRelationId:
1699                         Assert(object->objectSubId == 0);
1700                         return OCLASS_CAST;
1701
1702                 case ConstraintRelationId:
1703                         Assert(object->objectSubId == 0);
1704                         return OCLASS_CONSTRAINT;
1705
1706                 case ConversionRelationId:
1707                         Assert(object->objectSubId == 0);
1708                         return OCLASS_CONVERSION;
1709
1710                 case AttrDefaultRelationId:
1711                         Assert(object->objectSubId == 0);
1712                         return OCLASS_DEFAULT;
1713
1714                 case LanguageRelationId:
1715                         Assert(object->objectSubId == 0);
1716                         return OCLASS_LANGUAGE;
1717
1718                 case OperatorRelationId:
1719                         Assert(object->objectSubId == 0);
1720                         return OCLASS_OPERATOR;
1721
1722                 case OperatorClassRelationId:
1723                         Assert(object->objectSubId == 0);
1724                         return OCLASS_OPCLASS;
1725
1726                 case OperatorFamilyRelationId:
1727                         Assert(object->objectSubId == 0);
1728                         return OCLASS_OPFAMILY;
1729
1730                 case AccessMethodOperatorRelationId:
1731                         Assert(object->objectSubId == 0);
1732                         return OCLASS_AMOP;
1733
1734                 case AccessMethodProcedureRelationId:
1735                         Assert(object->objectSubId == 0);
1736                         return OCLASS_AMPROC;
1737
1738                 case RewriteRelationId:
1739                         Assert(object->objectSubId == 0);
1740                         return OCLASS_REWRITE;
1741
1742                 case TriggerRelationId:
1743                         Assert(object->objectSubId == 0);
1744                         return OCLASS_TRIGGER;
1745
1746                 case NamespaceRelationId:
1747                         Assert(object->objectSubId == 0);
1748                         return OCLASS_SCHEMA;
1749
1750                 case TSParserRelationId:
1751                         Assert(object->objectSubId == 0);
1752                         return OCLASS_TSPARSER;
1753
1754                 case TSDictionaryRelationId:
1755                         Assert(object->objectSubId == 0);
1756                         return OCLASS_TSDICT;
1757
1758                 case TSTemplateRelationId:
1759                         Assert(object->objectSubId == 0);
1760                         return OCLASS_TSTEMPLATE;
1761
1762                 case TSConfigRelationId:
1763                         Assert(object->objectSubId == 0);
1764                         return OCLASS_TSCONFIG;
1765
1766                 case AuthIdRelationId:
1767                         Assert(object->objectSubId == 0);
1768                         return OCLASS_ROLE;
1769
1770                 case DatabaseRelationId:
1771                         Assert(object->objectSubId == 0);
1772                         return OCLASS_DATABASE;
1773
1774                 case TableSpaceRelationId:
1775                         Assert(object->objectSubId == 0);
1776                         return OCLASS_TBLSPACE;
1777         }
1778
1779         /* shouldn't get here */
1780         elog(ERROR, "unrecognized object class: %u", object->classId);
1781         return OCLASS_CLASS;            /* keep compiler quiet */
1782 }
1783
1784 /*
1785  * getObjectDescription: build an object description for messages
1786  *
1787  * The result is a palloc'd string.
1788  */
1789 char *
1790 getObjectDescription(const ObjectAddress *object)
1791 {
1792         StringInfoData buffer;
1793
1794         initStringInfo(&buffer);
1795
1796         switch (getObjectClass(object))
1797         {
1798                 case OCLASS_CLASS:
1799                         getRelationDescription(&buffer, object->objectId);
1800                         if (object->objectSubId != 0)
1801                                 appendStringInfo(&buffer, _(" column %s"),
1802                                                                  get_relid_attribute_name(object->objectId,
1803                                                                                                            object->objectSubId));
1804                         break;
1805
1806                 case OCLASS_PROC:
1807                         appendStringInfo(&buffer, _("function %s"),
1808                                                          format_procedure(object->objectId));
1809                         break;
1810
1811                 case OCLASS_TYPE:
1812                         appendStringInfo(&buffer, _("type %s"),
1813                                                          format_type_be(object->objectId));
1814                         break;
1815
1816                 case OCLASS_CAST:
1817                         {
1818                                 Relation        castDesc;
1819                                 ScanKeyData skey[1];
1820                                 SysScanDesc rcscan;
1821                                 HeapTuple       tup;
1822                                 Form_pg_cast castForm;
1823
1824                                 castDesc = heap_open(CastRelationId, AccessShareLock);
1825
1826                                 ScanKeyInit(&skey[0],
1827                                                         ObjectIdAttributeNumber,
1828                                                         BTEqualStrategyNumber, F_OIDEQ,
1829                                                         ObjectIdGetDatum(object->objectId));
1830
1831                                 rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
1832                                                                                         SnapshotNow, 1, skey);
1833
1834                                 tup = systable_getnext(rcscan);
1835
1836                                 if (!HeapTupleIsValid(tup))
1837                                         elog(ERROR, "could not find tuple for cast %u",
1838                                                  object->objectId);
1839
1840                                 castForm = (Form_pg_cast) GETSTRUCT(tup);
1841
1842                                 appendStringInfo(&buffer, _("cast from %s to %s"),
1843                                                                  format_type_be(castForm->castsource),
1844                                                                  format_type_be(castForm->casttarget));
1845
1846                                 systable_endscan(rcscan);
1847                                 heap_close(castDesc, AccessShareLock);
1848                                 break;
1849                         }
1850
1851                 case OCLASS_CONSTRAINT:
1852                         {
1853                                 HeapTuple       conTup;
1854                                 Form_pg_constraint con;
1855
1856                                 conTup = SearchSysCache(CONSTROID,
1857                                                                                 ObjectIdGetDatum(object->objectId),
1858                                                                                 0, 0, 0);
1859                                 if (!HeapTupleIsValid(conTup))
1860                                         elog(ERROR, "cache lookup failed for constraint %u",
1861                                                  object->objectId);
1862                                 con = (Form_pg_constraint) GETSTRUCT(conTup);
1863
1864                                 if (OidIsValid(con->conrelid))
1865                                 {
1866                                         appendStringInfo(&buffer, _("constraint %s on "),
1867                                                                          NameStr(con->conname));
1868                                         getRelationDescription(&buffer, con->conrelid);
1869                                 }
1870                                 else
1871                                 {
1872                                         appendStringInfo(&buffer, _("constraint %s"),
1873                                                                          NameStr(con->conname));
1874                                 }
1875
1876                                 ReleaseSysCache(conTup);
1877                                 break;
1878                         }
1879
1880                 case OCLASS_CONVERSION:
1881                         {
1882                                 HeapTuple       conTup;
1883
1884                                 conTup = SearchSysCache(CONVOID,
1885                                                                                 ObjectIdGetDatum(object->objectId),
1886                                                                                 0, 0, 0);
1887                                 if (!HeapTupleIsValid(conTup))
1888                                         elog(ERROR, "cache lookup failed for conversion %u",
1889                                                  object->objectId);
1890                                 appendStringInfo(&buffer, _("conversion %s"),
1891                                  NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
1892                                 ReleaseSysCache(conTup);
1893                                 break;
1894                         }
1895
1896                 case OCLASS_DEFAULT:
1897                         {
1898                                 Relation        attrdefDesc;
1899                                 ScanKeyData skey[1];
1900                                 SysScanDesc adscan;
1901                                 HeapTuple       tup;
1902                                 Form_pg_attrdef attrdef;
1903                                 ObjectAddress colobject;
1904
1905                                 attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
1906
1907                                 ScanKeyInit(&skey[0],
1908                                                         ObjectIdAttributeNumber,
1909                                                         BTEqualStrategyNumber, F_OIDEQ,
1910                                                         ObjectIdGetDatum(object->objectId));
1911
1912                                 adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
1913                                                                                         true, SnapshotNow, 1, skey);
1914
1915                                 tup = systable_getnext(adscan);
1916
1917                                 if (!HeapTupleIsValid(tup))
1918                                         elog(ERROR, "could not find tuple for attrdef %u",
1919                                                  object->objectId);
1920
1921                                 attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
1922
1923                                 colobject.classId = RelationRelationId;
1924                                 colobject.objectId = attrdef->adrelid;
1925                                 colobject.objectSubId = attrdef->adnum;
1926
1927                                 appendStringInfo(&buffer, _("default for %s"),
1928                                                                  getObjectDescription(&colobject));
1929
1930                                 systable_endscan(adscan);
1931                                 heap_close(attrdefDesc, AccessShareLock);
1932                                 break;
1933                         }
1934
1935                 case OCLASS_LANGUAGE:
1936                         {
1937                                 HeapTuple       langTup;
1938
1939                                 langTup = SearchSysCache(LANGOID,
1940                                                                                  ObjectIdGetDatum(object->objectId),
1941                                                                                  0, 0, 0);
1942                                 if (!HeapTupleIsValid(langTup))
1943                                         elog(ERROR, "cache lookup failed for language %u",
1944                                                  object->objectId);
1945                                 appendStringInfo(&buffer, _("language %s"),
1946                                   NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
1947                                 ReleaseSysCache(langTup);
1948                                 break;
1949                         }
1950
1951                 case OCLASS_OPERATOR:
1952                         appendStringInfo(&buffer, _("operator %s"),
1953                                                          format_operator(object->objectId));
1954                         break;
1955
1956                 case OCLASS_OPCLASS:
1957                         {
1958                                 HeapTuple       opcTup;
1959                                 Form_pg_opclass opcForm;
1960                                 HeapTuple       amTup;
1961                                 Form_pg_am      amForm;
1962                                 char       *nspname;
1963
1964                                 opcTup = SearchSysCache(CLAOID,
1965                                                                                 ObjectIdGetDatum(object->objectId),
1966                                                                                 0, 0, 0);
1967                                 if (!HeapTupleIsValid(opcTup))
1968                                         elog(ERROR, "cache lookup failed for opclass %u",
1969                                                  object->objectId);
1970                                 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
1971
1972                                 amTup = SearchSysCache(AMOID,
1973                                                                            ObjectIdGetDatum(opcForm->opcmethod),
1974                                                                            0, 0, 0);
1975                                 if (!HeapTupleIsValid(amTup))
1976                                         elog(ERROR, "cache lookup failed for access method %u",
1977                                                  opcForm->opcmethod);
1978                                 amForm = (Form_pg_am) GETSTRUCT(amTup);
1979
1980                                 /* Qualify the name if not visible in search path */
1981                                 if (OpclassIsVisible(object->objectId))
1982                                         nspname = NULL;
1983                                 else
1984                                         nspname = get_namespace_name(opcForm->opcnamespace);
1985
1986                                 appendStringInfo(&buffer, _("operator class %s for access method %s"),
1987                                                                  quote_qualified_identifier(nspname,
1988                                                                                                   NameStr(opcForm->opcname)),
1989                                                                  NameStr(amForm->amname));
1990
1991                                 ReleaseSysCache(amTup);
1992                                 ReleaseSysCache(opcTup);
1993                                 break;
1994                         }
1995
1996                 case OCLASS_OPFAMILY:
1997                         getOpFamilyDescription(&buffer, object->objectId);
1998                         break;
1999
2000                 case OCLASS_AMOP:
2001                         {
2002                                 Relation        amopDesc;
2003                                 ScanKeyData skey[1];
2004                                 SysScanDesc amscan;
2005                                 HeapTuple       tup;
2006                                 Form_pg_amop amopForm;
2007
2008                                 amopDesc = heap_open(AccessMethodOperatorRelationId,
2009                                                                          AccessShareLock);
2010
2011                                 ScanKeyInit(&skey[0],
2012                                                         ObjectIdAttributeNumber,
2013                                                         BTEqualStrategyNumber, F_OIDEQ,
2014                                                         ObjectIdGetDatum(object->objectId));
2015
2016                                 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
2017                                                                                         SnapshotNow, 1, skey);
2018
2019                                 tup = systable_getnext(amscan);
2020
2021                                 if (!HeapTupleIsValid(tup))
2022                                         elog(ERROR, "could not find tuple for amop entry %u",
2023                                                  object->objectId);
2024
2025                                 amopForm = (Form_pg_amop) GETSTRUCT(tup);
2026
2027                                 appendStringInfo(&buffer, _("operator %d %s of "),
2028                                                                  amopForm->amopstrategy,
2029                                                                  format_operator(amopForm->amopopr));
2030                                 getOpFamilyDescription(&buffer, amopForm->amopfamily);
2031
2032                                 systable_endscan(amscan);
2033                                 heap_close(amopDesc, AccessShareLock);
2034                                 break;
2035                         }
2036
2037                 case OCLASS_AMPROC:
2038                         {
2039                                 Relation        amprocDesc;
2040                                 ScanKeyData skey[1];
2041                                 SysScanDesc amscan;
2042                                 HeapTuple       tup;
2043                                 Form_pg_amproc amprocForm;
2044
2045                                 amprocDesc = heap_open(AccessMethodProcedureRelationId,
2046                                                                            AccessShareLock);
2047
2048                                 ScanKeyInit(&skey[0],
2049                                                         ObjectIdAttributeNumber,
2050                                                         BTEqualStrategyNumber, F_OIDEQ,
2051                                                         ObjectIdGetDatum(object->objectId));
2052
2053                                 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
2054                                                                                         SnapshotNow, 1, skey);
2055
2056                                 tup = systable_getnext(amscan);
2057
2058                                 if (!HeapTupleIsValid(tup))
2059                                         elog(ERROR, "could not find tuple for amproc entry %u",
2060                                                  object->objectId);
2061
2062                                 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
2063
2064                                 appendStringInfo(&buffer, _("function %d %s of "),
2065                                                                  amprocForm->amprocnum,
2066                                                                  format_procedure(amprocForm->amproc));
2067                                 getOpFamilyDescription(&buffer, amprocForm->amprocfamily);
2068
2069                                 systable_endscan(amscan);
2070                                 heap_close(amprocDesc, AccessShareLock);
2071                                 break;
2072                         }
2073
2074                 case OCLASS_REWRITE:
2075                         {
2076                                 Relation        ruleDesc;
2077                                 ScanKeyData skey[1];
2078                                 SysScanDesc rcscan;
2079                                 HeapTuple       tup;
2080                                 Form_pg_rewrite rule;
2081
2082                                 ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
2083
2084                                 ScanKeyInit(&skey[0],
2085                                                         ObjectIdAttributeNumber,
2086                                                         BTEqualStrategyNumber, F_OIDEQ,
2087                                                         ObjectIdGetDatum(object->objectId));
2088
2089                                 rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
2090                                                                                         SnapshotNow, 1, skey);
2091
2092                                 tup = systable_getnext(rcscan);
2093
2094                                 if (!HeapTupleIsValid(tup))
2095                                         elog(ERROR, "could not find tuple for rule %u",
2096                                                  object->objectId);
2097
2098                                 rule = (Form_pg_rewrite) GETSTRUCT(tup);
2099
2100                                 appendStringInfo(&buffer, _("rule %s on "),
2101                                                                  NameStr(rule->rulename));
2102                                 getRelationDescription(&buffer, rule->ev_class);
2103
2104                                 systable_endscan(rcscan);
2105                                 heap_close(ruleDesc, AccessShareLock);
2106                                 break;
2107                         }
2108
2109                 case OCLASS_TRIGGER:
2110                         {
2111                                 Relation        trigDesc;
2112                                 ScanKeyData skey[1];
2113                                 SysScanDesc tgscan;
2114                                 HeapTuple       tup;
2115                                 Form_pg_trigger trig;
2116
2117                                 trigDesc = heap_open(TriggerRelationId, AccessShareLock);
2118
2119                                 ScanKeyInit(&skey[0],
2120                                                         ObjectIdAttributeNumber,
2121                                                         BTEqualStrategyNumber, F_OIDEQ,
2122                                                         ObjectIdGetDatum(object->objectId));
2123
2124                                 tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
2125                                                                                         SnapshotNow, 1, skey);
2126
2127                                 tup = systable_getnext(tgscan);
2128
2129                                 if (!HeapTupleIsValid(tup))
2130                                         elog(ERROR, "could not find tuple for trigger %u",
2131                                                  object->objectId);
2132
2133                                 trig = (Form_pg_trigger) GETSTRUCT(tup);
2134
2135                                 appendStringInfo(&buffer, _("trigger %s on "),
2136                                                                  NameStr(trig->tgname));
2137                                 getRelationDescription(&buffer, trig->tgrelid);
2138
2139                                 systable_endscan(tgscan);
2140                                 heap_close(trigDesc, AccessShareLock);
2141                                 break;
2142                         }
2143
2144                 case OCLASS_SCHEMA:
2145                         {
2146                                 char       *nspname;
2147
2148                                 nspname = get_namespace_name(object->objectId);
2149                                 if (!nspname)
2150                                         elog(ERROR, "cache lookup failed for namespace %u",
2151                                                  object->objectId);
2152                                 appendStringInfo(&buffer, _("schema %s"), nspname);
2153                                 break;
2154                         }
2155
2156                 case OCLASS_TSPARSER:
2157                         {
2158                                 HeapTuple       tup;
2159
2160                                 tup = SearchSysCache(TSPARSEROID,
2161                                                                          ObjectIdGetDatum(object->objectId),
2162                                                                          0, 0, 0);
2163                                 if (!HeapTupleIsValid(tup))
2164                                         elog(ERROR, "cache lookup failed for text search parser %u",
2165                                                  object->objectId);
2166                                 appendStringInfo(&buffer, _("text search parser %s"),
2167                                          NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
2168                                 ReleaseSysCache(tup);
2169                                 break;
2170                         }
2171
2172                 case OCLASS_TSDICT:
2173                         {
2174                                 HeapTuple       tup;
2175
2176                                 tup = SearchSysCache(TSDICTOID,
2177                                                                          ObjectIdGetDatum(object->objectId),
2178                                                                          0, 0, 0);
2179                                 if (!HeapTupleIsValid(tup))
2180                                         elog(ERROR, "cache lookup failed for text search dictionary %u",
2181                                                  object->objectId);
2182                                 appendStringInfo(&buffer, _("text search dictionary %s"),
2183                                           NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
2184                                 ReleaseSysCache(tup);
2185                                 break;
2186                         }
2187
2188                 case OCLASS_TSTEMPLATE:
2189                         {
2190                                 HeapTuple       tup;
2191
2192                                 tup = SearchSysCache(TSTEMPLATEOID,
2193                                                                          ObjectIdGetDatum(object->objectId),
2194                                                                          0, 0, 0);
2195                                 if (!HeapTupleIsValid(tup))
2196                                         elog(ERROR, "cache lookup failed for text search template %u",
2197                                                  object->objectId);
2198                                 appendStringInfo(&buffer, _("text search template %s"),
2199                                   NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
2200                                 ReleaseSysCache(tup);
2201                                 break;
2202                         }
2203
2204                 case OCLASS_TSCONFIG:
2205                         {
2206                                 HeapTuple       tup;
2207
2208                                 tup = SearchSysCache(TSCONFIGOID,
2209                                                                          ObjectIdGetDatum(object->objectId),
2210                                                                          0, 0, 0);
2211                                 if (!HeapTupleIsValid(tup))
2212                                         elog(ERROR, "cache lookup failed for text search configuration %u",
2213                                                  object->objectId);
2214                                 appendStringInfo(&buffer, _("text search configuration %s"),
2215                                          NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
2216                                 ReleaseSysCache(tup);
2217                                 break;
2218                         }
2219
2220                 case OCLASS_ROLE:
2221                         {
2222                                 appendStringInfo(&buffer, _("role %s"),
2223                                                                  GetUserNameFromId(object->objectId));
2224                                 break;
2225                         }
2226
2227                 case OCLASS_DATABASE:
2228                         {
2229                                 char       *datname;
2230
2231                                 datname = get_database_name(object->objectId);
2232                                 if (!datname)
2233                                         elog(ERROR, "cache lookup failed for database %u",
2234                                                  object->objectId);
2235                                 appendStringInfo(&buffer, _("database %s"), datname);
2236                                 break;
2237                         }
2238
2239                 case OCLASS_TBLSPACE:
2240                         {
2241                                 char       *tblspace;
2242
2243                                 tblspace = get_tablespace_name(object->objectId);
2244                                 if (!tblspace)
2245                                         elog(ERROR, "cache lookup failed for tablespace %u",
2246                                                  object->objectId);
2247                                 appendStringInfo(&buffer, _("tablespace %s"), tblspace);
2248                                 break;
2249                         }
2250
2251                 default:
2252                         appendStringInfo(&buffer, "unrecognized object %u %u %d",
2253                                                          object->classId,
2254                                                          object->objectId,
2255                                                          object->objectSubId);
2256                         break;
2257         }
2258
2259         return buffer.data;
2260 }
2261
2262 /*
2263  * subroutine for getObjectDescription: describe a relation
2264  */
2265 static void
2266 getRelationDescription(StringInfo buffer, Oid relid)
2267 {
2268         HeapTuple       relTup;
2269         Form_pg_class relForm;
2270         char       *nspname;
2271         char       *relname;
2272
2273         relTup = SearchSysCache(RELOID,
2274                                                         ObjectIdGetDatum(relid),
2275                                                         0, 0, 0);
2276         if (!HeapTupleIsValid(relTup))
2277                 elog(ERROR, "cache lookup failed for relation %u", relid);
2278         relForm = (Form_pg_class) GETSTRUCT(relTup);
2279
2280         /* Qualify the name if not visible in search path */
2281         if (RelationIsVisible(relid))
2282                 nspname = NULL;
2283         else
2284                 nspname = get_namespace_name(relForm->relnamespace);
2285
2286         relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
2287
2288         switch (relForm->relkind)
2289         {
2290                 case RELKIND_RELATION:
2291                         appendStringInfo(buffer, _("table %s"),
2292                                                          relname);
2293                         break;
2294                 case RELKIND_INDEX:
2295                         appendStringInfo(buffer, _("index %s"),
2296                                                          relname);
2297                         break;
2298                 case RELKIND_SEQUENCE:
2299                         appendStringInfo(buffer, _("sequence %s"),
2300                                                          relname);
2301                         break;
2302                 case RELKIND_UNCATALOGED:
2303                         appendStringInfo(buffer, _("uncataloged table %s"),
2304                                                          relname);
2305                         break;
2306                 case RELKIND_TOASTVALUE:
2307                         appendStringInfo(buffer, _("toast table %s"),
2308                                                          relname);
2309                         break;
2310                 case RELKIND_VIEW:
2311                         appendStringInfo(buffer, _("view %s"),
2312                                                          relname);
2313                         break;
2314                 case RELKIND_COMPOSITE_TYPE:
2315                         appendStringInfo(buffer, _("composite type %s"),
2316                                                          relname);
2317                         break;
2318                 default:
2319                         /* shouldn't get here */
2320                         appendStringInfo(buffer, _("relation %s"),
2321                                                          relname);
2322                         break;
2323         }
2324
2325         ReleaseSysCache(relTup);
2326 }
2327
2328 /*
2329  * subroutine for getObjectDescription: describe an operator family
2330  */
2331 static void
2332 getOpFamilyDescription(StringInfo buffer, Oid opfid)
2333 {
2334         HeapTuple       opfTup;
2335         Form_pg_opfamily opfForm;
2336         HeapTuple       amTup;
2337         Form_pg_am      amForm;
2338         char       *nspname;
2339
2340         opfTup = SearchSysCache(OPFAMILYOID,
2341                                                         ObjectIdGetDatum(opfid),
2342                                                         0, 0, 0);
2343         if (!HeapTupleIsValid(opfTup))
2344                 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
2345         opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
2346
2347         amTup = SearchSysCache(AMOID,
2348                                                    ObjectIdGetDatum(opfForm->opfmethod),
2349                                                    0, 0, 0);
2350         if (!HeapTupleIsValid(amTup))
2351                 elog(ERROR, "cache lookup failed for access method %u",
2352                          opfForm->opfmethod);
2353         amForm = (Form_pg_am) GETSTRUCT(amTup);
2354
2355         /* Qualify the name if not visible in search path */
2356         if (OpfamilyIsVisible(opfid))
2357                 nspname = NULL;
2358         else
2359                 nspname = get_namespace_name(opfForm->opfnamespace);
2360
2361         appendStringInfo(buffer, _("operator family %s for access method %s"),
2362                                          quote_qualified_identifier(nspname,
2363                                                                                                 NameStr(opfForm->opfname)),
2364                                          NameStr(amForm->amname));
2365
2366         ReleaseSysCache(amTup);
2367         ReleaseSysCache(opfTup);
2368 }