~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/catalog/dependency.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * dependency.c
 
4
 *        Routines to support inter-object dependencies.
 
5
 *
 
6
 *
 
7
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
8
 * Portions Copyright (c) 1994, Regents of the University of California
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        src/backend/catalog/dependency.c
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include "access/genam.h"
 
18
#include "access/heapam.h"
 
19
#include "access/sysattr.h"
 
20
#include "access/xact.h"
 
21
#include "catalog/dependency.h"
 
22
#include "catalog/heap.h"
 
23
#include "catalog/index.h"
 
24
#include "catalog/indexing.h"
 
25
#include "catalog/namespace.h"
 
26
#include "catalog/pg_amop.h"
 
27
#include "catalog/pg_amproc.h"
 
28
#include "catalog/pg_attrdef.h"
 
29
#include "catalog/pg_authid.h"
 
30
#include "catalog/pg_cast.h"
 
31
#include "catalog/pg_collation.h"
 
32
#include "catalog/pg_collation_fn.h"
 
33
#include "catalog/pg_constraint.h"
 
34
#include "catalog/pg_conversion.h"
 
35
#include "catalog/pg_conversion_fn.h"
 
36
#include "catalog/pg_database.h"
 
37
#include "catalog/pg_default_acl.h"
 
38
#include "catalog/pg_depend.h"
 
39
#include "catalog/pg_extension.h"
 
40
#include "catalog/pg_foreign_data_wrapper.h"
 
41
#include "catalog/pg_foreign_server.h"
 
42
#include "catalog/pg_foreign_table.h"
 
43
#include "catalog/pg_language.h"
 
44
#include "catalog/pg_largeobject.h"
 
45
#include "catalog/pg_namespace.h"
 
46
#include "catalog/pg_opclass.h"
 
47
#include "catalog/pg_operator.h"
 
48
#include "catalog/pg_opfamily.h"
 
49
#include "catalog/pg_proc.h"
 
50
#include "catalog/pg_rewrite.h"
 
51
#include "catalog/pg_tablespace.h"
 
52
#include "catalog/pg_trigger.h"
 
53
#include "catalog/pg_ts_config.h"
 
54
#include "catalog/pg_ts_dict.h"
 
55
#include "catalog/pg_ts_parser.h"
 
56
#include "catalog/pg_ts_template.h"
 
57
#include "catalog/pg_type.h"
 
58
#include "catalog/pg_user_mapping.h"
 
59
#include "commands/comment.h"
 
60
#include "commands/dbcommands.h"
 
61
#include "commands/defrem.h"
 
62
#include "commands/extension.h"
 
63
#include "commands/proclang.h"
 
64
#include "commands/schemacmds.h"
 
65
#include "commands/seclabel.h"
 
66
#include "commands/tablespace.h"
 
67
#include "commands/trigger.h"
 
68
#include "commands/typecmds.h"
 
69
#include "foreign/foreign.h"
 
70
#include "miscadmin.h"
 
71
#include "nodes/nodeFuncs.h"
 
72
#include "parser/parsetree.h"
 
73
#include "rewrite/rewriteRemove.h"
 
74
#include "storage/lmgr.h"
 
75
#include "utils/acl.h"
 
76
#include "utils/builtins.h"
 
77
#include "utils/fmgroids.h"
 
78
#include "utils/guc.h"
 
79
#include "utils/lsyscache.h"
 
80
#include "utils/syscache.h"
 
81
#include "utils/tqual.h"
 
82
 
 
83
 
 
84
/*
 
85
 * Deletion processing requires additional state for each ObjectAddress that
 
86
 * it's planning to delete.  For simplicity and code-sharing we make the
 
87
 * ObjectAddresses code support arrays with or without this extra state.
 
88
 */
 
89
typedef struct
 
90
{
 
91
        int                     flags;                  /* bitmask, see bit definitions below */
 
92
        ObjectAddress dependee;         /* object whose deletion forced this one */
 
93
} ObjectAddressExtra;
 
94
 
 
95
/* ObjectAddressExtra flag bits */
 
96
#define DEPFLAG_ORIGINAL        0x0001          /* an original deletion target */
 
97
#define DEPFLAG_NORMAL          0x0002          /* reached via normal dependency */
 
98
#define DEPFLAG_AUTO            0x0004          /* reached via auto dependency */
 
99
#define DEPFLAG_INTERNAL        0x0008          /* reached via internal dependency */
 
100
#define DEPFLAG_EXTENSION       0x0010          /* reached via extension dependency */
 
101
 
 
102
 
 
103
/* expansible list of ObjectAddresses */
 
104
struct ObjectAddresses
 
105
{
 
106
        ObjectAddress *refs;            /* => palloc'd array */
 
107
        ObjectAddressExtra *extras; /* => palloc'd array, or NULL if not used */
 
108
        int                     numrefs;                /* current number of references */
 
109
        int                     maxrefs;                /* current size of palloc'd array(s) */
 
110
};
 
111
 
 
112
/* typedef ObjectAddresses appears in dependency.h */
 
113
 
 
114
/* threaded list of ObjectAddresses, for recursion detection */
 
115
typedef struct ObjectAddressStack
 
116
{
 
117
        const ObjectAddress *object;    /* object being visited */
 
118
        int                     flags;                  /* its current flag bits */
 
119
        struct ObjectAddressStack *next;        /* next outer stack level */
 
120
} ObjectAddressStack;
 
121
 
 
122
/* for find_expr_references_walker */
 
123
typedef struct
 
124
{
 
125
        ObjectAddresses *addrs;         /* addresses being accumulated */
 
126
        List       *rtables;            /* list of rangetables to resolve Vars */
 
127
} find_expr_references_context;
 
128
 
 
129
/*
 
130
 * This constant table maps ObjectClasses to the corresponding catalog OIDs.
 
131
 * See also getObjectClass().
 
132
 */
 
133
static const Oid object_classes[MAX_OCLASS] = {
 
134
        RelationRelationId,                     /* OCLASS_CLASS */
 
135
        ProcedureRelationId,            /* OCLASS_PROC */
 
136
        TypeRelationId,                         /* OCLASS_TYPE */
 
137
        CastRelationId,                         /* OCLASS_CAST */
 
138
        CollationRelationId,            /* OCLASS_COLLATION */
 
139
        ConstraintRelationId,           /* OCLASS_CONSTRAINT */
 
140
        ConversionRelationId,           /* OCLASS_CONVERSION */
 
141
        AttrDefaultRelationId,          /* OCLASS_DEFAULT */
 
142
        LanguageRelationId,                     /* OCLASS_LANGUAGE */
 
143
        LargeObjectRelationId,          /* OCLASS_LARGEOBJECT */
 
144
        OperatorRelationId,                     /* OCLASS_OPERATOR */
 
145
        OperatorClassRelationId,        /* OCLASS_OPCLASS */
 
146
        OperatorFamilyRelationId,       /* OCLASS_OPFAMILY */
 
147
        AccessMethodOperatorRelationId,         /* OCLASS_AMOP */
 
148
        AccessMethodProcedureRelationId,        /* OCLASS_AMPROC */
 
149
        RewriteRelationId,                      /* OCLASS_REWRITE */
 
150
        TriggerRelationId,                      /* OCLASS_TRIGGER */
 
151
        NamespaceRelationId,            /* OCLASS_SCHEMA */
 
152
        TSParserRelationId,                     /* OCLASS_TSPARSER */
 
153
        TSDictionaryRelationId,         /* OCLASS_TSDICT */
 
154
        TSTemplateRelationId,           /* OCLASS_TSTEMPLATE */
 
155
        TSConfigRelationId,                     /* OCLASS_TSCONFIG */
 
156
        AuthIdRelationId,                       /* OCLASS_ROLE */
 
157
        DatabaseRelationId,                     /* OCLASS_DATABASE */
 
158
        TableSpaceRelationId,           /* OCLASS_TBLSPACE */
 
159
        ForeignDataWrapperRelationId,           /* OCLASS_FDW */
 
160
        ForeignServerRelationId,        /* OCLASS_FOREIGN_SERVER */
 
161
        UserMappingRelationId,          /* OCLASS_USER_MAPPING */
 
162
        DefaultAclRelationId,           /* OCLASS_DEFACL */
 
163
        ExtensionRelationId                     /* OCLASS_EXTENSION */
 
164
};
 
165
 
 
166
 
 
167
static void findDependentObjects(const ObjectAddress *object,
 
168
                                         int flags,
 
169
                                         ObjectAddressStack *stack,
 
170
                                         ObjectAddresses *targetObjects,
 
171
                                         const ObjectAddresses *pendingObjects,
 
172
                                         Relation depRel);
 
173
static void reportDependentObjects(const ObjectAddresses *targetObjects,
 
174
                                           DropBehavior behavior,
 
175
                                           int msglevel,
 
176
                                           const ObjectAddress *origObject);
 
177
static void deleteOneObject(const ObjectAddress *object, Relation depRel);
 
178
static void doDeletion(const ObjectAddress *object);
 
179
static void AcquireDeletionLock(const ObjectAddress *object);
 
180
static void ReleaseDeletionLock(const ObjectAddress *object);
 
181
static bool find_expr_references_walker(Node *node,
 
182
                                                        find_expr_references_context *context);
 
183
static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
 
184
static int      object_address_comparator(const void *a, const void *b);
 
185
static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
 
186
                                   ObjectAddresses *addrs);
 
187
static void add_exact_object_address_extra(const ObjectAddress *object,
 
188
                                                           const ObjectAddressExtra *extra,
 
189
                                                           ObjectAddresses *addrs);
 
190
static bool object_address_present_add_flags(const ObjectAddress *object,
 
191
                                                                 int flags,
 
192
                                                                 ObjectAddresses *addrs);
 
193
static void getRelationDescription(StringInfo buffer, Oid relid);
 
194
static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
 
195
 
 
196
 
 
197
/*
 
198
 * performDeletion: attempt to drop the specified object.  If CASCADE
 
199
 * behavior is specified, also drop any dependent objects (recursively).
 
200
 * If RESTRICT behavior is specified, error out if there are any dependent
 
201
 * objects, except for those that should be implicitly dropped anyway
 
202
 * according to the dependency type.
 
203
 *
 
204
 * This is the outer control routine for all forms of DROP that drop objects
 
205
 * that can participate in dependencies.  Note that the next two routines
 
206
 * are variants on the same theme; if you change anything here you'll likely
 
207
 * need to fix them too.
 
208
 */
 
209
void
 
210
performDeletion(const ObjectAddress *object,
 
211
                                DropBehavior behavior)
 
212
{
 
213
        Relation        depRel;
 
214
        ObjectAddresses *targetObjects;
 
215
        int                     i;
 
216
 
 
217
        /*
 
218
         * We save some cycles by opening pg_depend just once and passing the
 
219
         * Relation pointer down to all the recursive deletion steps.
 
220
         */
 
221
        depRel = heap_open(DependRelationId, RowExclusiveLock);
 
222
 
 
223
        /*
 
224
         * Acquire deletion lock on the target object.  (Ideally the caller has
 
225
         * done this already, but many places are sloppy about it.)
 
226
         */
 
227
        AcquireDeletionLock(object);
 
228
 
 
229
        /*
 
230
         * Construct a list of objects to delete (ie, the given object plus
 
231
         * everything directly or indirectly dependent on it).
 
232
         */
 
233
        targetObjects = new_object_addresses();
 
234
 
 
235
        findDependentObjects(object,
 
236
                                                 DEPFLAG_ORIGINAL,
 
237
                                                 NULL,  /* empty stack */
 
238
                                                 targetObjects,
 
239
                                                 NULL,  /* no pendingObjects */
 
240
                                                 depRel);
 
241
 
 
242
        /*
 
243
         * Check if deletion is allowed, and report about cascaded deletes.
 
244
         */
 
245
        reportDependentObjects(targetObjects,
 
246
                                                   behavior,
 
247
                                                   NOTICE,
 
248
                                                   object);
 
249
 
 
250
        /*
 
251
         * Delete all the objects in the proper order.
 
252
         */
 
253
        for (i = 0; i < targetObjects->numrefs; i++)
 
254
        {
 
255
                ObjectAddress *thisobj = targetObjects->refs + i;
 
256
 
 
257
                deleteOneObject(thisobj, depRel);
 
258
        }
 
259
 
 
260
        /* And clean up */
 
261
        free_object_addresses(targetObjects);
 
262
 
 
263
        heap_close(depRel, RowExclusiveLock);
 
264
}
 
265
 
 
266
/*
 
267
 * performMultipleDeletions: Similar to performDeletion, but act on multiple
 
268
 * objects at once.
 
269
 *
 
270
 * The main difference from issuing multiple performDeletion calls is that the
 
271
 * list of objects that would be implicitly dropped, for each object to be
 
272
 * dropped, is the union of the implicit-object list for all objects.  This
 
273
 * makes each check be more relaxed.
 
274
 */
 
275
void
 
276
performMultipleDeletions(const ObjectAddresses *objects,
 
277
                                                 DropBehavior behavior)
 
278
{
 
279
        Relation        depRel;
 
280
        ObjectAddresses *targetObjects;
 
281
        int                     i;
 
282
 
 
283
        /* No work if no objects... */
 
284
        if (objects->numrefs <= 0)
 
285
                return;
 
286
 
 
287
        /*
 
288
         * We save some cycles by opening pg_depend just once and passing the
 
289
         * Relation pointer down to all the recursive deletion steps.
 
290
         */
 
291
        depRel = heap_open(DependRelationId, RowExclusiveLock);
 
292
 
 
293
        /*
 
294
         * Construct a list of objects to delete (ie, the given objects plus
 
295
         * everything directly or indirectly dependent on them).  Note that
 
296
         * because we pass the whole objects list as pendingObjects context, we
 
297
         * won't get a failure from trying to delete an object that is internally
 
298
         * dependent on another one in the list; we'll just skip that object and
 
299
         * delete it when we reach its owner.
 
300
         */
 
301
        targetObjects = new_object_addresses();
 
302
 
 
303
        for (i = 0; i < objects->numrefs; i++)
 
304
        {
 
305
                const ObjectAddress *thisobj = objects->refs + i;
 
306
 
 
307
                /*
 
308
                 * Acquire deletion lock on each target object.  (Ideally the caller
 
309
                 * has done this already, but many places are sloppy about it.)
 
310
                 */
 
311
                AcquireDeletionLock(thisobj);
 
312
 
 
313
                findDependentObjects(thisobj,
 
314
                                                         DEPFLAG_ORIGINAL,
 
315
                                                         NULL,          /* empty stack */
 
316
                                                         targetObjects,
 
317
                                                         objects,
 
318
                                                         depRel);
 
319
        }
 
320
 
 
321
        /*
 
322
         * Check if deletion is allowed, and report about cascaded deletes.
 
323
         *
 
324
         * If there's exactly one object being deleted, report it the same way as
 
325
         * in performDeletion(), else we have to be vaguer.
 
326
         */
 
327
        reportDependentObjects(targetObjects,
 
328
                                                   behavior,
 
329
                                                   NOTICE,
 
330
                                                   (objects->numrefs == 1 ? objects->refs : NULL));
 
331
 
 
332
        /*
 
333
         * Delete all the objects in the proper order.
 
334
         */
 
335
        for (i = 0; i < targetObjects->numrefs; i++)
 
336
        {
 
337
                ObjectAddress *thisobj = targetObjects->refs + i;
 
338
 
 
339
                deleteOneObject(thisobj, depRel);
 
340
        }
 
341
 
 
342
        /* And clean up */
 
343
        free_object_addresses(targetObjects);
 
344
 
 
345
        heap_close(depRel, RowExclusiveLock);
 
346
}
 
347
 
 
348
/*
 
349
 * deleteWhatDependsOn: attempt to drop everything that depends on the
 
350
 * specified object, though not the object itself.      Behavior is always
 
351
 * CASCADE.
 
352
 *
 
353
 * This is currently used only to clean out the contents of a schema
 
354
 * (namespace): the passed object is a namespace.  We normally want this
 
355
 * to be done silently, so there's an option to suppress NOTICE messages.
 
356
 */
 
357
void
 
358
deleteWhatDependsOn(const ObjectAddress *object,
 
359
                                        bool showNotices)
 
360
{
 
361
        Relation        depRel;
 
362
        ObjectAddresses *targetObjects;
 
363
        int                     i;
 
364
 
 
365
        /*
 
366
         * We save some cycles by opening pg_depend just once and passing the
 
367
         * Relation pointer down to all the recursive deletion steps.
 
368
         */
 
369
        depRel = heap_open(DependRelationId, RowExclusiveLock);
 
370
 
 
371
        /*
 
372
         * Acquire deletion lock on the target object.  (Ideally the caller has
 
373
         * done this already, but many places are sloppy about it.)
 
374
         */
 
375
        AcquireDeletionLock(object);
 
376
 
 
377
        /*
 
378
         * Construct a list of objects to delete (ie, the given object plus
 
379
         * everything directly or indirectly dependent on it).
 
380
         */
 
381
        targetObjects = new_object_addresses();
 
382
 
 
383
        findDependentObjects(object,
 
384
                                                 DEPFLAG_ORIGINAL,
 
385
                                                 NULL,  /* empty stack */
 
386
                                                 targetObjects,
 
387
                                                 NULL,  /* no pendingObjects */
 
388
                                                 depRel);
 
389
 
 
390
        /*
 
391
         * Check if deletion is allowed, and report about cascaded deletes.
 
392
         */
 
393
        reportDependentObjects(targetObjects,
 
394
                                                   DROP_CASCADE,
 
395
                                                   showNotices ? NOTICE : DEBUG2,
 
396
                                                   object);
 
397
 
 
398
        /*
 
399
         * Delete all the objects in the proper order, except we skip the original
 
400
         * object.
 
401
         */
 
402
        for (i = 0; i < targetObjects->numrefs; i++)
 
403
        {
 
404
                ObjectAddress *thisobj = targetObjects->refs + i;
 
405
                ObjectAddressExtra *thisextra = targetObjects->extras + i;
 
406
 
 
407
                if (thisextra->flags & DEPFLAG_ORIGINAL)
 
408
                        continue;
 
409
 
 
410
                deleteOneObject(thisobj, depRel);
 
411
        }
 
412
 
 
413
        /* And clean up */
 
414
        free_object_addresses(targetObjects);
 
415
 
 
416
        heap_close(depRel, RowExclusiveLock);
 
417
}
 
418
 
 
419
/*
 
420
 * findDependentObjects - find all objects that depend on 'object'
 
421
 *
 
422
 * For every object that depends on the starting object, acquire a deletion
 
423
 * lock on the object, add it to targetObjects (if not already there),
 
424
 * and recursively find objects that depend on it.      An object's dependencies
 
425
 * will be placed into targetObjects before the object itself; this means
 
426
 * that the finished list's order represents a safe deletion order.
 
427
 *
 
428
 * The caller must already have a deletion lock on 'object' itself,
 
429
 * but must not have added it to targetObjects.  (Note: there are corner
 
430
 * cases where we won't add the object either, and will also release the
 
431
 * caller-taken lock.  This is a bit ugly, but the API is set up this way
 
432
 * to allow easy rechecking of an object's liveness after we lock it.  See
 
433
 * notes within the function.)
 
434
 *
 
435
 * When dropping a whole object (subId = 0), we find dependencies for
 
436
 * its sub-objects too.
 
437
 *
 
438
 *      object: the object to add to targetObjects and find dependencies on
 
439
 *      flags: flags to be ORed into the object's targetObjects entry
 
440
 *      stack: list of objects being visited in current recursion; topmost item
 
441
 *                      is the object that we recursed from (NULL for external callers)
 
442
 *      targetObjects: list of objects that are scheduled to be deleted
 
443
 *      pendingObjects: list of other objects slated for destruction, but
 
444
 *                      not necessarily in targetObjects yet (can be NULL if none)
 
445
 *      depRel: already opened pg_depend relation
 
446
 */
 
447
static void
 
448
findDependentObjects(const ObjectAddress *object,
 
449
                                         int flags,
 
450
                                         ObjectAddressStack *stack,
 
451
                                         ObjectAddresses *targetObjects,
 
452
                                         const ObjectAddresses *pendingObjects,
 
453
                                         Relation depRel)
 
454
{
 
455
        ScanKeyData key[3];
 
456
        int                     nkeys;
 
457
        SysScanDesc scan;
 
458
        HeapTuple       tup;
 
459
        ObjectAddress otherObject;
 
460
        ObjectAddressStack mystack;
 
461
        ObjectAddressExtra extra;
 
462
        ObjectAddressStack *stackptr;
 
463
 
 
464
        /*
 
465
         * If the target object is already being visited in an outer recursion
 
466
         * level, just report the current flags back to that level and exit. This
 
467
         * is needed to avoid infinite recursion in the face of circular
 
468
         * dependencies.
 
469
         *
 
470
         * The stack check alone would result in dependency loops being broken at
 
471
         * an arbitrary point, ie, the first member object of the loop to be
 
472
         * visited is the last one to be deleted.  This is obviously unworkable.
 
473
         * However, the check for internal dependency below guarantees that we
 
474
         * will not break a loop at an internal dependency: if we enter the loop
 
475
         * at an "owned" object we will switch and start at the "owning" object
 
476
         * instead.  We could probably hack something up to avoid breaking at an
 
477
         * auto dependency, too, if we had to.  However there are no known cases
 
478
         * where that would be necessary.
 
479
         */
 
480
        for (stackptr = stack; stackptr; stackptr = stackptr->next)
 
481
        {
 
482
                if (object->classId == stackptr->object->classId &&
 
483
                        object->objectId == stackptr->object->objectId)
 
484
                {
 
485
                        if (object->objectSubId == stackptr->object->objectSubId)
 
486
                        {
 
487
                                stackptr->flags |= flags;
 
488
                                return;
 
489
                        }
 
490
 
 
491
                        /*
 
492
                         * Could visit column with whole table already on stack; this is
 
493
                         * the same case noted in object_address_present_add_flags().
 
494
                         * (It's not clear this can really happen, but we might as well
 
495
                         * check.)
 
496
                         */
 
497
                        if (stackptr->object->objectSubId == 0)
 
498
                                return;
 
499
                }
 
500
        }
 
501
 
 
502
        /*
 
503
         * It's also possible that the target object has already been completely
 
504
         * processed and put into targetObjects.  If so, again we just add the
 
505
         * specified flags to its entry and return.
 
506
         *
 
507
         * (Note: in these early-exit cases we could release the caller-taken
 
508
         * lock, since the object is presumably now locked multiple times; but it
 
509
         * seems not worth the cycles.)
 
510
         */
 
511
        if (object_address_present_add_flags(object, flags, targetObjects))
 
512
                return;
 
513
 
 
514
        /*
 
515
         * The target object might be internally dependent on some other object
 
516
         * (its "owner").  If so, and if we aren't recursing from the owning
 
517
         * object, we have to transform this deletion request into a deletion
 
518
         * request of the owning object.  (We'll eventually recurse back to this
 
519
         * object, but the owning object has to be visited first so it will be
 
520
         * deleted after.)      The way to find out about this is to scan the
 
521
         * pg_depend entries that show what this object depends on.
 
522
         */
 
523
        ScanKeyInit(&key[0],
 
524
                                Anum_pg_depend_classid,
 
525
                                BTEqualStrategyNumber, F_OIDEQ,
 
526
                                ObjectIdGetDatum(object->classId));
 
527
        ScanKeyInit(&key[1],
 
528
                                Anum_pg_depend_objid,
 
529
                                BTEqualStrategyNumber, F_OIDEQ,
 
530
                                ObjectIdGetDatum(object->objectId));
 
531
        if (object->objectSubId != 0)
 
532
        {
 
533
                ScanKeyInit(&key[2],
 
534
                                        Anum_pg_depend_objsubid,
 
535
                                        BTEqualStrategyNumber, F_INT4EQ,
 
536
                                        Int32GetDatum(object->objectSubId));
 
537
                nkeys = 3;
 
538
        }
 
539
        else
 
540
                nkeys = 2;
 
541
 
 
542
        scan = systable_beginscan(depRel, DependDependerIndexId, true,
 
543
                                                          SnapshotNow, nkeys, key);
 
544
 
 
545
        while (HeapTupleIsValid(tup = systable_getnext(scan)))
 
546
        {
 
547
                Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
 
548
 
 
549
                otherObject.classId = foundDep->refclassid;
 
550
                otherObject.objectId = foundDep->refobjid;
 
551
                otherObject.objectSubId = foundDep->refobjsubid;
 
552
 
 
553
                switch (foundDep->deptype)
 
554
                {
 
555
                        case DEPENDENCY_NORMAL:
 
556
                        case DEPENDENCY_AUTO:
 
557
                                /* no problem */
 
558
                                break;
 
559
                        case DEPENDENCY_INTERNAL:
 
560
                        case DEPENDENCY_EXTENSION:
 
561
 
 
562
                                /*
 
563
                                 * This object is part of the internal implementation of
 
564
                                 * another object, or is part of the extension that is the
 
565
                                 * other object.  We have three cases:
 
566
                                 *
 
567
                                 * 1. At the outermost recursion level, disallow the DROP. (We
 
568
                                 * just ereport here, rather than proceeding, since no other
 
569
                                 * dependencies are likely to be interesting.)  However, if
 
570
                                 * the other object is listed in pendingObjects, just release
 
571
                                 * the caller's lock and return; we'll eventually complete the
 
572
                                 * DROP when we reach that entry in the pending list.
 
573
                                 */
 
574
                                if (stack == NULL)
 
575
                                {
 
576
                                        char       *otherObjDesc;
 
577
 
 
578
                                        if (pendingObjects &&
 
579
                                                object_address_present(&otherObject, pendingObjects))
 
580
                                        {
 
581
                                                systable_endscan(scan);
 
582
                                                /* need to release caller's lock; see notes below */
 
583
                                                ReleaseDeletionLock(object);
 
584
                                                return;
 
585
                                        }
 
586
                                        otherObjDesc = getObjectDescription(&otherObject);
 
587
                                        ereport(ERROR,
 
588
                                                        (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
 
589
                                                         errmsg("cannot drop %s because %s requires it",
 
590
                                                                        getObjectDescription(object),
 
591
                                                                        otherObjDesc),
 
592
                                                         errhint("You can drop %s instead.",
 
593
                                                                         otherObjDesc)));
 
594
                                }
 
595
 
 
596
                                /*
 
597
                                 * 2. When recursing from the other end of this dependency,
 
598
                                 * it's okay to continue with the deletion. This holds when
 
599
                                 * recursing from a whole object that includes the nominal
 
600
                                 * other end as a component, too.
 
601
                                 */
 
602
                                if (stack->object->classId == otherObject.classId &&
 
603
                                        stack->object->objectId == otherObject.objectId &&
 
604
                                        (stack->object->objectSubId == otherObject.objectSubId ||
 
605
                                         stack->object->objectSubId == 0))
 
606
                                        break;
 
607
 
 
608
                                /*
 
609
                                 * 3. When recursing from anyplace else, transform this
 
610
                                 * deletion request into a delete of the other object.
 
611
                                 *
 
612
                                 * First, release caller's lock on this object and get
 
613
                                 * deletion lock on the other object.  (We must release
 
614
                                 * caller's lock to avoid deadlock against a concurrent
 
615
                                 * deletion of the other object.)
 
616
                                 */
 
617
                                ReleaseDeletionLock(object);
 
618
                                AcquireDeletionLock(&otherObject);
 
619
 
 
620
                                /*
 
621
                                 * The other object might have been deleted while we waited to
 
622
                                 * lock it; if so, neither it nor the current object are
 
623
                                 * interesting anymore.  We test this by checking the
 
624
                                 * pg_depend entry (see notes below).
 
625
                                 */
 
626
                                if (!systable_recheck_tuple(scan, tup))
 
627
                                {
 
628
                                        systable_endscan(scan);
 
629
                                        ReleaseDeletionLock(&otherObject);
 
630
                                        return;
 
631
                                }
 
632
 
 
633
                                /*
 
634
                                 * Okay, recurse to the other object instead of proceeding. We
 
635
                                 * treat this exactly as if the original reference had linked
 
636
                                 * to that object instead of this one; hence, pass through the
 
637
                                 * same flags and stack.
 
638
                                 */
 
639
                                findDependentObjects(&otherObject,
 
640
                                                                         flags,
 
641
                                                                         stack,
 
642
                                                                         targetObjects,
 
643
                                                                         pendingObjects,
 
644
                                                                         depRel);
 
645
                                /* And we're done here. */
 
646
                                systable_endscan(scan);
 
647
                                return;
 
648
                        case DEPENDENCY_PIN:
 
649
 
 
650
                                /*
 
651
                                 * Should not happen; PIN dependencies should have zeroes in
 
652
                                 * the depender fields...
 
653
                                 */
 
654
                                elog(ERROR, "incorrect use of PIN dependency with %s",
 
655
                                         getObjectDescription(object));
 
656
                                break;
 
657
                        default:
 
658
                                elog(ERROR, "unrecognized dependency type '%c' for %s",
 
659
                                         foundDep->deptype, getObjectDescription(object));
 
660
                                break;
 
661
                }
 
662
        }
 
663
 
 
664
        systable_endscan(scan);
 
665
 
 
666
        /*
 
667
         * Now recurse to any dependent objects.  We must visit them first since
 
668
         * they have to be deleted before the current object.
 
669
         */
 
670
        mystack.object = object;        /* set up a new stack level */
 
671
        mystack.flags = flags;
 
672
        mystack.next = stack;
 
673
 
 
674
        ScanKeyInit(&key[0],
 
675
                                Anum_pg_depend_refclassid,
 
676
                                BTEqualStrategyNumber, F_OIDEQ,
 
677
                                ObjectIdGetDatum(object->classId));
 
678
        ScanKeyInit(&key[1],
 
679
                                Anum_pg_depend_refobjid,
 
680
                                BTEqualStrategyNumber, F_OIDEQ,
 
681
                                ObjectIdGetDatum(object->objectId));
 
682
        if (object->objectSubId != 0)
 
683
        {
 
684
                ScanKeyInit(&key[2],
 
685
                                        Anum_pg_depend_refobjsubid,
 
686
                                        BTEqualStrategyNumber, F_INT4EQ,
 
687
                                        Int32GetDatum(object->objectSubId));
 
688
                nkeys = 3;
 
689
        }
 
690
        else
 
691
                nkeys = 2;
 
692
 
 
693
        scan = systable_beginscan(depRel, DependReferenceIndexId, true,
 
694
                                                          SnapshotNow, nkeys, key);
 
695
 
 
696
        while (HeapTupleIsValid(tup = systable_getnext(scan)))
 
697
        {
 
698
                Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
 
699
                int                     subflags;
 
700
 
 
701
                otherObject.classId = foundDep->classid;
 
702
                otherObject.objectId = foundDep->objid;
 
703
                otherObject.objectSubId = foundDep->objsubid;
 
704
 
 
705
                /*
 
706
                 * Must lock the dependent object before recursing to it.
 
707
                 */
 
708
                AcquireDeletionLock(&otherObject);
 
709
 
 
710
                /*
 
711
                 * The dependent object might have been deleted while we waited to
 
712
                 * lock it; if so, we don't need to do anything more with it. We can
 
713
                 * test this cheaply and independently of the object's type by seeing
 
714
                 * if the pg_depend tuple we are looking at is still live. (If the
 
715
                 * object got deleted, the tuple would have been deleted too.)
 
716
                 */
 
717
                if (!systable_recheck_tuple(scan, tup))
 
718
                {
 
719
                        /* release the now-useless lock */
 
720
                        ReleaseDeletionLock(&otherObject);
 
721
                        /* and continue scanning for dependencies */
 
722
                        continue;
 
723
                }
 
724
 
 
725
                /* Recurse, passing flags indicating the dependency type */
 
726
                switch (foundDep->deptype)
 
727
                {
 
728
                        case DEPENDENCY_NORMAL:
 
729
                                subflags = DEPFLAG_NORMAL;
 
730
                                break;
 
731
                        case DEPENDENCY_AUTO:
 
732
                                subflags = DEPFLAG_AUTO;
 
733
                                break;
 
734
                        case DEPENDENCY_INTERNAL:
 
735
                                subflags = DEPFLAG_INTERNAL;
 
736
                                break;
 
737
                        case DEPENDENCY_EXTENSION:
 
738
                                subflags = DEPFLAG_EXTENSION;
 
739
                                break;
 
740
                        case DEPENDENCY_PIN:
 
741
 
 
742
                                /*
 
743
                                 * For a PIN dependency we just ereport immediately; there
 
744
                                 * won't be any others to report.
 
745
                                 */
 
746
                                ereport(ERROR,
 
747
                                                (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
 
748
                                                 errmsg("cannot drop %s because it is required by the database system",
 
749
                                                                getObjectDescription(object))));
 
750
                                subflags = 0;   /* keep compiler quiet */
 
751
                                break;
 
752
                        default:
 
753
                                elog(ERROR, "unrecognized dependency type '%c' for %s",
 
754
                                         foundDep->deptype, getObjectDescription(object));
 
755
                                subflags = 0;   /* keep compiler quiet */
 
756
                                break;
 
757
                }
 
758
 
 
759
                findDependentObjects(&otherObject,
 
760
                                                         subflags,
 
761
                                                         &mystack,
 
762
                                                         targetObjects,
 
763
                                                         pendingObjects,
 
764
                                                         depRel);
 
765
        }
 
766
 
 
767
        systable_endscan(scan);
 
768
 
 
769
        /*
 
770
         * Finally, we can add the target object to targetObjects.      Be careful to
 
771
         * include any flags that were passed back down to us from inner recursion
 
772
         * levels.
 
773
         */
 
774
        extra.flags = mystack.flags;
 
775
        if (stack)
 
776
                extra.dependee = *stack->object;
 
777
        else
 
778
                memset(&extra.dependee, 0, sizeof(extra.dependee));
 
779
        add_exact_object_address_extra(object, &extra, targetObjects);
 
780
}
 
781
 
 
782
/*
 
783
 * reportDependentObjects - report about dependencies, and fail if RESTRICT
 
784
 *
 
785
 * Tell the user about dependent objects that we are going to delete
 
786
 * (or would need to delete, but are prevented by RESTRICT mode);
 
787
 * then error out if there are any and it's not CASCADE mode.
 
788
 *
 
789
 *      targetObjects: list of objects that are scheduled to be deleted
 
790
 *      behavior: RESTRICT or CASCADE
 
791
 *      msglevel: elog level for non-error report messages
 
792
 *      origObject: base object of deletion, or NULL if not available
 
793
 *              (the latter case occurs in DROP OWNED)
 
794
 */
 
795
static void
 
796
reportDependentObjects(const ObjectAddresses *targetObjects,
 
797
                                           DropBehavior behavior,
 
798
                                           int msglevel,
 
799
                                           const ObjectAddress *origObject)
 
800
{
 
801
        bool            ok = true;
 
802
        StringInfoData clientdetail;
 
803
        StringInfoData logdetail;
 
804
        int                     numReportedClient = 0;
 
805
        int                     numNotReportedClient = 0;
 
806
        int                     i;
 
807
 
 
808
        /*
 
809
         * If no error is to be thrown, and the msglevel is too low to be shown to
 
810
         * either client or server log, there's no need to do any of the work.
 
811
         *
 
812
         * Note: this code doesn't know all there is to be known about elog
 
813
         * levels, but it works for NOTICE and DEBUG2, which are the only values
 
814
         * msglevel can currently have.  We also assume we are running in a normal
 
815
         * operating environment.
 
816
         */
 
817
        if (behavior == DROP_CASCADE &&
 
818
                msglevel < client_min_messages &&
 
819
                (msglevel < log_min_messages || log_min_messages == LOG))
 
820
                return;
 
821
 
 
822
        /*
 
823
         * We limit the number of dependencies reported to the client to
 
824
         * MAX_REPORTED_DEPS, since client software may not deal well with
 
825
         * enormous error strings.      The server log always gets a full report.
 
826
         */
 
827
#define MAX_REPORTED_DEPS 100
 
828
 
 
829
        initStringInfo(&clientdetail);
 
830
        initStringInfo(&logdetail);
 
831
 
 
832
        /*
 
833
         * We process the list back to front (ie, in dependency order not deletion
 
834
         * order), since this makes for a more understandable display.
 
835
         */
 
836
        for (i = targetObjects->numrefs - 1; i >= 0; i--)
 
837
        {
 
838
                const ObjectAddress *obj = &targetObjects->refs[i];
 
839
                const ObjectAddressExtra *extra = &targetObjects->extras[i];
 
840
                char       *objDesc;
 
841
 
 
842
                /* Ignore the original deletion target(s) */
 
843
                if (extra->flags & DEPFLAG_ORIGINAL)
 
844
                        continue;
 
845
 
 
846
                objDesc = getObjectDescription(obj);
 
847
 
 
848
                /*
 
849
                 * If, at any stage of the recursive search, we reached the object via
 
850
                 * an AUTO, INTERNAL, or EXTENSION dependency, then it's okay to
 
851
                 * delete it even in RESTRICT mode.
 
852
                 */
 
853
                if (extra->flags & (DEPFLAG_AUTO |
 
854
                                                        DEPFLAG_INTERNAL |
 
855
                                                        DEPFLAG_EXTENSION))
 
856
                {
 
857
                        /*
 
858
                         * auto-cascades are reported at DEBUG2, not msglevel.  We don't
 
859
                         * try to combine them with the regular message because the
 
860
                         * results are too confusing when client_min_messages and
 
861
                         * log_min_messages are different.
 
862
                         */
 
863
                        ereport(DEBUG2,
 
864
                                        (errmsg("drop auto-cascades to %s",
 
865
                                                        objDesc)));
 
866
                }
 
867
                else if (behavior == DROP_RESTRICT)
 
868
                {
 
869
                        char       *otherDesc = getObjectDescription(&extra->dependee);
 
870
 
 
871
                        if (numReportedClient < MAX_REPORTED_DEPS)
 
872
                        {
 
873
                                /* separate entries with a newline */
 
874
                                if (clientdetail.len != 0)
 
875
                                        appendStringInfoChar(&clientdetail, '\n');
 
876
                                appendStringInfo(&clientdetail, _("%s depends on %s"),
 
877
                                                                 objDesc, otherDesc);
 
878
                                numReportedClient++;
 
879
                        }
 
880
                        else
 
881
                                numNotReportedClient++;
 
882
                        /* separate entries with a newline */
 
883
                        if (logdetail.len != 0)
 
884
                                appendStringInfoChar(&logdetail, '\n');
 
885
                        appendStringInfo(&logdetail, _("%s depends on %s"),
 
886
                                                         objDesc, otherDesc);
 
887
                        pfree(otherDesc);
 
888
                        ok = false;
 
889
                }
 
890
                else
 
891
                {
 
892
                        if (numReportedClient < MAX_REPORTED_DEPS)
 
893
                        {
 
894
                                /* separate entries with a newline */
 
895
                                if (clientdetail.len != 0)
 
896
                                        appendStringInfoChar(&clientdetail, '\n');
 
897
                                appendStringInfo(&clientdetail, _("drop cascades to %s"),
 
898
                                                                 objDesc);
 
899
                                numReportedClient++;
 
900
                        }
 
901
                        else
 
902
                                numNotReportedClient++;
 
903
                        /* separate entries with a newline */
 
904
                        if (logdetail.len != 0)
 
905
                                appendStringInfoChar(&logdetail, '\n');
 
906
                        appendStringInfo(&logdetail, _("drop cascades to %s"),
 
907
                                                         objDesc);
 
908
                }
 
909
 
 
910
                pfree(objDesc);
 
911
        }
 
912
 
 
913
        if (numNotReportedClient > 0)
 
914
                appendStringInfo(&clientdetail, ngettext("\nand %d other object "
 
915
                                                                                                 "(see server log for list)",
 
916
                                                                                                 "\nand %d other objects "
 
917
                                                                                                 "(see server log for list)",
 
918
                                                                                                 numNotReportedClient),
 
919
                                                 numNotReportedClient);
 
920
 
 
921
        if (!ok)
 
922
        {
 
923
                if (origObject)
 
924
                        ereport(ERROR,
 
925
                                        (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
 
926
                                  errmsg("cannot drop %s because other objects depend on it",
 
927
                                                 getObjectDescription(origObject)),
 
928
                                         errdetail("%s", clientdetail.data),
 
929
                                         errdetail_log("%s", logdetail.data),
 
930
                                         errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
 
931
                else
 
932
                        ereport(ERROR,
 
933
                                        (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
 
934
                                         errmsg("cannot drop desired object(s) because other objects depend on them"),
 
935
                                         errdetail("%s", clientdetail.data),
 
936
                                         errdetail_log("%s", logdetail.data),
 
937
                                         errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
 
938
        }
 
939
        else if (numReportedClient > 1)
 
940
        {
 
941
                ereport(msglevel,
 
942
                /* translator: %d always has a value larger than 1 */
 
943
                                (errmsg_plural("drop cascades to %d other object",
 
944
                                                           "drop cascades to %d other objects",
 
945
                                                           numReportedClient + numNotReportedClient,
 
946
                                                           numReportedClient + numNotReportedClient),
 
947
                                 errdetail("%s", clientdetail.data),
 
948
                                 errdetail_log("%s", logdetail.data)));
 
949
        }
 
950
        else if (numReportedClient == 1)
 
951
        {
 
952
                /* we just use the single item as-is */
 
953
                ereport(msglevel,
 
954
                                (errmsg_internal("%s", clientdetail.data)));
 
955
        }
 
956
 
 
957
        pfree(clientdetail.data);
 
958
        pfree(logdetail.data);
 
959
}
 
960
 
 
961
/*
 
962
 * deleteOneObject: delete a single object for performDeletion.
 
963
 *
 
964
 * depRel is the already-open pg_depend relation.
 
965
 */
 
966
static void
 
967
deleteOneObject(const ObjectAddress *object, Relation depRel)
 
968
{
 
969
        ScanKeyData key[3];
 
970
        int                     nkeys;
 
971
        SysScanDesc scan;
 
972
        HeapTuple       tup;
 
973
 
 
974
        /*
 
975
         * First remove any pg_depend records that link from this object to
 
976
         * others.      (Any records linking to this object should be gone already.)
 
977
         *
 
978
         * When dropping a whole object (subId = 0), remove all pg_depend records
 
979
         * for its sub-objects too.
 
980
         */
 
981
        ScanKeyInit(&key[0],
 
982
                                Anum_pg_depend_classid,
 
983
                                BTEqualStrategyNumber, F_OIDEQ,
 
984
                                ObjectIdGetDatum(object->classId));
 
985
        ScanKeyInit(&key[1],
 
986
                                Anum_pg_depend_objid,
 
987
                                BTEqualStrategyNumber, F_OIDEQ,
 
988
                                ObjectIdGetDatum(object->objectId));
 
989
        if (object->objectSubId != 0)
 
990
        {
 
991
                ScanKeyInit(&key[2],
 
992
                                        Anum_pg_depend_objsubid,
 
993
                                        BTEqualStrategyNumber, F_INT4EQ,
 
994
                                        Int32GetDatum(object->objectSubId));
 
995
                nkeys = 3;
 
996
        }
 
997
        else
 
998
                nkeys = 2;
 
999
 
 
1000
        scan = systable_beginscan(depRel, DependDependerIndexId, true,
 
1001
                                                          SnapshotNow, nkeys, key);
 
1002
 
 
1003
        while (HeapTupleIsValid(tup = systable_getnext(scan)))
 
1004
        {
 
1005
                simple_heap_delete(depRel, &tup->t_self);
 
1006
        }
 
1007
 
 
1008
        systable_endscan(scan);
 
1009
 
 
1010
        /*
 
1011
         * Delete shared dependency references related to this object.  Again, if
 
1012
         * subId = 0, remove records for sub-objects too.
 
1013
         */
 
1014
        deleteSharedDependencyRecordsFor(object->classId, object->objectId,
 
1015
                                                                         object->objectSubId);
 
1016
 
 
1017
        /*
 
1018
         * Now delete the object itself, in an object-type-dependent way.
 
1019
         */
 
1020
        doDeletion(object);
 
1021
 
 
1022
        /*
 
1023
         * Delete any comments or security labels associated with this object.
 
1024
         * (This is a convenient place to do these things, rather than having
 
1025
         * every object type know to do it.)
 
1026
         */
 
1027
        DeleteComments(object->objectId, object->classId, object->objectSubId);
 
1028
        DeleteSecurityLabel(object);
 
1029
 
 
1030
        /*
 
1031
         * CommandCounterIncrement here to ensure that preceding changes are all
 
1032
         * visible to the next deletion step.
 
1033
         */
 
1034
        CommandCounterIncrement();
 
1035
 
 
1036
        /*
 
1037
         * And we're done!
 
1038
         */
 
1039
}
 
1040
 
 
1041
/*
 
1042
 * doDeletion: actually delete a single object
 
1043
 */
 
1044
static void
 
1045
doDeletion(const ObjectAddress *object)
 
1046
{
 
1047
        switch (getObjectClass(object))
 
1048
        {
 
1049
                case OCLASS_CLASS:
 
1050
                        {
 
1051
                                char            relKind = get_rel_relkind(object->objectId);
 
1052
 
 
1053
                                if (relKind == RELKIND_INDEX)
 
1054
                                {
 
1055
                                        Assert(object->objectSubId == 0);
 
1056
                                        index_drop(object->objectId);
 
1057
                                }
 
1058
                                else
 
1059
                                {
 
1060
                                        if (object->objectSubId != 0)
 
1061
                                                RemoveAttributeById(object->objectId,
 
1062
                                                                                        object->objectSubId);
 
1063
                                        else
 
1064
                                                heap_drop_with_catalog(object->objectId);
 
1065
                                }
 
1066
                                break;
 
1067
                        }
 
1068
 
 
1069
                case OCLASS_PROC:
 
1070
                        RemoveFunctionById(object->objectId);
 
1071
                        break;
 
1072
 
 
1073
                case OCLASS_TYPE:
 
1074
                        RemoveTypeById(object->objectId);
 
1075
                        break;
 
1076
 
 
1077
                case OCLASS_CAST:
 
1078
                        DropCastById(object->objectId);
 
1079
                        break;
 
1080
 
 
1081
                case OCLASS_COLLATION:
 
1082
                        RemoveCollationById(object->objectId);
 
1083
                        break;
 
1084
 
 
1085
                case OCLASS_CONSTRAINT:
 
1086
                        RemoveConstraintById(object->objectId);
 
1087
                        break;
 
1088
 
 
1089
                case OCLASS_CONVERSION:
 
1090
                        RemoveConversionById(object->objectId);
 
1091
                        break;
 
1092
 
 
1093
                case OCLASS_DEFAULT:
 
1094
                        RemoveAttrDefaultById(object->objectId);
 
1095
                        break;
 
1096
 
 
1097
                case OCLASS_LANGUAGE:
 
1098
                        DropProceduralLanguageById(object->objectId);
 
1099
                        break;
 
1100
 
 
1101
                case OCLASS_LARGEOBJECT:
 
1102
                        LargeObjectDrop(object->objectId);
 
1103
                        break;
 
1104
 
 
1105
                case OCLASS_OPERATOR:
 
1106
                        RemoveOperatorById(object->objectId);
 
1107
                        break;
 
1108
 
 
1109
                case OCLASS_OPCLASS:
 
1110
                        RemoveOpClassById(object->objectId);
 
1111
                        break;
 
1112
 
 
1113
                case OCLASS_OPFAMILY:
 
1114
                        RemoveOpFamilyById(object->objectId);
 
1115
                        break;
 
1116
 
 
1117
                case OCLASS_AMOP:
 
1118
                        RemoveAmOpEntryById(object->objectId);
 
1119
                        break;
 
1120
 
 
1121
                case OCLASS_AMPROC:
 
1122
                        RemoveAmProcEntryById(object->objectId);
 
1123
                        break;
 
1124
 
 
1125
                case OCLASS_REWRITE:
 
1126
                        RemoveRewriteRuleById(object->objectId);
 
1127
                        break;
 
1128
 
 
1129
                case OCLASS_TRIGGER:
 
1130
                        RemoveTriggerById(object->objectId);
 
1131
                        break;
 
1132
 
 
1133
                case OCLASS_SCHEMA:
 
1134
                        RemoveSchemaById(object->objectId);
 
1135
                        break;
 
1136
 
 
1137
                case OCLASS_TSPARSER:
 
1138
                        RemoveTSParserById(object->objectId);
 
1139
                        break;
 
1140
 
 
1141
                case OCLASS_TSDICT:
 
1142
                        RemoveTSDictionaryById(object->objectId);
 
1143
                        break;
 
1144
 
 
1145
                case OCLASS_TSTEMPLATE:
 
1146
                        RemoveTSTemplateById(object->objectId);
 
1147
                        break;
 
1148
 
 
1149
                case OCLASS_TSCONFIG:
 
1150
                        RemoveTSConfigurationById(object->objectId);
 
1151
                        break;
 
1152
 
 
1153
                        /*
 
1154
                         * OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE intentionally not
 
1155
                         * handled here
 
1156
                         */
 
1157
 
 
1158
                case OCLASS_FDW:
 
1159
                        RemoveForeignDataWrapperById(object->objectId);
 
1160
                        break;
 
1161
 
 
1162
                case OCLASS_FOREIGN_SERVER:
 
1163
                        RemoveForeignServerById(object->objectId);
 
1164
                        break;
 
1165
 
 
1166
                case OCLASS_USER_MAPPING:
 
1167
                        RemoveUserMappingById(object->objectId);
 
1168
                        break;
 
1169
 
 
1170
                case OCLASS_DEFACL:
 
1171
                        RemoveDefaultACLById(object->objectId);
 
1172
                        break;
 
1173
 
 
1174
                case OCLASS_EXTENSION:
 
1175
                        RemoveExtensionById(object->objectId);
 
1176
                        break;
 
1177
 
 
1178
                default:
 
1179
                        elog(ERROR, "unrecognized object class: %u",
 
1180
                                 object->classId);
 
1181
        }
 
1182
}
 
1183
 
 
1184
/*
 
1185
 * AcquireDeletionLock - acquire a suitable lock for deleting an object
 
1186
 *
 
1187
 * We use LockRelation for relations, LockDatabaseObject for everything
 
1188
 * else.  Note that dependency.c is not concerned with deleting any kind of
 
1189
 * shared-across-databases object, so we have no need for LockSharedObject.
 
1190
 */
 
1191
static void
 
1192
AcquireDeletionLock(const ObjectAddress *object)
 
1193
{
 
1194
        if (object->classId == RelationRelationId)
 
1195
                LockRelationOid(object->objectId, AccessExclusiveLock);
 
1196
        else
 
1197
                /* assume we should lock the whole object not a sub-object */
 
1198
                LockDatabaseObject(object->classId, object->objectId, 0,
 
1199
                                                   AccessExclusiveLock);
 
1200
}
 
1201
 
 
1202
/*
 
1203
 * ReleaseDeletionLock - release an object deletion lock
 
1204
 */
 
1205
static void
 
1206
ReleaseDeletionLock(const ObjectAddress *object)
 
1207
{
 
1208
        if (object->classId == RelationRelationId)
 
1209
                UnlockRelationOid(object->objectId, AccessExclusiveLock);
 
1210
        else
 
1211
                /* assume we should lock the whole object not a sub-object */
 
1212
                UnlockDatabaseObject(object->classId, object->objectId, 0,
 
1213
                                                         AccessExclusiveLock);
 
1214
}
 
1215
 
 
1216
/*
 
1217
 * recordDependencyOnExpr - find expression dependencies
 
1218
 *
 
1219
 * This is used to find the dependencies of rules, constraint expressions,
 
1220
 * etc.
 
1221
 *
 
1222
 * Given an expression or query in node-tree form, find all the objects
 
1223
 * it refers to (tables, columns, operators, functions, etc).  Record
 
1224
 * a dependency of the specified type from the given depender object
 
1225
 * to each object mentioned in the expression.
 
1226
 *
 
1227
 * rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
 
1228
 * It can be NIL if no such variables are expected.
 
1229
 */
 
1230
void
 
1231
recordDependencyOnExpr(const ObjectAddress *depender,
 
1232
                                           Node *expr, List *rtable,
 
1233
                                           DependencyType behavior)
 
1234
{
 
1235
        find_expr_references_context context;
 
1236
 
 
1237
        context.addrs = new_object_addresses();
 
1238
 
 
1239
        /* Set up interpretation for Vars at varlevelsup = 0 */
 
1240
        context.rtables = list_make1(rtable);
 
1241
 
 
1242
        /* Scan the expression tree for referenceable objects */
 
1243
        find_expr_references_walker(expr, &context);
 
1244
 
 
1245
        /* Remove any duplicates */
 
1246
        eliminate_duplicate_dependencies(context.addrs);
 
1247
 
 
1248
        /* And record 'em */
 
1249
        recordMultipleDependencies(depender,
 
1250
                                                           context.addrs->refs, context.addrs->numrefs,
 
1251
                                                           behavior);
 
1252
 
 
1253
        free_object_addresses(context.addrs);
 
1254
}
 
1255
 
 
1256
/*
 
1257
 * recordDependencyOnSingleRelExpr - find expression dependencies
 
1258
 *
 
1259
 * As above, but only one relation is expected to be referenced (with
 
1260
 * varno = 1 and varlevelsup = 0).      Pass the relation OID instead of a
 
1261
 * range table.  An additional frammish is that dependencies on that
 
1262
 * relation (or its component columns) will be marked with 'self_behavior',
 
1263
 * whereas 'behavior' is used for everything else.
 
1264
 *
 
1265
 * NOTE: the caller should ensure that a whole-table dependency on the
 
1266
 * specified relation is created separately, if one is needed.  In particular,
 
1267
 * a whole-row Var "relation.*" will not cause this routine to emit any
 
1268
 * dependency item.  This is appropriate behavior for subexpressions of an
 
1269
 * ordinary query, so other cases need to cope as necessary.
 
1270
 */
 
1271
void
 
1272
recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
 
1273
                                                                Node *expr, Oid relId,
 
1274
                                                                DependencyType behavior,
 
1275
                                                                DependencyType self_behavior)
 
1276
{
 
1277
        find_expr_references_context context;
 
1278
        RangeTblEntry rte;
 
1279
 
 
1280
        context.addrs = new_object_addresses();
 
1281
 
 
1282
        /* We gin up a rather bogus rangetable list to handle Vars */
 
1283
        MemSet(&rte, 0, sizeof(rte));
 
1284
        rte.type = T_RangeTblEntry;
 
1285
        rte.rtekind = RTE_RELATION;
 
1286
        rte.relid = relId;
 
1287
        rte.relkind = RELKIND_RELATION;         /* no need for exactness here */
 
1288
 
 
1289
        context.rtables = list_make1(list_make1(&rte));
 
1290
 
 
1291
        /* Scan the expression tree for referenceable objects */
 
1292
        find_expr_references_walker(expr, &context);
 
1293
 
 
1294
        /* Remove any duplicates */
 
1295
        eliminate_duplicate_dependencies(context.addrs);
 
1296
 
 
1297
        /* Separate self-dependencies if necessary */
 
1298
        if (behavior != self_behavior && context.addrs->numrefs > 0)
 
1299
        {
 
1300
                ObjectAddresses *self_addrs;
 
1301
                ObjectAddress *outobj;
 
1302
                int                     oldref,
 
1303
                                        outrefs;
 
1304
 
 
1305
                self_addrs = new_object_addresses();
 
1306
 
 
1307
                outobj = context.addrs->refs;
 
1308
                outrefs = 0;
 
1309
                for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
 
1310
                {
 
1311
                        ObjectAddress *thisobj = context.addrs->refs + oldref;
 
1312
 
 
1313
                        if (thisobj->classId == RelationRelationId &&
 
1314
                                thisobj->objectId == relId)
 
1315
                        {
 
1316
                                /* Move this ref into self_addrs */
 
1317
                                add_exact_object_address(thisobj, self_addrs);
 
1318
                        }
 
1319
                        else
 
1320
                        {
 
1321
                                /* Keep it in context.addrs */
 
1322
                                *outobj = *thisobj;
 
1323
                                outobj++;
 
1324
                                outrefs++;
 
1325
                        }
 
1326
                }
 
1327
                context.addrs->numrefs = outrefs;
 
1328
 
 
1329
                /* Record the self-dependencies */
 
1330
                recordMultipleDependencies(depender,
 
1331
                                                                   self_addrs->refs, self_addrs->numrefs,
 
1332
                                                                   self_behavior);
 
1333
 
 
1334
                free_object_addresses(self_addrs);
 
1335
        }
 
1336
 
 
1337
        /* Record the external dependencies */
 
1338
        recordMultipleDependencies(depender,
 
1339
                                                           context.addrs->refs, context.addrs->numrefs,
 
1340
                                                           behavior);
 
1341
 
 
1342
        free_object_addresses(context.addrs);
 
1343
}
 
1344
 
 
1345
/*
 
1346
 * Recursively search an expression tree for object references.
 
1347
 *
 
1348
 * Note: we avoid creating references to columns of tables that participate
 
1349
 * in an SQL JOIN construct, but are not actually used anywhere in the query.
 
1350
 * To do so, we do not scan the joinaliasvars list of a join RTE while
 
1351
 * scanning the query rangetable, but instead scan each individual entry
 
1352
 * of the alias list when we find a reference to it.
 
1353
 *
 
1354
 * Note: in many cases we do not need to create dependencies on the datatypes
 
1355
 * involved in an expression, because we'll have an indirect dependency via
 
1356
 * some other object.  For instance Var nodes depend on a column which depends
 
1357
 * on the datatype, and OpExpr nodes depend on the operator which depends on
 
1358
 * the datatype.  However we do need a type dependency if there is no such
 
1359
 * indirect dependency, as for example in Const and CoerceToDomain nodes.
 
1360
 *
 
1361
 * Similarly, we don't need to create dependencies on collations except where
 
1362
 * the collation is being freshly introduced to the expression.
 
1363
 */
 
1364
static bool
 
1365
find_expr_references_walker(Node *node,
 
1366
                                                        find_expr_references_context *context)
 
1367
{
 
1368
        if (node == NULL)
 
1369
                return false;
 
1370
        if (IsA(node, Var))
 
1371
        {
 
1372
                Var                *var = (Var *) node;
 
1373
                List       *rtable;
 
1374
                RangeTblEntry *rte;
 
1375
 
 
1376
                /* Find matching rtable entry, or complain if not found */
 
1377
                if (var->varlevelsup >= list_length(context->rtables))
 
1378
                        elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
 
1379
                rtable = (List *) list_nth(context->rtables, var->varlevelsup);
 
1380
                if (var->varno <= 0 || var->varno > list_length(rtable))
 
1381
                        elog(ERROR, "invalid varno %d", var->varno);
 
1382
                rte = rt_fetch(var->varno, rtable);
 
1383
 
 
1384
                /*
 
1385
                 * A whole-row Var references no specific columns, so adds no new
 
1386
                 * dependency.  (We assume that there is a whole-table dependency
 
1387
                 * arising from each underlying rangetable entry.  While we could
 
1388
                 * record such a dependency when finding a whole-row Var that
 
1389
                 * references a relation directly, it's quite unclear how to extend
 
1390
                 * that to whole-row Vars for JOINs, so it seems better to leave the
 
1391
                 * responsibility with the range table.  Note that this poses some
 
1392
                 * risks for identifying dependencies of stand-alone expressions:
 
1393
                 * whole-table references may need to be created separately.)
 
1394
                 */
 
1395
                if (var->varattno == InvalidAttrNumber)
 
1396
                        return false;
 
1397
                if (rte->rtekind == RTE_RELATION)
 
1398
                {
 
1399
                        /* If it's a plain relation, reference this column */
 
1400
                        add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
 
1401
                                                           context->addrs);
 
1402
                }
 
1403
                else if (rte->rtekind == RTE_JOIN)
 
1404
                {
 
1405
                        /* Scan join output column to add references to join inputs */
 
1406
                        List       *save_rtables;
 
1407
 
 
1408
                        /* We must make the context appropriate for join's level */
 
1409
                        save_rtables = context->rtables;
 
1410
                        context->rtables = list_copy_tail(context->rtables,
 
1411
                                                                                          var->varlevelsup);
 
1412
                        if (var->varattno <= 0 ||
 
1413
                                var->varattno > list_length(rte->joinaliasvars))
 
1414
                                elog(ERROR, "invalid varattno %d", var->varattno);
 
1415
                        find_expr_references_walker((Node *) list_nth(rte->joinaliasvars,
 
1416
                                                                                                                  var->varattno - 1),
 
1417
                                                                                context);
 
1418
                        list_free(context->rtables);
 
1419
                        context->rtables = save_rtables;
 
1420
                }
 
1421
                return false;
 
1422
        }
 
1423
        else if (IsA(node, Const))
 
1424
        {
 
1425
                Const      *con = (Const *) node;
 
1426
                Oid                     objoid;
 
1427
 
 
1428
                /* A constant must depend on the constant's datatype */
 
1429
                add_object_address(OCLASS_TYPE, con->consttype, 0,
 
1430
                                                   context->addrs);
 
1431
 
 
1432
                /*
 
1433
                 * We must also depend on the constant's collation: it could be
 
1434
                 * different from the datatype's, if a CollateExpr was const-folded to
 
1435
                 * a simple constant.  However we can save work in the most common
 
1436
                 * case where the collation is "default", since we know that's pinned.
 
1437
                 */
 
1438
                if (OidIsValid(con->constcollid) &&
 
1439
                        con->constcollid != DEFAULT_COLLATION_OID)
 
1440
                        add_object_address(OCLASS_COLLATION, con->constcollid, 0,
 
1441
                                                           context->addrs);
 
1442
 
 
1443
                /*
 
1444
                 * If it's a regclass or similar literal referring to an existing
 
1445
                 * object, add a reference to that object.      (Currently, only the
 
1446
                 * regclass and regconfig cases have any likely use, but we may as
 
1447
                 * well handle all the OID-alias datatypes consistently.)
 
1448
                 */
 
1449
                if (!con->constisnull)
 
1450
                {
 
1451
                        switch (con->consttype)
 
1452
                        {
 
1453
                                case REGPROCOID:
 
1454
                                case REGPROCEDUREOID:
 
1455
                                        objoid = DatumGetObjectId(con->constvalue);
 
1456
                                        if (SearchSysCacheExists1(PROCOID,
 
1457
                                                                                          ObjectIdGetDatum(objoid)))
 
1458
                                                add_object_address(OCLASS_PROC, objoid, 0,
 
1459
                                                                                   context->addrs);
 
1460
                                        break;
 
1461
                                case REGOPEROID:
 
1462
                                case REGOPERATOROID:
 
1463
                                        objoid = DatumGetObjectId(con->constvalue);
 
1464
                                        if (SearchSysCacheExists1(OPEROID,
 
1465
                                                                                          ObjectIdGetDatum(objoid)))
 
1466
                                                add_object_address(OCLASS_OPERATOR, objoid, 0,
 
1467
                                                                                   context->addrs);
 
1468
                                        break;
 
1469
                                case REGCLASSOID:
 
1470
                                        objoid = DatumGetObjectId(con->constvalue);
 
1471
                                        if (SearchSysCacheExists1(RELOID,
 
1472
                                                                                          ObjectIdGetDatum(objoid)))
 
1473
                                                add_object_address(OCLASS_CLASS, objoid, 0,
 
1474
                                                                                   context->addrs);
 
1475
                                        break;
 
1476
                                case REGTYPEOID:
 
1477
                                        objoid = DatumGetObjectId(con->constvalue);
 
1478
                                        if (SearchSysCacheExists1(TYPEOID,
 
1479
                                                                                          ObjectIdGetDatum(objoid)))
 
1480
                                                add_object_address(OCLASS_TYPE, objoid, 0,
 
1481
                                                                                   context->addrs);
 
1482
                                        break;
 
1483
                                case REGCONFIGOID:
 
1484
                                        objoid = DatumGetObjectId(con->constvalue);
 
1485
                                        if (SearchSysCacheExists1(TSCONFIGOID,
 
1486
                                                                                          ObjectIdGetDatum(objoid)))
 
1487
                                                add_object_address(OCLASS_TSCONFIG, objoid, 0,
 
1488
                                                                                   context->addrs);
 
1489
                                        break;
 
1490
                                case REGDICTIONARYOID:
 
1491
                                        objoid = DatumGetObjectId(con->constvalue);
 
1492
                                        if (SearchSysCacheExists1(TSDICTOID,
 
1493
                                                                                          ObjectIdGetDatum(objoid)))
 
1494
                                                add_object_address(OCLASS_TSDICT, objoid, 0,
 
1495
                                                                                   context->addrs);
 
1496
                                        break;
 
1497
                        }
 
1498
                }
 
1499
                return false;
 
1500
        }
 
1501
        else if (IsA(node, Param))
 
1502
        {
 
1503
                Param      *param = (Param *) node;
 
1504
 
 
1505
                /* A parameter must depend on the parameter's datatype */
 
1506
                add_object_address(OCLASS_TYPE, param->paramtype, 0,
 
1507
                                                   context->addrs);
 
1508
                /* and its collation, just as for Consts */
 
1509
                if (OidIsValid(param->paramcollid) &&
 
1510
                        param->paramcollid != DEFAULT_COLLATION_OID)
 
1511
                        add_object_address(OCLASS_COLLATION, param->paramcollid, 0,
 
1512
                                                           context->addrs);
 
1513
        }
 
1514
        else if (IsA(node, FuncExpr))
 
1515
        {
 
1516
                FuncExpr   *funcexpr = (FuncExpr *) node;
 
1517
 
 
1518
                add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
 
1519
                                                   context->addrs);
 
1520
                /* fall through to examine arguments */
 
1521
        }
 
1522
        else if (IsA(node, OpExpr))
 
1523
        {
 
1524
                OpExpr     *opexpr = (OpExpr *) node;
 
1525
 
 
1526
                add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
 
1527
                                                   context->addrs);
 
1528
                /* fall through to examine arguments */
 
1529
        }
 
1530
        else if (IsA(node, DistinctExpr))
 
1531
        {
 
1532
                DistinctExpr *distinctexpr = (DistinctExpr *) node;
 
1533
 
 
1534
                add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
 
1535
                                                   context->addrs);
 
1536
                /* fall through to examine arguments */
 
1537
        }
 
1538
        else if (IsA(node, NullIfExpr))
 
1539
        {
 
1540
                NullIfExpr *nullifexpr = (NullIfExpr *) node;
 
1541
 
 
1542
                add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
 
1543
                                                   context->addrs);
 
1544
                /* fall through to examine arguments */
 
1545
        }
 
1546
        else if (IsA(node, ScalarArrayOpExpr))
 
1547
        {
 
1548
                ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
 
1549
 
 
1550
                add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
 
1551
                                                   context->addrs);
 
1552
                /* fall through to examine arguments */
 
1553
        }
 
1554
        else if (IsA(node, Aggref))
 
1555
        {
 
1556
                Aggref     *aggref = (Aggref *) node;
 
1557
 
 
1558
                add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
 
1559
                                                   context->addrs);
 
1560
                /* fall through to examine arguments */
 
1561
        }
 
1562
        else if (IsA(node, WindowFunc))
 
1563
        {
 
1564
                WindowFunc *wfunc = (WindowFunc *) node;
 
1565
 
 
1566
                add_object_address(OCLASS_PROC, wfunc->winfnoid, 0,
 
1567
                                                   context->addrs);
 
1568
                /* fall through to examine arguments */
 
1569
        }
 
1570
        else if (IsA(node, SubPlan))
 
1571
        {
 
1572
                /* Extra work needed here if we ever need this case */
 
1573
                elog(ERROR, "already-planned subqueries not supported");
 
1574
        }
 
1575
        else if (IsA(node, RelabelType))
 
1576
        {
 
1577
                RelabelType *relab = (RelabelType *) node;
 
1578
 
 
1579
                /* since there is no function dependency, need to depend on type */
 
1580
                add_object_address(OCLASS_TYPE, relab->resulttype, 0,
 
1581
                                                   context->addrs);
 
1582
                /* the collation might not be referenced anywhere else, either */
 
1583
                if (OidIsValid(relab->resultcollid) &&
 
1584
                        relab->resultcollid != DEFAULT_COLLATION_OID)
 
1585
                        add_object_address(OCLASS_COLLATION, relab->resultcollid, 0,
 
1586
                                                           context->addrs);
 
1587
        }
 
1588
        else if (IsA(node, CoerceViaIO))
 
1589
        {
 
1590
                CoerceViaIO *iocoerce = (CoerceViaIO *) node;
 
1591
 
 
1592
                /* since there is no exposed function, need to depend on type */
 
1593
                add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0,
 
1594
                                                   context->addrs);
 
1595
        }
 
1596
        else if (IsA(node, ArrayCoerceExpr))
 
1597
        {
 
1598
                ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
 
1599
 
 
1600
                if (OidIsValid(acoerce->elemfuncid))
 
1601
                        add_object_address(OCLASS_PROC, acoerce->elemfuncid, 0,
 
1602
                                                           context->addrs);
 
1603
                add_object_address(OCLASS_TYPE, acoerce->resulttype, 0,
 
1604
                                                   context->addrs);
 
1605
                /* fall through to examine arguments */
 
1606
        }
 
1607
        else if (IsA(node, ConvertRowtypeExpr))
 
1608
        {
 
1609
                ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
 
1610
 
 
1611
                /* since there is no function dependency, need to depend on type */
 
1612
                add_object_address(OCLASS_TYPE, cvt->resulttype, 0,
 
1613
                                                   context->addrs);
 
1614
        }
 
1615
        else if (IsA(node, CollateExpr))
 
1616
        {
 
1617
                CollateExpr *coll = (CollateExpr *) node;
 
1618
 
 
1619
                add_object_address(OCLASS_COLLATION, coll->collOid, 0,
 
1620
                                                   context->addrs);
 
1621
        }
 
1622
        else if (IsA(node, RowExpr))
 
1623
        {
 
1624
                RowExpr    *rowexpr = (RowExpr *) node;
 
1625
 
 
1626
                add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
 
1627
                                                   context->addrs);
 
1628
        }
 
1629
        else if (IsA(node, RowCompareExpr))
 
1630
        {
 
1631
                RowCompareExpr *rcexpr = (RowCompareExpr *) node;
 
1632
                ListCell   *l;
 
1633
 
 
1634
                foreach(l, rcexpr->opnos)
 
1635
                {
 
1636
                        add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
 
1637
                                                           context->addrs);
 
1638
                }
 
1639
                foreach(l, rcexpr->opfamilies)
 
1640
                {
 
1641
                        add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
 
1642
                                                           context->addrs);
 
1643
                }
 
1644
                /* fall through to examine arguments */
 
1645
        }
 
1646
        else if (IsA(node, CoerceToDomain))
 
1647
        {
 
1648
                CoerceToDomain *cd = (CoerceToDomain *) node;
 
1649
 
 
1650
                add_object_address(OCLASS_TYPE, cd->resulttype, 0,
 
1651
                                                   context->addrs);
 
1652
        }
 
1653
        else if (IsA(node, SortGroupClause))
 
1654
        {
 
1655
                SortGroupClause *sgc = (SortGroupClause *) node;
 
1656
 
 
1657
                add_object_address(OCLASS_OPERATOR, sgc->eqop, 0,
 
1658
                                                   context->addrs);
 
1659
                if (OidIsValid(sgc->sortop))
 
1660
                        add_object_address(OCLASS_OPERATOR, sgc->sortop, 0,
 
1661
                                                           context->addrs);
 
1662
                return false;
 
1663
        }
 
1664
        else if (IsA(node, Query))
 
1665
        {
 
1666
                /* Recurse into RTE subquery or not-yet-planned sublink subquery */
 
1667
                Query      *query = (Query *) node;
 
1668
                ListCell   *lc;
 
1669
                bool            result;
 
1670
 
 
1671
                /*
 
1672
                 * Add whole-relation refs for each plain relation mentioned in the
 
1673
                 * subquery's rtable, as well as refs for any datatypes and collations
 
1674
                 * used in a RECORD function's output.
 
1675
                 *
 
1676
                 * Note: query_tree_walker takes care of recursing into RTE_FUNCTION
 
1677
                 * RTEs, subqueries, etc, so no need to do that here.  But keep it
 
1678
                 * from looking at join alias lists.
 
1679
                 *
 
1680
                 * Note: we don't need to worry about collations mentioned in
 
1681
                 * RTE_VALUES or RTE_CTE RTEs, because those must just duplicate
 
1682
                 * collations referenced in other parts of the Query.
 
1683
                 */
 
1684
                foreach(lc, query->rtable)
 
1685
                {
 
1686
                        RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
 
1687
                        ListCell   *ct;
 
1688
 
 
1689
                        switch (rte->rtekind)
 
1690
                        {
 
1691
                                case RTE_RELATION:
 
1692
                                        add_object_address(OCLASS_CLASS, rte->relid, 0,
 
1693
                                                                           context->addrs);
 
1694
                                        break;
 
1695
                                case RTE_FUNCTION:
 
1696
                                        foreach(ct, rte->funccoltypes)
 
1697
                                        {
 
1698
                                                add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0,
 
1699
                                                                                   context->addrs);
 
1700
                                        }
 
1701
                                        foreach(ct, rte->funccolcollations)
 
1702
                                        {
 
1703
                                                Oid                     collid = lfirst_oid(ct);
 
1704
 
 
1705
                                                if (OidIsValid(collid) &&
 
1706
                                                        collid != DEFAULT_COLLATION_OID)
 
1707
                                                        add_object_address(OCLASS_COLLATION, collid, 0,
 
1708
                                                                                           context->addrs);
 
1709
                                        }
 
1710
                                        break;
 
1711
                                default:
 
1712
                                        break;
 
1713
                        }
 
1714
                }
 
1715
 
 
1716
                /*
 
1717
                 * Add dependencies on constraints listed in query's constraintDeps
 
1718
                 */
 
1719
                foreach(lc, query->constraintDeps)
 
1720
                {
 
1721
                        add_object_address(OCLASS_CONSTRAINT, lfirst_oid(lc), 0,
 
1722
                                                           context->addrs);
 
1723
                }
 
1724
 
 
1725
                /* query_tree_walker ignores ORDER BY etc, but we need those opers */
 
1726
                find_expr_references_walker((Node *) query->sortClause, context);
 
1727
                find_expr_references_walker((Node *) query->groupClause, context);
 
1728
                find_expr_references_walker((Node *) query->windowClause, context);
 
1729
                find_expr_references_walker((Node *) query->distinctClause, context);
 
1730
 
 
1731
                /* Examine substructure of query */
 
1732
                context->rtables = lcons(query->rtable, context->rtables);
 
1733
                result = query_tree_walker(query,
 
1734
                                                                   find_expr_references_walker,
 
1735
                                                                   (void *) context,
 
1736
                                                                   QTW_IGNORE_JOINALIASES);
 
1737
                context->rtables = list_delete_first(context->rtables);
 
1738
                return result;
 
1739
        }
 
1740
        else if (IsA(node, SetOperationStmt))
 
1741
        {
 
1742
                SetOperationStmt *setop = (SetOperationStmt *) node;
 
1743
 
 
1744
                /* we need to look at the groupClauses for operator references */
 
1745
                find_expr_references_walker((Node *) setop->groupClauses, context);
 
1746
                /* fall through to examine child nodes */
 
1747
        }
 
1748
 
 
1749
        return expression_tree_walker(node, find_expr_references_walker,
 
1750
                                                                  (void *) context);
 
1751
}
 
1752
 
 
1753
/*
 
1754
 * Given an array of dependency references, eliminate any duplicates.
 
1755
 */
 
1756
static void
 
1757
eliminate_duplicate_dependencies(ObjectAddresses *addrs)
 
1758
{
 
1759
        ObjectAddress *priorobj;
 
1760
        int                     oldref,
 
1761
                                newrefs;
 
1762
 
 
1763
        /*
 
1764
         * We can't sort if the array has "extra" data, because there's no way to
 
1765
         * keep it in sync.  Fortunately that combination of features is not
 
1766
         * needed.
 
1767
         */
 
1768
        Assert(!addrs->extras);
 
1769
 
 
1770
        if (addrs->numrefs <= 1)
 
1771
                return;                                 /* nothing to do */
 
1772
 
 
1773
        /* Sort the refs so that duplicates are adjacent */
 
1774
        qsort((void *) addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
 
1775
                  object_address_comparator);
 
1776
 
 
1777
        /* Remove dups */
 
1778
        priorobj = addrs->refs;
 
1779
        newrefs = 1;
 
1780
        for (oldref = 1; oldref < addrs->numrefs; oldref++)
 
1781
        {
 
1782
                ObjectAddress *thisobj = addrs->refs + oldref;
 
1783
 
 
1784
                if (priorobj->classId == thisobj->classId &&
 
1785
                        priorobj->objectId == thisobj->objectId)
 
1786
                {
 
1787
                        if (priorobj->objectSubId == thisobj->objectSubId)
 
1788
                                continue;               /* identical, so drop thisobj */
 
1789
 
 
1790
                        /*
 
1791
                         * If we have a whole-object reference and a reference to a part
 
1792
                         * of the same object, we don't need the whole-object reference
 
1793
                         * (for example, we don't need to reference both table foo and
 
1794
                         * column foo.bar).  The whole-object reference will always appear
 
1795
                         * first in the sorted list.
 
1796
                         */
 
1797
                        if (priorobj->objectSubId == 0)
 
1798
                        {
 
1799
                                /* replace whole ref with partial */
 
1800
                                priorobj->objectSubId = thisobj->objectSubId;
 
1801
                                continue;
 
1802
                        }
 
1803
                }
 
1804
                /* Not identical, so add thisobj to output set */
 
1805
                priorobj++;
 
1806
                *priorobj = *thisobj;
 
1807
                newrefs++;
 
1808
        }
 
1809
 
 
1810
        addrs->numrefs = newrefs;
 
1811
}
 
1812
 
 
1813
/*
 
1814
 * qsort comparator for ObjectAddress items
 
1815
 */
 
1816
static int
 
1817
object_address_comparator(const void *a, const void *b)
 
1818
{
 
1819
        const ObjectAddress *obja = (const ObjectAddress *) a;
 
1820
        const ObjectAddress *objb = (const ObjectAddress *) b;
 
1821
 
 
1822
        if (obja->classId < objb->classId)
 
1823
                return -1;
 
1824
        if (obja->classId > objb->classId)
 
1825
                return 1;
 
1826
        if (obja->objectId < objb->objectId)
 
1827
                return -1;
 
1828
        if (obja->objectId > objb->objectId)
 
1829
                return 1;
 
1830
 
 
1831
        /*
 
1832
         * We sort the subId as an unsigned int so that 0 will come first. See
 
1833
         * logic in eliminate_duplicate_dependencies.
 
1834
         */
 
1835
        if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
 
1836
                return -1;
 
1837
        if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
 
1838
                return 1;
 
1839
        return 0;
 
1840
}
 
1841
 
 
1842
/*
 
1843
 * Routines for handling an expansible array of ObjectAddress items.
 
1844
 *
 
1845
 * new_object_addresses: create a new ObjectAddresses array.
 
1846
 */
 
1847
ObjectAddresses *
 
1848
new_object_addresses(void)
 
1849
{
 
1850
        ObjectAddresses *addrs;
 
1851
 
 
1852
        addrs = palloc(sizeof(ObjectAddresses));
 
1853
 
 
1854
        addrs->numrefs = 0;
 
1855
        addrs->maxrefs = 32;
 
1856
        addrs->refs = (ObjectAddress *)
 
1857
                palloc(addrs->maxrefs * sizeof(ObjectAddress));
 
1858
        addrs->extras = NULL;           /* until/unless needed */
 
1859
 
 
1860
        return addrs;
 
1861
}
 
1862
 
 
1863
/*
 
1864
 * Add an entry to an ObjectAddresses array.
 
1865
 *
 
1866
 * It is convenient to specify the class by ObjectClass rather than directly
 
1867
 * by catalog OID.
 
1868
 */
 
1869
static void
 
1870
add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
 
1871
                                   ObjectAddresses *addrs)
 
1872
{
 
1873
        ObjectAddress *item;
 
1874
 
 
1875
        /* enlarge array if needed */
 
1876
        if (addrs->numrefs >= addrs->maxrefs)
 
1877
        {
 
1878
                addrs->maxrefs *= 2;
 
1879
                addrs->refs = (ObjectAddress *)
 
1880
                        repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
 
1881
                Assert(!addrs->extras);
 
1882
        }
 
1883
        /* record this item */
 
1884
        item = addrs->refs + addrs->numrefs;
 
1885
        item->classId = object_classes[oclass];
 
1886
        item->objectId = objectId;
 
1887
        item->objectSubId = subId;
 
1888
        addrs->numrefs++;
 
1889
}
 
1890
 
 
1891
/*
 
1892
 * Add an entry to an ObjectAddresses array.
 
1893
 *
 
1894
 * As above, but specify entry exactly.
 
1895
 */
 
1896
void
 
1897
add_exact_object_address(const ObjectAddress *object,
 
1898
                                                 ObjectAddresses *addrs)
 
1899
{
 
1900
        ObjectAddress *item;
 
1901
 
 
1902
        /* enlarge array if needed */
 
1903
        if (addrs->numrefs >= addrs->maxrefs)
 
1904
        {
 
1905
                addrs->maxrefs *= 2;
 
1906
                addrs->refs = (ObjectAddress *)
 
1907
                        repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
 
1908
                Assert(!addrs->extras);
 
1909
        }
 
1910
        /* record this item */
 
1911
        item = addrs->refs + addrs->numrefs;
 
1912
        *item = *object;
 
1913
        addrs->numrefs++;
 
1914
}
 
1915
 
 
1916
/*
 
1917
 * Add an entry to an ObjectAddresses array.
 
1918
 *
 
1919
 * As above, but specify entry exactly and provide some "extra" data too.
 
1920
 */
 
1921
static void
 
1922
add_exact_object_address_extra(const ObjectAddress *object,
 
1923
                                                           const ObjectAddressExtra *extra,
 
1924
                                                           ObjectAddresses *addrs)
 
1925
{
 
1926
        ObjectAddress *item;
 
1927
        ObjectAddressExtra *itemextra;
 
1928
 
 
1929
        /* allocate extra space if first time */
 
1930
        if (!addrs->extras)
 
1931
                addrs->extras = (ObjectAddressExtra *)
 
1932
                        palloc(addrs->maxrefs * sizeof(ObjectAddressExtra));
 
1933
 
 
1934
        /* enlarge array if needed */
 
1935
        if (addrs->numrefs >= addrs->maxrefs)
 
1936
        {
 
1937
                addrs->maxrefs *= 2;
 
1938
                addrs->refs = (ObjectAddress *)
 
1939
                        repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
 
1940
                addrs->extras = (ObjectAddressExtra *)
 
1941
                        repalloc(addrs->extras, addrs->maxrefs * sizeof(ObjectAddressExtra));
 
1942
        }
 
1943
        /* record this item */
 
1944
        item = addrs->refs + addrs->numrefs;
 
1945
        *item = *object;
 
1946
        itemextra = addrs->extras + addrs->numrefs;
 
1947
        *itemextra = *extra;
 
1948
        addrs->numrefs++;
 
1949
}
 
1950
 
 
1951
/*
 
1952
 * Test whether an object is present in an ObjectAddresses array.
 
1953
 *
 
1954
 * We return "true" if object is a subobject of something in the array, too.
 
1955
 */
 
1956
bool
 
1957
object_address_present(const ObjectAddress *object,
 
1958
                                           const ObjectAddresses *addrs)
 
1959
{
 
1960
        int                     i;
 
1961
 
 
1962
        for (i = addrs->numrefs - 1; i >= 0; i--)
 
1963
        {
 
1964
                const ObjectAddress *thisobj = addrs->refs + i;
 
1965
 
 
1966
                if (object->classId == thisobj->classId &&
 
1967
                        object->objectId == thisobj->objectId)
 
1968
                {
 
1969
                        if (object->objectSubId == thisobj->objectSubId ||
 
1970
                                thisobj->objectSubId == 0)
 
1971
                                return true;
 
1972
                }
 
1973
        }
 
1974
 
 
1975
        return false;
 
1976
}
 
1977
 
 
1978
/*
 
1979
 * As above, except that if the object is present then also OR the given
 
1980
 * flags into its associated extra data (which must exist).
 
1981
 */
 
1982
static bool
 
1983
object_address_present_add_flags(const ObjectAddress *object,
 
1984
                                                                 int flags,
 
1985
                                                                 ObjectAddresses *addrs)
 
1986
{
 
1987
        int                     i;
 
1988
 
 
1989
        for (i = addrs->numrefs - 1; i >= 0; i--)
 
1990
        {
 
1991
                ObjectAddress *thisobj = addrs->refs + i;
 
1992
 
 
1993
                if (object->classId == thisobj->classId &&
 
1994
                        object->objectId == thisobj->objectId)
 
1995
                {
 
1996
                        if (object->objectSubId == thisobj->objectSubId)
 
1997
                        {
 
1998
                                ObjectAddressExtra *thisextra = addrs->extras + i;
 
1999
 
 
2000
                                thisextra->flags |= flags;
 
2001
                                return true;
 
2002
                        }
 
2003
                        if (thisobj->objectSubId == 0)
 
2004
                        {
 
2005
                                /*
 
2006
                                 * We get here if we find a need to delete a column after
 
2007
                                 * having already decided to drop its whole table.      Obviously
 
2008
                                 * we no longer need to drop the column.  But don't plaster
 
2009
                                 * its flags on the table.
 
2010
                                 */
 
2011
                                return true;
 
2012
                        }
 
2013
                }
 
2014
        }
 
2015
 
 
2016
        return false;
 
2017
}
 
2018
 
 
2019
/*
 
2020
 * Record multiple dependencies from an ObjectAddresses array, after first
 
2021
 * removing any duplicates.
 
2022
 */
 
2023
void
 
2024
record_object_address_dependencies(const ObjectAddress *depender,
 
2025
                                                                   ObjectAddresses *referenced,
 
2026
                                                                   DependencyType behavior)
 
2027
{
 
2028
        eliminate_duplicate_dependencies(referenced);
 
2029
        recordMultipleDependencies(depender,
 
2030
                                                           referenced->refs, referenced->numrefs,
 
2031
                                                           behavior);
 
2032
}
 
2033
 
 
2034
/*
 
2035
 * Clean up when done with an ObjectAddresses array.
 
2036
 */
 
2037
void
 
2038
free_object_addresses(ObjectAddresses *addrs)
 
2039
{
 
2040
        pfree(addrs->refs);
 
2041
        if (addrs->extras)
 
2042
                pfree(addrs->extras);
 
2043
        pfree(addrs);
 
2044
}
 
2045
 
 
2046
/*
 
2047
 * Determine the class of a given object identified by objectAddress.
 
2048
 *
 
2049
 * This function is essentially the reverse mapping for the object_classes[]
 
2050
 * table.  We implement it as a function because the OIDs aren't consecutive.
 
2051
 */
 
2052
ObjectClass
 
2053
getObjectClass(const ObjectAddress *object)
 
2054
{
 
2055
        /* only pg_class entries can have nonzero objectSubId */
 
2056
        if (object->classId != RelationRelationId &&
 
2057
                object->objectSubId != 0)
 
2058
                elog(ERROR, "invalid objectSubId 0 for object class %u",
 
2059
                         object->classId);
 
2060
 
 
2061
        switch (object->classId)
 
2062
        {
 
2063
                case RelationRelationId:
 
2064
                        /* caller must check objectSubId */
 
2065
                        return OCLASS_CLASS;
 
2066
 
 
2067
                case ProcedureRelationId:
 
2068
                        return OCLASS_PROC;
 
2069
 
 
2070
                case TypeRelationId:
 
2071
                        return OCLASS_TYPE;
 
2072
 
 
2073
                case CastRelationId:
 
2074
                        return OCLASS_CAST;
 
2075
 
 
2076
                case CollationRelationId:
 
2077
                        return OCLASS_COLLATION;
 
2078
 
 
2079
                case ConstraintRelationId:
 
2080
                        return OCLASS_CONSTRAINT;
 
2081
 
 
2082
                case ConversionRelationId:
 
2083
                        return OCLASS_CONVERSION;
 
2084
 
 
2085
                case AttrDefaultRelationId:
 
2086
                        return OCLASS_DEFAULT;
 
2087
 
 
2088
                case LanguageRelationId:
 
2089
                        return OCLASS_LANGUAGE;
 
2090
 
 
2091
                case LargeObjectRelationId:
 
2092
                        return OCLASS_LARGEOBJECT;
 
2093
 
 
2094
                case OperatorRelationId:
 
2095
                        return OCLASS_OPERATOR;
 
2096
 
 
2097
                case OperatorClassRelationId:
 
2098
                        return OCLASS_OPCLASS;
 
2099
 
 
2100
                case OperatorFamilyRelationId:
 
2101
                        return OCLASS_OPFAMILY;
 
2102
 
 
2103
                case AccessMethodOperatorRelationId:
 
2104
                        return OCLASS_AMOP;
 
2105
 
 
2106
                case AccessMethodProcedureRelationId:
 
2107
                        return OCLASS_AMPROC;
 
2108
 
 
2109
                case RewriteRelationId:
 
2110
                        return OCLASS_REWRITE;
 
2111
 
 
2112
                case TriggerRelationId:
 
2113
                        return OCLASS_TRIGGER;
 
2114
 
 
2115
                case NamespaceRelationId:
 
2116
                        return OCLASS_SCHEMA;
 
2117
 
 
2118
                case TSParserRelationId:
 
2119
                        return OCLASS_TSPARSER;
 
2120
 
 
2121
                case TSDictionaryRelationId:
 
2122
                        return OCLASS_TSDICT;
 
2123
 
 
2124
                case TSTemplateRelationId:
 
2125
                        return OCLASS_TSTEMPLATE;
 
2126
 
 
2127
                case TSConfigRelationId:
 
2128
                        return OCLASS_TSCONFIG;
 
2129
 
 
2130
                case AuthIdRelationId:
 
2131
                        return OCLASS_ROLE;
 
2132
 
 
2133
                case DatabaseRelationId:
 
2134
                        return OCLASS_DATABASE;
 
2135
 
 
2136
                case TableSpaceRelationId:
 
2137
                        return OCLASS_TBLSPACE;
 
2138
 
 
2139
                case ForeignDataWrapperRelationId:
 
2140
                        return OCLASS_FDW;
 
2141
 
 
2142
                case ForeignServerRelationId:
 
2143
                        return OCLASS_FOREIGN_SERVER;
 
2144
 
 
2145
                case UserMappingRelationId:
 
2146
                        return OCLASS_USER_MAPPING;
 
2147
 
 
2148
                case DefaultAclRelationId:
 
2149
                        return OCLASS_DEFACL;
 
2150
 
 
2151
                case ExtensionRelationId:
 
2152
                        return OCLASS_EXTENSION;
 
2153
        }
 
2154
 
 
2155
        /* shouldn't get here */
 
2156
        elog(ERROR, "unrecognized object class: %u", object->classId);
 
2157
        return OCLASS_CLASS;            /* keep compiler quiet */
 
2158
}
 
2159
 
 
2160
/*
 
2161
 * getObjectDescription: build an object description for messages
 
2162
 *
 
2163
 * The result is a palloc'd string.
 
2164
 */
 
2165
char *
 
2166
getObjectDescription(const ObjectAddress *object)
 
2167
{
 
2168
        StringInfoData buffer;
 
2169
 
 
2170
        initStringInfo(&buffer);
 
2171
 
 
2172
        switch (getObjectClass(object))
 
2173
        {
 
2174
                case OCLASS_CLASS:
 
2175
                        getRelationDescription(&buffer, object->objectId);
 
2176
                        if (object->objectSubId != 0)
 
2177
                                appendStringInfo(&buffer, _(" column %s"),
 
2178
                                                                 get_relid_attribute_name(object->objectId,
 
2179
                                                                                                           object->objectSubId));
 
2180
                        break;
 
2181
 
 
2182
                case OCLASS_PROC:
 
2183
                        appendStringInfo(&buffer, _("function %s"),
 
2184
                                                         format_procedure(object->objectId));
 
2185
                        break;
 
2186
 
 
2187
                case OCLASS_TYPE:
 
2188
                        appendStringInfo(&buffer, _("type %s"),
 
2189
                                                         format_type_be(object->objectId));
 
2190
                        break;
 
2191
 
 
2192
                case OCLASS_CAST:
 
2193
                        {
 
2194
                                Relation        castDesc;
 
2195
                                ScanKeyData skey[1];
 
2196
                                SysScanDesc rcscan;
 
2197
                                HeapTuple       tup;
 
2198
                                Form_pg_cast castForm;
 
2199
 
 
2200
                                castDesc = heap_open(CastRelationId, AccessShareLock);
 
2201
 
 
2202
                                ScanKeyInit(&skey[0],
 
2203
                                                        ObjectIdAttributeNumber,
 
2204
                                                        BTEqualStrategyNumber, F_OIDEQ,
 
2205
                                                        ObjectIdGetDatum(object->objectId));
 
2206
 
 
2207
                                rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
 
2208
                                                                                        SnapshotNow, 1, skey);
 
2209
 
 
2210
                                tup = systable_getnext(rcscan);
 
2211
 
 
2212
                                if (!HeapTupleIsValid(tup))
 
2213
                                        elog(ERROR, "could not find tuple for cast %u",
 
2214
                                                 object->objectId);
 
2215
 
 
2216
                                castForm = (Form_pg_cast) GETSTRUCT(tup);
 
2217
 
 
2218
                                appendStringInfo(&buffer, _("cast from %s to %s"),
 
2219
                                                                 format_type_be(castForm->castsource),
 
2220
                                                                 format_type_be(castForm->casttarget));
 
2221
 
 
2222
                                systable_endscan(rcscan);
 
2223
                                heap_close(castDesc, AccessShareLock);
 
2224
                                break;
 
2225
                        }
 
2226
 
 
2227
                case OCLASS_COLLATION:
 
2228
                        {
 
2229
                                HeapTuple       collTup;
 
2230
                                Form_pg_collation coll;
 
2231
 
 
2232
                                collTup = SearchSysCache1(COLLOID,
 
2233
                                                                                  ObjectIdGetDatum(object->objectId));
 
2234
                                if (!HeapTupleIsValid(collTup))
 
2235
                                        elog(ERROR, "cache lookup failed for collation %u",
 
2236
                                                 object->objectId);
 
2237
                                coll = (Form_pg_collation) GETSTRUCT(collTup);
 
2238
                                appendStringInfo(&buffer, _("collation %s"),
 
2239
                                                                 NameStr(coll->collname));
 
2240
                                ReleaseSysCache(collTup);
 
2241
                                break;
 
2242
                        }
 
2243
 
 
2244
                case OCLASS_CONSTRAINT:
 
2245
                        {
 
2246
                                HeapTuple       conTup;
 
2247
                                Form_pg_constraint con;
 
2248
 
 
2249
                                conTup = SearchSysCache1(CONSTROID,
 
2250
                                                                                 ObjectIdGetDatum(object->objectId));
 
2251
                                if (!HeapTupleIsValid(conTup))
 
2252
                                        elog(ERROR, "cache lookup failed for constraint %u",
 
2253
                                                 object->objectId);
 
2254
                                con = (Form_pg_constraint) GETSTRUCT(conTup);
 
2255
 
 
2256
                                if (OidIsValid(con->conrelid))
 
2257
                                {
 
2258
                                        StringInfoData rel;
 
2259
 
 
2260
                                        initStringInfo(&rel);
 
2261
                                        getRelationDescription(&rel, con->conrelid);
 
2262
                                        appendStringInfo(&buffer, _("constraint %s on %s"),
 
2263
                                                                         NameStr(con->conname), rel.data);
 
2264
                                        pfree(rel.data);
 
2265
                                }
 
2266
                                else
 
2267
                                {
 
2268
                                        appendStringInfo(&buffer, _("constraint %s"),
 
2269
                                                                         NameStr(con->conname));
 
2270
                                }
 
2271
 
 
2272
                                ReleaseSysCache(conTup);
 
2273
                                break;
 
2274
                        }
 
2275
 
 
2276
                case OCLASS_CONVERSION:
 
2277
                        {
 
2278
                                HeapTuple       conTup;
 
2279
 
 
2280
                                conTup = SearchSysCache1(CONVOID,
 
2281
                                                                                 ObjectIdGetDatum(object->objectId));
 
2282
                                if (!HeapTupleIsValid(conTup))
 
2283
                                        elog(ERROR, "cache lookup failed for conversion %u",
 
2284
                                                 object->objectId);
 
2285
                                appendStringInfo(&buffer, _("conversion %s"),
 
2286
                                 NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
 
2287
                                ReleaseSysCache(conTup);
 
2288
                                break;
 
2289
                        }
 
2290
 
 
2291
                case OCLASS_DEFAULT:
 
2292
                        {
 
2293
                                Relation        attrdefDesc;
 
2294
                                ScanKeyData skey[1];
 
2295
                                SysScanDesc adscan;
 
2296
                                HeapTuple       tup;
 
2297
                                Form_pg_attrdef attrdef;
 
2298
                                ObjectAddress colobject;
 
2299
 
 
2300
                                attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
 
2301
 
 
2302
                                ScanKeyInit(&skey[0],
 
2303
                                                        ObjectIdAttributeNumber,
 
2304
                                                        BTEqualStrategyNumber, F_OIDEQ,
 
2305
                                                        ObjectIdGetDatum(object->objectId));
 
2306
 
 
2307
                                adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
 
2308
                                                                                        true, SnapshotNow, 1, skey);
 
2309
 
 
2310
                                tup = systable_getnext(adscan);
 
2311
 
 
2312
                                if (!HeapTupleIsValid(tup))
 
2313
                                        elog(ERROR, "could not find tuple for attrdef %u",
 
2314
                                                 object->objectId);
 
2315
 
 
2316
                                attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
 
2317
 
 
2318
                                colobject.classId = RelationRelationId;
 
2319
                                colobject.objectId = attrdef->adrelid;
 
2320
                                colobject.objectSubId = attrdef->adnum;
 
2321
 
 
2322
                                appendStringInfo(&buffer, _("default for %s"),
 
2323
                                                                 getObjectDescription(&colobject));
 
2324
 
 
2325
                                systable_endscan(adscan);
 
2326
                                heap_close(attrdefDesc, AccessShareLock);
 
2327
                                break;
 
2328
                        }
 
2329
 
 
2330
                case OCLASS_LANGUAGE:
 
2331
                        {
 
2332
                                HeapTuple       langTup;
 
2333
 
 
2334
                                langTup = SearchSysCache1(LANGOID,
 
2335
                                                                                  ObjectIdGetDatum(object->objectId));
 
2336
                                if (!HeapTupleIsValid(langTup))
 
2337
                                        elog(ERROR, "cache lookup failed for language %u",
 
2338
                                                 object->objectId);
 
2339
                                appendStringInfo(&buffer, _("language %s"),
 
2340
                                  NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
 
2341
                                ReleaseSysCache(langTup);
 
2342
                                break;
 
2343
                        }
 
2344
                case OCLASS_LARGEOBJECT:
 
2345
                        appendStringInfo(&buffer, _("large object %u"),
 
2346
                                                         object->objectId);
 
2347
                        break;
 
2348
 
 
2349
                case OCLASS_OPERATOR:
 
2350
                        appendStringInfo(&buffer, _("operator %s"),
 
2351
                                                         format_operator(object->objectId));
 
2352
                        break;
 
2353
 
 
2354
                case OCLASS_OPCLASS:
 
2355
                        {
 
2356
                                HeapTuple       opcTup;
 
2357
                                Form_pg_opclass opcForm;
 
2358
                                HeapTuple       amTup;
 
2359
                                Form_pg_am      amForm;
 
2360
                                char       *nspname;
 
2361
 
 
2362
                                opcTup = SearchSysCache1(CLAOID,
 
2363
                                                                                 ObjectIdGetDatum(object->objectId));
 
2364
                                if (!HeapTupleIsValid(opcTup))
 
2365
                                        elog(ERROR, "cache lookup failed for opclass %u",
 
2366
                                                 object->objectId);
 
2367
                                opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
 
2368
 
 
2369
                                amTup = SearchSysCache1(AMOID,
 
2370
                                                                                ObjectIdGetDatum(opcForm->opcmethod));
 
2371
                                if (!HeapTupleIsValid(amTup))
 
2372
                                        elog(ERROR, "cache lookup failed for access method %u",
 
2373
                                                 opcForm->opcmethod);
 
2374
                                amForm = (Form_pg_am) GETSTRUCT(amTup);
 
2375
 
 
2376
                                /* Qualify the name if not visible in search path */
 
2377
                                if (OpclassIsVisible(object->objectId))
 
2378
                                        nspname = NULL;
 
2379
                                else
 
2380
                                        nspname = get_namespace_name(opcForm->opcnamespace);
 
2381
 
 
2382
                                appendStringInfo(&buffer, _("operator class %s for access method %s"),
 
2383
                                                                 quote_qualified_identifier(nspname,
 
2384
                                                                                                  NameStr(opcForm->opcname)),
 
2385
                                                                 NameStr(amForm->amname));
 
2386
 
 
2387
                                ReleaseSysCache(amTup);
 
2388
                                ReleaseSysCache(opcTup);
 
2389
                                break;
 
2390
                        }
 
2391
 
 
2392
                case OCLASS_OPFAMILY:
 
2393
                        getOpFamilyDescription(&buffer, object->objectId);
 
2394
                        break;
 
2395
 
 
2396
                case OCLASS_AMOP:
 
2397
                        {
 
2398
                                Relation        amopDesc;
 
2399
                                ScanKeyData skey[1];
 
2400
                                SysScanDesc amscan;
 
2401
                                HeapTuple       tup;
 
2402
                                Form_pg_amop amopForm;
 
2403
                                StringInfoData opfam;
 
2404
 
 
2405
                                amopDesc = heap_open(AccessMethodOperatorRelationId,
 
2406
                                                                         AccessShareLock);
 
2407
 
 
2408
                                ScanKeyInit(&skey[0],
 
2409
                                                        ObjectIdAttributeNumber,
 
2410
                                                        BTEqualStrategyNumber, F_OIDEQ,
 
2411
                                                        ObjectIdGetDatum(object->objectId));
 
2412
 
 
2413
                                amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
 
2414
                                                                                        SnapshotNow, 1, skey);
 
2415
 
 
2416
                                tup = systable_getnext(amscan);
 
2417
 
 
2418
                                if (!HeapTupleIsValid(tup))
 
2419
                                        elog(ERROR, "could not find tuple for amop entry %u",
 
2420
                                                 object->objectId);
 
2421
 
 
2422
                                amopForm = (Form_pg_amop) GETSTRUCT(tup);
 
2423
 
 
2424
                                initStringInfo(&opfam);
 
2425
                                getOpFamilyDescription(&opfam, amopForm->amopfamily);
 
2426
 
 
2427
                                /*
 
2428
                                 * translator: %d is the operator strategy (a number), the
 
2429
                                 * first two %s's are data type names, the third %s is the
 
2430
                                 * description of the operator family, and the last %s is the
 
2431
                                 * textual form of the operator with arguments.
 
2432
                                 */
 
2433
                                appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
 
2434
                                                                 amopForm->amopstrategy,
 
2435
                                                                 format_type_be(amopForm->amoplefttype),
 
2436
                                                                 format_type_be(amopForm->amoprighttype),
 
2437
                                                                 opfam.data,
 
2438
                                                                 format_operator(amopForm->amopopr));
 
2439
 
 
2440
                                pfree(opfam.data);
 
2441
 
 
2442
                                systable_endscan(amscan);
 
2443
                                heap_close(amopDesc, AccessShareLock);
 
2444
                                break;
 
2445
                        }
 
2446
 
 
2447
                case OCLASS_AMPROC:
 
2448
                        {
 
2449
                                Relation        amprocDesc;
 
2450
                                ScanKeyData skey[1];
 
2451
                                SysScanDesc amscan;
 
2452
                                HeapTuple       tup;
 
2453
                                Form_pg_amproc amprocForm;
 
2454
                                StringInfoData opfam;
 
2455
 
 
2456
                                amprocDesc = heap_open(AccessMethodProcedureRelationId,
 
2457
                                                                           AccessShareLock);
 
2458
 
 
2459
                                ScanKeyInit(&skey[0],
 
2460
                                                        ObjectIdAttributeNumber,
 
2461
                                                        BTEqualStrategyNumber, F_OIDEQ,
 
2462
                                                        ObjectIdGetDatum(object->objectId));
 
2463
 
 
2464
                                amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
 
2465
                                                                                        SnapshotNow, 1, skey);
 
2466
 
 
2467
                                tup = systable_getnext(amscan);
 
2468
 
 
2469
                                if (!HeapTupleIsValid(tup))
 
2470
                                        elog(ERROR, "could not find tuple for amproc entry %u",
 
2471
                                                 object->objectId);
 
2472
 
 
2473
                                amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
 
2474
 
 
2475
                                initStringInfo(&opfam);
 
2476
                                getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
 
2477
 
 
2478
                                /*
 
2479
                                 * translator: %d is the function number, the first two %s's
 
2480
                                 * are data type names, the third %s is the description of the
 
2481
                                 * operator family, and the last %s is the textual form of the
 
2482
                                 * function with arguments.
 
2483
                                 */
 
2484
                                appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
 
2485
                                                                 amprocForm->amprocnum,
 
2486
                                                                 format_type_be(amprocForm->amproclefttype),
 
2487
                                                                 format_type_be(amprocForm->amprocrighttype),
 
2488
                                                                 opfam.data,
 
2489
                                                                 format_procedure(amprocForm->amproc));
 
2490
 
 
2491
                                pfree(opfam.data);
 
2492
 
 
2493
                                systable_endscan(amscan);
 
2494
                                heap_close(amprocDesc, AccessShareLock);
 
2495
                                break;
 
2496
                        }
 
2497
 
 
2498
                case OCLASS_REWRITE:
 
2499
                        {
 
2500
                                Relation        ruleDesc;
 
2501
                                ScanKeyData skey[1];
 
2502
                                SysScanDesc rcscan;
 
2503
                                HeapTuple       tup;
 
2504
                                Form_pg_rewrite rule;
 
2505
 
 
2506
                                ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
 
2507
 
 
2508
                                ScanKeyInit(&skey[0],
 
2509
                                                        ObjectIdAttributeNumber,
 
2510
                                                        BTEqualStrategyNumber, F_OIDEQ,
 
2511
                                                        ObjectIdGetDatum(object->objectId));
 
2512
 
 
2513
                                rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
 
2514
                                                                                        SnapshotNow, 1, skey);
 
2515
 
 
2516
                                tup = systable_getnext(rcscan);
 
2517
 
 
2518
                                if (!HeapTupleIsValid(tup))
 
2519
                                        elog(ERROR, "could not find tuple for rule %u",
 
2520
                                                 object->objectId);
 
2521
 
 
2522
                                rule = (Form_pg_rewrite) GETSTRUCT(tup);
 
2523
 
 
2524
                                appendStringInfo(&buffer, _("rule %s on "),
 
2525
                                                                 NameStr(rule->rulename));
 
2526
                                getRelationDescription(&buffer, rule->ev_class);
 
2527
 
 
2528
                                systable_endscan(rcscan);
 
2529
                                heap_close(ruleDesc, AccessShareLock);
 
2530
                                break;
 
2531
                        }
 
2532
 
 
2533
                case OCLASS_TRIGGER:
 
2534
                        {
 
2535
                                Relation        trigDesc;
 
2536
                                ScanKeyData skey[1];
 
2537
                                SysScanDesc tgscan;
 
2538
                                HeapTuple       tup;
 
2539
                                Form_pg_trigger trig;
 
2540
 
 
2541
                                trigDesc = heap_open(TriggerRelationId, AccessShareLock);
 
2542
 
 
2543
                                ScanKeyInit(&skey[0],
 
2544
                                                        ObjectIdAttributeNumber,
 
2545
                                                        BTEqualStrategyNumber, F_OIDEQ,
 
2546
                                                        ObjectIdGetDatum(object->objectId));
 
2547
 
 
2548
                                tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
 
2549
                                                                                        SnapshotNow, 1, skey);
 
2550
 
 
2551
                                tup = systable_getnext(tgscan);
 
2552
 
 
2553
                                if (!HeapTupleIsValid(tup))
 
2554
                                        elog(ERROR, "could not find tuple for trigger %u",
 
2555
                                                 object->objectId);
 
2556
 
 
2557
                                trig = (Form_pg_trigger) GETSTRUCT(tup);
 
2558
 
 
2559
                                appendStringInfo(&buffer, _("trigger %s on "),
 
2560
                                                                 NameStr(trig->tgname));
 
2561
                                getRelationDescription(&buffer, trig->tgrelid);
 
2562
 
 
2563
                                systable_endscan(tgscan);
 
2564
                                heap_close(trigDesc, AccessShareLock);
 
2565
                                break;
 
2566
                        }
 
2567
 
 
2568
                case OCLASS_SCHEMA:
 
2569
                        {
 
2570
                                char       *nspname;
 
2571
 
 
2572
                                nspname = get_namespace_name(object->objectId);
 
2573
                                if (!nspname)
 
2574
                                        elog(ERROR, "cache lookup failed for namespace %u",
 
2575
                                                 object->objectId);
 
2576
                                appendStringInfo(&buffer, _("schema %s"), nspname);
 
2577
                                break;
 
2578
                        }
 
2579
 
 
2580
                case OCLASS_TSPARSER:
 
2581
                        {
 
2582
                                HeapTuple       tup;
 
2583
 
 
2584
                                tup = SearchSysCache1(TSPARSEROID,
 
2585
                                                                          ObjectIdGetDatum(object->objectId));
 
2586
                                if (!HeapTupleIsValid(tup))
 
2587
                                        elog(ERROR, "cache lookup failed for text search parser %u",
 
2588
                                                 object->objectId);
 
2589
                                appendStringInfo(&buffer, _("text search parser %s"),
 
2590
                                         NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
 
2591
                                ReleaseSysCache(tup);
 
2592
                                break;
 
2593
                        }
 
2594
 
 
2595
                case OCLASS_TSDICT:
 
2596
                        {
 
2597
                                HeapTuple       tup;
 
2598
 
 
2599
                                tup = SearchSysCache1(TSDICTOID,
 
2600
                                                                          ObjectIdGetDatum(object->objectId));
 
2601
                                if (!HeapTupleIsValid(tup))
 
2602
                                        elog(ERROR, "cache lookup failed for text search dictionary %u",
 
2603
                                                 object->objectId);
 
2604
                                appendStringInfo(&buffer, _("text search dictionary %s"),
 
2605
                                          NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
 
2606
                                ReleaseSysCache(tup);
 
2607
                                break;
 
2608
                        }
 
2609
 
 
2610
                case OCLASS_TSTEMPLATE:
 
2611
                        {
 
2612
                                HeapTuple       tup;
 
2613
 
 
2614
                                tup = SearchSysCache1(TSTEMPLATEOID,
 
2615
                                                                          ObjectIdGetDatum(object->objectId));
 
2616
                                if (!HeapTupleIsValid(tup))
 
2617
                                        elog(ERROR, "cache lookup failed for text search template %u",
 
2618
                                                 object->objectId);
 
2619
                                appendStringInfo(&buffer, _("text search template %s"),
 
2620
                                  NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
 
2621
                                ReleaseSysCache(tup);
 
2622
                                break;
 
2623
                        }
 
2624
 
 
2625
                case OCLASS_TSCONFIG:
 
2626
                        {
 
2627
                                HeapTuple       tup;
 
2628
 
 
2629
                                tup = SearchSysCache1(TSCONFIGOID,
 
2630
                                                                          ObjectIdGetDatum(object->objectId));
 
2631
                                if (!HeapTupleIsValid(tup))
 
2632
                                        elog(ERROR, "cache lookup failed for text search configuration %u",
 
2633
                                                 object->objectId);
 
2634
                                appendStringInfo(&buffer, _("text search configuration %s"),
 
2635
                                         NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
 
2636
                                ReleaseSysCache(tup);
 
2637
                                break;
 
2638
                        }
 
2639
 
 
2640
                case OCLASS_ROLE:
 
2641
                        {
 
2642
                                appendStringInfo(&buffer, _("role %s"),
 
2643
                                                                 GetUserNameFromId(object->objectId));
 
2644
                                break;
 
2645
                        }
 
2646
 
 
2647
                case OCLASS_DATABASE:
 
2648
                        {
 
2649
                                char       *datname;
 
2650
 
 
2651
                                datname = get_database_name(object->objectId);
 
2652
                                if (!datname)
 
2653
                                        elog(ERROR, "cache lookup failed for database %u",
 
2654
                                                 object->objectId);
 
2655
                                appendStringInfo(&buffer, _("database %s"), datname);
 
2656
                                break;
 
2657
                        }
 
2658
 
 
2659
                case OCLASS_TBLSPACE:
 
2660
                        {
 
2661
                                char       *tblspace;
 
2662
 
 
2663
                                tblspace = get_tablespace_name(object->objectId);
 
2664
                                if (!tblspace)
 
2665
                                        elog(ERROR, "cache lookup failed for tablespace %u",
 
2666
                                                 object->objectId);
 
2667
                                appendStringInfo(&buffer, _("tablespace %s"), tblspace);
 
2668
                                break;
 
2669
                        }
 
2670
 
 
2671
                case OCLASS_FDW:
 
2672
                        {
 
2673
                                ForeignDataWrapper *fdw;
 
2674
 
 
2675
                                fdw = GetForeignDataWrapper(object->objectId);
 
2676
                                appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
 
2677
                                break;
 
2678
                        }
 
2679
 
 
2680
                case OCLASS_FOREIGN_SERVER:
 
2681
                        {
 
2682
                                ForeignServer *srv;
 
2683
 
 
2684
                                srv = GetForeignServer(object->objectId);
 
2685
                                appendStringInfo(&buffer, _("server %s"), srv->servername);
 
2686
                                break;
 
2687
                        }
 
2688
 
 
2689
                case OCLASS_USER_MAPPING:
 
2690
                        {
 
2691
                                HeapTuple       tup;
 
2692
                                Oid                     useid;
 
2693
                                char       *usename;
 
2694
 
 
2695
                                tup = SearchSysCache1(USERMAPPINGOID,
 
2696
                                                                          ObjectIdGetDatum(object->objectId));
 
2697
                                if (!HeapTupleIsValid(tup))
 
2698
                                        elog(ERROR, "cache lookup failed for user mapping %u",
 
2699
                                                 object->objectId);
 
2700
 
 
2701
                                useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
 
2702
 
 
2703
                                ReleaseSysCache(tup);
 
2704
 
 
2705
                                if (OidIsValid(useid))
 
2706
                                        usename = GetUserNameFromId(useid);
 
2707
                                else
 
2708
                                        usename = "public";
 
2709
 
 
2710
                                appendStringInfo(&buffer, _("user mapping for %s"), usename);
 
2711
                                break;
 
2712
                        }
 
2713
 
 
2714
                case OCLASS_DEFACL:
 
2715
                        {
 
2716
                                Relation        defaclrel;
 
2717
                                ScanKeyData skey[1];
 
2718
                                SysScanDesc rcscan;
 
2719
                                HeapTuple       tup;
 
2720
                                Form_pg_default_acl defacl;
 
2721
 
 
2722
                                defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
 
2723
 
 
2724
                                ScanKeyInit(&skey[0],
 
2725
                                                        ObjectIdAttributeNumber,
 
2726
                                                        BTEqualStrategyNumber, F_OIDEQ,
 
2727
                                                        ObjectIdGetDatum(object->objectId));
 
2728
 
 
2729
                                rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
 
2730
                                                                                        true, SnapshotNow, 1, skey);
 
2731
 
 
2732
                                tup = systable_getnext(rcscan);
 
2733
 
 
2734
                                if (!HeapTupleIsValid(tup))
 
2735
                                        elog(ERROR, "could not find tuple for default ACL %u",
 
2736
                                                 object->objectId);
 
2737
 
 
2738
                                defacl = (Form_pg_default_acl) GETSTRUCT(tup);
 
2739
 
 
2740
                                switch (defacl->defaclobjtype)
 
2741
                                {
 
2742
                                        case DEFACLOBJ_RELATION:
 
2743
                                                appendStringInfo(&buffer,
 
2744
                                                                                 _("default privileges on new relations belonging to role %s"),
 
2745
                                                                          GetUserNameFromId(defacl->defaclrole));
 
2746
                                                break;
 
2747
                                        case DEFACLOBJ_SEQUENCE:
 
2748
                                                appendStringInfo(&buffer,
 
2749
                                                                                 _("default privileges on new sequences belonging to role %s"),
 
2750
                                                                          GetUserNameFromId(defacl->defaclrole));
 
2751
                                                break;
 
2752
                                        case DEFACLOBJ_FUNCTION:
 
2753
                                                appendStringInfo(&buffer,
 
2754
                                                                                 _("default privileges on new functions belonging to role %s"),
 
2755
                                                                          GetUserNameFromId(defacl->defaclrole));
 
2756
                                                break;
 
2757
                                        default:
 
2758
                                                /* shouldn't get here */
 
2759
                                                appendStringInfo(&buffer,
 
2760
                                                                _("default privileges belonging to role %s"),
 
2761
                                                                          GetUserNameFromId(defacl->defaclrole));
 
2762
                                                break;
 
2763
                                }
 
2764
 
 
2765
                                if (OidIsValid(defacl->defaclnamespace))
 
2766
                                {
 
2767
                                        appendStringInfo(&buffer,
 
2768
                                                                         _(" in schema %s"),
 
2769
                                                                get_namespace_name(defacl->defaclnamespace));
 
2770
                                }
 
2771
 
 
2772
                                systable_endscan(rcscan);
 
2773
                                heap_close(defaclrel, AccessShareLock);
 
2774
                                break;
 
2775
                        }
 
2776
 
 
2777
                case OCLASS_EXTENSION:
 
2778
                        {
 
2779
                                char       *extname;
 
2780
 
 
2781
                                extname = get_extension_name(object->objectId);
 
2782
                                if (!extname)
 
2783
                                        elog(ERROR, "cache lookup failed for extension %u",
 
2784
                                                 object->objectId);
 
2785
                                appendStringInfo(&buffer, _("extension %s"), extname);
 
2786
                                break;
 
2787
                        }
 
2788
 
 
2789
                default:
 
2790
                        appendStringInfo(&buffer, "unrecognized object %u %u %d",
 
2791
                                                         object->classId,
 
2792
                                                         object->objectId,
 
2793
                                                         object->objectSubId);
 
2794
                        break;
 
2795
        }
 
2796
 
 
2797
        return buffer.data;
 
2798
}
 
2799
 
 
2800
/*
 
2801
 * getObjectDescriptionOids: as above, except the object is specified by Oids
 
2802
 */
 
2803
char *
 
2804
getObjectDescriptionOids(Oid classid, Oid objid)
 
2805
{
 
2806
        ObjectAddress address;
 
2807
 
 
2808
        address.classId = classid;
 
2809
        address.objectId = objid;
 
2810
        address.objectSubId = 0;
 
2811
 
 
2812
        return getObjectDescription(&address);
 
2813
}
 
2814
 
 
2815
/*
 
2816
 * subroutine for getObjectDescription: describe a relation
 
2817
 */
 
2818
static void
 
2819
getRelationDescription(StringInfo buffer, Oid relid)
 
2820
{
 
2821
        HeapTuple       relTup;
 
2822
        Form_pg_class relForm;
 
2823
        char       *nspname;
 
2824
        char       *relname;
 
2825
 
 
2826
        relTup = SearchSysCache1(RELOID,
 
2827
                                                         ObjectIdGetDatum(relid));
 
2828
        if (!HeapTupleIsValid(relTup))
 
2829
                elog(ERROR, "cache lookup failed for relation %u", relid);
 
2830
        relForm = (Form_pg_class) GETSTRUCT(relTup);
 
2831
 
 
2832
        /* Qualify the name if not visible in search path */
 
2833
        if (RelationIsVisible(relid))
 
2834
                nspname = NULL;
 
2835
        else
 
2836
                nspname = get_namespace_name(relForm->relnamespace);
 
2837
 
 
2838
        relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
 
2839
 
 
2840
        switch (relForm->relkind)
 
2841
        {
 
2842
                case RELKIND_RELATION:
 
2843
                        appendStringInfo(buffer, _("table %s"),
 
2844
                                                         relname);
 
2845
                        break;
 
2846
                case RELKIND_INDEX:
 
2847
                        appendStringInfo(buffer, _("index %s"),
 
2848
                                                         relname);
 
2849
                        break;
 
2850
                case RELKIND_SEQUENCE:
 
2851
                        appendStringInfo(buffer, _("sequence %s"),
 
2852
                                                         relname);
 
2853
                        break;
 
2854
                case RELKIND_UNCATALOGED:
 
2855
                        appendStringInfo(buffer, _("uncataloged table %s"),
 
2856
                                                         relname);
 
2857
                        break;
 
2858
                case RELKIND_TOASTVALUE:
 
2859
                        appendStringInfo(buffer, _("toast table %s"),
 
2860
                                                         relname);
 
2861
                        break;
 
2862
                case RELKIND_VIEW:
 
2863
                        appendStringInfo(buffer, _("view %s"),
 
2864
                                                         relname);
 
2865
                        break;
 
2866
                case RELKIND_COMPOSITE_TYPE:
 
2867
                        appendStringInfo(buffer, _("composite type %s"),
 
2868
                                                         relname);
 
2869
                        break;
 
2870
                case RELKIND_FOREIGN_TABLE:
 
2871
                        appendStringInfo(buffer, _("foreign table %s"),
 
2872
                                                         relname);
 
2873
                        break;
 
2874
                default:
 
2875
                        /* shouldn't get here */
 
2876
                        appendStringInfo(buffer, _("relation %s"),
 
2877
                                                         relname);
 
2878
                        break;
 
2879
        }
 
2880
 
 
2881
        ReleaseSysCache(relTup);
 
2882
}
 
2883
 
 
2884
/*
 
2885
 * subroutine for getObjectDescription: describe an operator family
 
2886
 */
 
2887
static void
 
2888
getOpFamilyDescription(StringInfo buffer, Oid opfid)
 
2889
{
 
2890
        HeapTuple       opfTup;
 
2891
        Form_pg_opfamily opfForm;
 
2892
        HeapTuple       amTup;
 
2893
        Form_pg_am      amForm;
 
2894
        char       *nspname;
 
2895
 
 
2896
        opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
 
2897
        if (!HeapTupleIsValid(opfTup))
 
2898
                elog(ERROR, "cache lookup failed for opfamily %u", opfid);
 
2899
        opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
 
2900
 
 
2901
        amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
 
2902
        if (!HeapTupleIsValid(amTup))
 
2903
                elog(ERROR, "cache lookup failed for access method %u",
 
2904
                         opfForm->opfmethod);
 
2905
        amForm = (Form_pg_am) GETSTRUCT(amTup);
 
2906
 
 
2907
        /* Qualify the name if not visible in search path */
 
2908
        if (OpfamilyIsVisible(opfid))
 
2909
                nspname = NULL;
 
2910
        else
 
2911
                nspname = get_namespace_name(opfForm->opfnamespace);
 
2912
 
 
2913
        appendStringInfo(buffer, _("operator family %s for access method %s"),
 
2914
                                         quote_qualified_identifier(nspname,
 
2915
                                                                                                NameStr(opfForm->opfname)),
 
2916
                                         NameStr(amForm->amname));
 
2917
 
 
2918
        ReleaseSysCache(amTup);
 
2919
        ReleaseSysCache(opfTup);
 
2920
}
 
2921
 
 
2922
/*
 
2923
 * SQL-level callable version of getObjectDescription
 
2924
 */
 
2925
Datum
 
2926
pg_describe_object(PG_FUNCTION_ARGS)
 
2927
{
 
2928
        Oid                     classid = PG_GETARG_OID(0);
 
2929
        Oid                     objid = PG_GETARG_OID(1);
 
2930
        int32           subobjid = PG_GETARG_INT32(2);
 
2931
        char       *description = NULL;
 
2932
        ObjectAddress address;
 
2933
 
 
2934
        /* for "pinned" items in pg_depend, return null */
 
2935
        if (!OidIsValid(classid) && !OidIsValid(objid))
 
2936
                PG_RETURN_NULL();
 
2937
 
 
2938
        address.classId = classid;
 
2939
        address.objectId = objid;
 
2940
        address.objectSubId = subobjid;
 
2941
 
 
2942
        description = getObjectDescription(&address);
 
2943
        PG_RETURN_TEXT_P(cstring_to_text(description));
 
2944
}