Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/catalog/objectaddress.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * objectaddress.c
4
 *    functions for working with ObjectAddresses
5
 *
6
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/catalog/objectaddress.c
12
 *
13
 *-------------------------------------------------------------------------
14
 */
15
16
#include "postgres.h"
17
18
#include "access/genam.h"
19
#include "access/htup_details.h"
20
#include "access/relation.h"
21
#include "access/table.h"
22
#include "catalog/catalog.h"
23
#include "catalog/objectaddress.h"
24
#include "catalog/pg_am.h"
25
#include "catalog/pg_amop.h"
26
#include "catalog/pg_amproc.h"
27
#include "catalog/pg_attrdef.h"
28
#include "catalog/pg_authid.h"
29
#include "catalog/pg_auth_members.h"
30
#include "catalog/pg_cast.h"
31
#include "catalog/pg_collation.h"
32
#include "catalog/pg_constraint.h"
33
#include "catalog/pg_conversion.h"
34
#include "catalog/pg_database.h"
35
#include "catalog/pg_default_acl.h"
36
#include "catalog/pg_event_trigger.h"
37
#include "catalog/pg_extension.h"
38
#include "catalog/pg_foreign_data_wrapper.h"
39
#include "catalog/pg_foreign_server.h"
40
#include "catalog/pg_language.h"
41
#include "catalog/pg_largeobject.h"
42
#include "catalog/pg_largeobject_metadata.h"
43
#include "catalog/pg_namespace.h"
44
#include "catalog/pg_opclass.h"
45
#include "catalog/pg_operator.h"
46
#include "catalog/pg_opfamily.h"
47
#include "catalog/pg_parameter_acl.h"
48
#include "catalog/pg_policy.h"
49
#include "catalog/pg_proc.h"
50
#include "catalog/pg_publication.h"
51
#include "catalog/pg_publication_namespace.h"
52
#include "catalog/pg_publication_rel.h"
53
#include "catalog/pg_rewrite.h"
54
#include "catalog/pg_statistic_ext.h"
55
#include "catalog/pg_subscription.h"
56
#include "catalog/pg_tablespace.h"
57
#include "catalog/pg_transform.h"
58
#include "catalog/pg_trigger.h"
59
#include "catalog/pg_ts_config.h"
60
#include "catalog/pg_ts_dict.h"
61
#include "catalog/pg_ts_parser.h"
62
#include "catalog/pg_ts_template.h"
63
#include "catalog/pg_type.h"
64
#include "catalog/pg_user_mapping.h"
65
#include "commands/defrem.h"
66
#include "commands/event_trigger.h"
67
#include "commands/extension.h"
68
#include "commands/policy.h"
69
#include "commands/proclang.h"
70
#include "commands/tablespace.h"
71
#include "commands/trigger.h"
72
#include "foreign/foreign.h"
73
#include "funcapi.h"
74
#include "miscadmin.h"
75
#include "parser/parse_func.h"
76
#include "parser/parse_oper.h"
77
#include "parser/parse_type.h"
78
#include "rewrite/rewriteSupport.h"
79
#include "storage/large_object.h"
80
#include "storage/lmgr.h"
81
#include "storage/sinval.h"
82
#include "utils/acl.h"
83
#include "utils/builtins.h"
84
#include "utils/fmgroids.h"
85
#include "utils/lsyscache.h"
86
#include "utils/memutils.h"
87
#include "utils/regproc.h"
88
#include "utils/syscache.h"
89
90
/*
91
 * ObjectProperty
92
 *
93
 * This array provides a common part of system object structure; to help
94
 * consolidate routines to handle various kind of object classes.
95
 */
96
typedef struct
97
{
98
  const char *class_descr;  /* string describing the catalog, for internal
99
                 * error messages */
100
  Oid     class_oid;    /* oid of catalog */
101
  Oid     oid_index_oid;  /* oid of index on system oid column */
102
  SysCacheIdentifier oid_catcache_id; /* id of catcache on system oid column  */
103
  SysCacheIdentifier name_catcache_id;  /* id of catcache on
104
                       * (name,namespace), or (name) if
105
                       * the object does not live in a
106
                       * namespace */
107
  AttrNumber  attnum_oid;   /* attribute number of oid column */
108
  AttrNumber  attnum_name;  /* attnum of name field */
109
  AttrNumber  attnum_namespace; /* attnum of namespace field */
110
  AttrNumber  attnum_owner; /* attnum of owner field */
111
  AttrNumber  attnum_acl;   /* attnum of acl field */
112
  ObjectType  objtype;    /* OBJECT_* of this object type */
113
  bool    is_nsp_name_unique; /* can the nsp/name combination (or name
114
                   * alone, if there's no namespace) be
115
                   * considered a unique identifier for an
116
                   * object of this class? */
117
} ObjectPropertyType;
118
119
static const ObjectPropertyType ObjectProperty[] =
120
{
121
  {
122
    "access method",
123
    AccessMethodRelationId,
124
    AmOidIndexId,
125
    AMOID,
126
    AMNAME,
127
    Anum_pg_am_oid,
128
    Anum_pg_am_amname,
129
    InvalidAttrNumber,
130
    InvalidAttrNumber,
131
    InvalidAttrNumber,
132
    OBJECT_ACCESS_METHOD,
133
    true
134
  },
135
  {
136
    "access method operator",
137
    AccessMethodOperatorRelationId,
138
    AccessMethodOperatorOidIndexId,
139
    SYSCACHEID_INVALID,
140
    SYSCACHEID_INVALID,
141
    Anum_pg_amop_oid,
142
    InvalidAttrNumber,
143
    InvalidAttrNumber,
144
    InvalidAttrNumber,
145
    InvalidAttrNumber,
146
    OBJECT_AMOP,
147
    false
148
  },
149
  {
150
    "access method procedure",
151
    AccessMethodProcedureRelationId,
152
    AccessMethodProcedureOidIndexId,
153
    SYSCACHEID_INVALID,
154
    SYSCACHEID_INVALID,
155
    Anum_pg_amproc_oid,
156
    InvalidAttrNumber,
157
    InvalidAttrNumber,
158
    InvalidAttrNumber,
159
    InvalidAttrNumber,
160
    OBJECT_AMPROC,
161
    false
162
  },
163
  {
164
    "cast",
165
    CastRelationId,
166
    CastOidIndexId,
167
    SYSCACHEID_INVALID,
168
    SYSCACHEID_INVALID,
169
    Anum_pg_cast_oid,
170
    InvalidAttrNumber,
171
    InvalidAttrNumber,
172
    InvalidAttrNumber,
173
    InvalidAttrNumber,
174
    OBJECT_CAST,
175
    false
176
  },
177
  {
178
    "collation",
179
    CollationRelationId,
180
    CollationOidIndexId,
181
    COLLOID,
182
    SYSCACHEID_INVALID,   /* COLLNAMEENCNSP also takes encoding */
183
    Anum_pg_collation_oid,
184
    Anum_pg_collation_collname,
185
    Anum_pg_collation_collnamespace,
186
    Anum_pg_collation_collowner,
187
    InvalidAttrNumber,
188
    OBJECT_COLLATION,
189
    true
190
  },
191
  {
192
    "constraint",
193
    ConstraintRelationId,
194
    ConstraintOidIndexId,
195
    CONSTROID,
196
    SYSCACHEID_INVALID,
197
    Anum_pg_constraint_oid,
198
    Anum_pg_constraint_conname,
199
    Anum_pg_constraint_connamespace,
200
    InvalidAttrNumber,
201
    InvalidAttrNumber,
202
    -1,
203
    false
204
  },
205
  {
206
    "conversion",
207
    ConversionRelationId,
208
    ConversionOidIndexId,
209
    CONVOID,
210
    CONNAMENSP,
211
    Anum_pg_conversion_oid,
212
    Anum_pg_conversion_conname,
213
    Anum_pg_conversion_connamespace,
214
    Anum_pg_conversion_conowner,
215
    InvalidAttrNumber,
216
    OBJECT_CONVERSION,
217
    true
218
  },
219
  {
220
    "database",
221
    DatabaseRelationId,
222
    DatabaseOidIndexId,
223
    DATABASEOID,
224
    SYSCACHEID_INVALID,
225
    Anum_pg_database_oid,
226
    Anum_pg_database_datname,
227
    InvalidAttrNumber,
228
    Anum_pg_database_datdba,
229
    Anum_pg_database_datacl,
230
    OBJECT_DATABASE,
231
    true
232
  },
233
  {
234
    "default ACL",
235
    DefaultAclRelationId,
236
    DefaultAclOidIndexId,
237
    SYSCACHEID_INVALID,
238
    SYSCACHEID_INVALID,
239
    Anum_pg_default_acl_oid,
240
    InvalidAttrNumber,
241
    InvalidAttrNumber,
242
    InvalidAttrNumber,
243
    InvalidAttrNumber,
244
    OBJECT_DEFACL,
245
    false
246
  },
247
  {
248
    "extension",
249
    ExtensionRelationId,
250
    ExtensionOidIndexId,
251
    SYSCACHEID_INVALID,
252
    SYSCACHEID_INVALID,
253
    Anum_pg_extension_oid,
254
    Anum_pg_extension_extname,
255
    InvalidAttrNumber,    /* extension doesn't belong to extnamespace */
256
    Anum_pg_extension_extowner,
257
    InvalidAttrNumber,
258
    OBJECT_EXTENSION,
259
    true
260
  },
261
  {
262
    "foreign-data wrapper",
263
    ForeignDataWrapperRelationId,
264
    ForeignDataWrapperOidIndexId,
265
    FOREIGNDATAWRAPPEROID,
266
    FOREIGNDATAWRAPPERNAME,
267
    Anum_pg_foreign_data_wrapper_oid,
268
    Anum_pg_foreign_data_wrapper_fdwname,
269
    InvalidAttrNumber,
270
    Anum_pg_foreign_data_wrapper_fdwowner,
271
    Anum_pg_foreign_data_wrapper_fdwacl,
272
    OBJECT_FDW,
273
    true
274
  },
275
  {
276
    "foreign server",
277
    ForeignServerRelationId,
278
    ForeignServerOidIndexId,
279
    FOREIGNSERVEROID,
280
    FOREIGNSERVERNAME,
281
    Anum_pg_foreign_server_oid,
282
    Anum_pg_foreign_server_srvname,
283
    InvalidAttrNumber,
284
    Anum_pg_foreign_server_srvowner,
285
    Anum_pg_foreign_server_srvacl,
286
    OBJECT_FOREIGN_SERVER,
287
    true
288
  },
289
  {
290
    "function",
291
    ProcedureRelationId,
292
    ProcedureOidIndexId,
293
    PROCOID,
294
    SYSCACHEID_INVALID,   /* PROCNAMEARGSNSP also takes argument types */
295
    Anum_pg_proc_oid,
296
    Anum_pg_proc_proname,
297
    Anum_pg_proc_pronamespace,
298
    Anum_pg_proc_proowner,
299
    Anum_pg_proc_proacl,
300
    OBJECT_FUNCTION,
301
    false
302
  },
303
  {
304
    "language",
305
    LanguageRelationId,
306
    LanguageOidIndexId,
307
    LANGOID,
308
    LANGNAME,
309
    Anum_pg_language_oid,
310
    Anum_pg_language_lanname,
311
    InvalidAttrNumber,
312
    Anum_pg_language_lanowner,
313
    Anum_pg_language_lanacl,
314
    OBJECT_LANGUAGE,
315
    true
316
  },
317
  {
318
    "large object metadata",
319
    LargeObjectMetadataRelationId,
320
    LargeObjectMetadataOidIndexId,
321
    SYSCACHEID_INVALID,
322
    SYSCACHEID_INVALID,
323
    Anum_pg_largeobject_metadata_oid,
324
    InvalidAttrNumber,
325
    InvalidAttrNumber,
326
    Anum_pg_largeobject_metadata_lomowner,
327
    Anum_pg_largeobject_metadata_lomacl,
328
    OBJECT_LARGEOBJECT,
329
    false
330
  },
331
  {
332
    "operator class",
333
    OperatorClassRelationId,
334
    OpclassOidIndexId,
335
    CLAOID,
336
    SYSCACHEID_INVALID,   /* CLAAMNAMENSP also takes opcmethod */
337
    Anum_pg_opclass_oid,
338
    Anum_pg_opclass_opcname,
339
    Anum_pg_opclass_opcnamespace,
340
    Anum_pg_opclass_opcowner,
341
    InvalidAttrNumber,
342
    OBJECT_OPCLASS,
343
    true
344
  },
345
  {
346
    "operator",
347
    OperatorRelationId,
348
    OperatorOidIndexId,
349
    OPEROID,
350
    SYSCACHEID_INVALID,   /* OPERNAMENSP also takes left and right type */
351
    Anum_pg_operator_oid,
352
    Anum_pg_operator_oprname,
353
    Anum_pg_operator_oprnamespace,
354
    Anum_pg_operator_oprowner,
355
    InvalidAttrNumber,
356
    OBJECT_OPERATOR,
357
    false
358
  },
359
  {
360
    "operator family",
361
    OperatorFamilyRelationId,
362
    OpfamilyOidIndexId,
363
    OPFAMILYOID,
364
    SYSCACHEID_INVALID,   /* OPFAMILYAMNAMENSP also takes opfmethod */
365
    Anum_pg_opfamily_oid,
366
    Anum_pg_opfamily_opfname,
367
    Anum_pg_opfamily_opfnamespace,
368
    Anum_pg_opfamily_opfowner,
369
    InvalidAttrNumber,
370
    OBJECT_OPFAMILY,
371
    true
372
  },
373
  {
374
    "role",
375
    AuthIdRelationId,
376
    AuthIdOidIndexId,
377
    AUTHOID,
378
    AUTHNAME,
379
    Anum_pg_authid_oid,
380
    Anum_pg_authid_rolname,
381
    InvalidAttrNumber,
382
    InvalidAttrNumber,
383
    InvalidAttrNumber,
384
    OBJECT_ROLE,
385
    true
386
  },
387
  {
388
    "role membership",
389
    AuthMemRelationId,
390
    AuthMemOidIndexId,
391
    SYSCACHEID_INVALID,
392
    SYSCACHEID_INVALID,
393
    Anum_pg_auth_members_oid,
394
    InvalidAttrNumber,
395
    InvalidAttrNumber,
396
    Anum_pg_auth_members_grantor,
397
    InvalidAttrNumber,
398
    -1,
399
    true
400
  },
401
  {
402
    "rule",
403
    RewriteRelationId,
404
    RewriteOidIndexId,
405
    SYSCACHEID_INVALID,
406
    SYSCACHEID_INVALID,
407
    Anum_pg_rewrite_oid,
408
    Anum_pg_rewrite_rulename,
409
    InvalidAttrNumber,
410
    InvalidAttrNumber,
411
    InvalidAttrNumber,
412
    OBJECT_RULE,
413
    false
414
  },
415
  {
416
    "schema",
417
    NamespaceRelationId,
418
    NamespaceOidIndexId,
419
    NAMESPACEOID,
420
    NAMESPACENAME,
421
    Anum_pg_namespace_oid,
422
    Anum_pg_namespace_nspname,
423
    InvalidAttrNumber,
424
    Anum_pg_namespace_nspowner,
425
    Anum_pg_namespace_nspacl,
426
    OBJECT_SCHEMA,
427
    true
428
  },
429
  {
430
    "relation",
431
    RelationRelationId,
432
    ClassOidIndexId,
433
    RELOID,
434
    RELNAMENSP,
435
    Anum_pg_class_oid,
436
    Anum_pg_class_relname,
437
    Anum_pg_class_relnamespace,
438
    Anum_pg_class_relowner,
439
    Anum_pg_class_relacl,
440
    OBJECT_TABLE,
441
    true
442
  },
443
  {
444
    "tablespace",
445
    TableSpaceRelationId,
446
    TablespaceOidIndexId,
447
    TABLESPACEOID,
448
    SYSCACHEID_INVALID,
449
    Anum_pg_tablespace_oid,
450
    Anum_pg_tablespace_spcname,
451
    InvalidAttrNumber,
452
    Anum_pg_tablespace_spcowner,
453
    Anum_pg_tablespace_spcacl,
454
    OBJECT_TABLESPACE,
455
    true
456
  },
457
  {
458
    "transform",
459
    TransformRelationId,
460
    TransformOidIndexId,
461
    TRFOID,
462
    SYSCACHEID_INVALID,
463
    Anum_pg_transform_oid,
464
    InvalidAttrNumber,
465
    InvalidAttrNumber,
466
    InvalidAttrNumber,
467
    InvalidAttrNumber,
468
    OBJECT_TRANSFORM,
469
    false
470
  },
471
  {
472
    "trigger",
473
    TriggerRelationId,
474
    TriggerOidIndexId,
475
    SYSCACHEID_INVALID,
476
    SYSCACHEID_INVALID,
477
    Anum_pg_trigger_oid,
478
    Anum_pg_trigger_tgname,
479
    InvalidAttrNumber,
480
    InvalidAttrNumber,
481
    InvalidAttrNumber,
482
    OBJECT_TRIGGER,
483
    false
484
  },
485
  {
486
    "policy",
487
    PolicyRelationId,
488
    PolicyOidIndexId,
489
    SYSCACHEID_INVALID,
490
    SYSCACHEID_INVALID,
491
    Anum_pg_policy_oid,
492
    Anum_pg_policy_polname,
493
    InvalidAttrNumber,
494
    InvalidAttrNumber,
495
    InvalidAttrNumber,
496
    OBJECT_POLICY,
497
    false
498
  },
499
  {
500
    "event trigger",
501
    EventTriggerRelationId,
502
    EventTriggerOidIndexId,
503
    EVENTTRIGGEROID,
504
    EVENTTRIGGERNAME,
505
    Anum_pg_event_trigger_oid,
506
    Anum_pg_event_trigger_evtname,
507
    InvalidAttrNumber,
508
    Anum_pg_event_trigger_evtowner,
509
    InvalidAttrNumber,
510
    OBJECT_EVENT_TRIGGER,
511
    true
512
  },
513
  {
514
    "text search configuration",
515
    TSConfigRelationId,
516
    TSConfigOidIndexId,
517
    TSCONFIGOID,
518
    TSCONFIGNAMENSP,
519
    Anum_pg_ts_config_oid,
520
    Anum_pg_ts_config_cfgname,
521
    Anum_pg_ts_config_cfgnamespace,
522
    Anum_pg_ts_config_cfgowner,
523
    InvalidAttrNumber,
524
    OBJECT_TSCONFIGURATION,
525
    true
526
  },
527
  {
528
    "text search dictionary",
529
    TSDictionaryRelationId,
530
    TSDictionaryOidIndexId,
531
    TSDICTOID,
532
    TSDICTNAMENSP,
533
    Anum_pg_ts_dict_oid,
534
    Anum_pg_ts_dict_dictname,
535
    Anum_pg_ts_dict_dictnamespace,
536
    Anum_pg_ts_dict_dictowner,
537
    InvalidAttrNumber,
538
    OBJECT_TSDICTIONARY,
539
    true
540
  },
541
  {
542
    "text search parser",
543
    TSParserRelationId,
544
    TSParserOidIndexId,
545
    TSPARSEROID,
546
    TSPARSERNAMENSP,
547
    Anum_pg_ts_parser_oid,
548
    Anum_pg_ts_parser_prsname,
549
    Anum_pg_ts_parser_prsnamespace,
550
    InvalidAttrNumber,
551
    InvalidAttrNumber,
552
    OBJECT_TSPARSER,
553
    true
554
  },
555
  {
556
    "text search template",
557
    TSTemplateRelationId,
558
    TSTemplateOidIndexId,
559
    TSTEMPLATEOID,
560
    TSTEMPLATENAMENSP,
561
    Anum_pg_ts_template_oid,
562
    Anum_pg_ts_template_tmplname,
563
    Anum_pg_ts_template_tmplnamespace,
564
    InvalidAttrNumber,
565
    InvalidAttrNumber,
566
    OBJECT_TSTEMPLATE,
567
    true,
568
  },
569
  {
570
    "type",
571
    TypeRelationId,
572
    TypeOidIndexId,
573
    TYPEOID,
574
    TYPENAMENSP,
575
    Anum_pg_type_oid,
576
    Anum_pg_type_typname,
577
    Anum_pg_type_typnamespace,
578
    Anum_pg_type_typowner,
579
    Anum_pg_type_typacl,
580
    OBJECT_TYPE,
581
    true
582
  },
583
  {
584
    "publication",
585
    PublicationRelationId,
586
    PublicationObjectIndexId,
587
    PUBLICATIONOID,
588
    PUBLICATIONNAME,
589
    Anum_pg_publication_oid,
590
    Anum_pg_publication_pubname,
591
    InvalidAttrNumber,
592
    Anum_pg_publication_pubowner,
593
    InvalidAttrNumber,
594
    OBJECT_PUBLICATION,
595
    true
596
  },
597
  {
598
    "subscription",
599
    SubscriptionRelationId,
600
    SubscriptionObjectIndexId,
601
    SUBSCRIPTIONOID,
602
    SUBSCRIPTIONNAME,
603
    Anum_pg_subscription_oid,
604
    Anum_pg_subscription_subname,
605
    InvalidAttrNumber,
606
    Anum_pg_subscription_subowner,
607
    InvalidAttrNumber,
608
    OBJECT_SUBSCRIPTION,
609
    true
610
  },
611
  {
612
    "extended statistics",
613
    StatisticExtRelationId,
614
    StatisticExtOidIndexId,
615
    STATEXTOID,
616
    STATEXTNAMENSP,
617
    Anum_pg_statistic_ext_oid,
618
    Anum_pg_statistic_ext_stxname,
619
    Anum_pg_statistic_ext_stxnamespace,
620
    Anum_pg_statistic_ext_stxowner,
621
    InvalidAttrNumber,    /* no ACL (same as relation) */
622
    OBJECT_STATISTIC_EXT,
623
    true
624
  },
625
  {
626
    "user mapping",
627
    UserMappingRelationId,
628
    UserMappingOidIndexId,
629
    USERMAPPINGOID,
630
    SYSCACHEID_INVALID,
631
    Anum_pg_user_mapping_oid,
632
    InvalidAttrNumber,
633
    InvalidAttrNumber,
634
    InvalidAttrNumber,
635
    InvalidAttrNumber,
636
    OBJECT_USER_MAPPING,
637
    false
638
  },
639
};
640
641
/*
642
 * This struct maps the string object types as returned by
643
 * getObjectTypeDescription into ObjectType enum values.  Note that some enum
644
 * values can be obtained by different names, and that some string object types
645
 * do not have corresponding values in the output enum.  The user of this map
646
 * must be careful to test for invalid values being returned.
647
 *
648
 * To ease maintenance, this follows the order of getObjectTypeDescription.
649
 */
650
static const struct object_type_map
651
{
652
  const char *tm_name;
653
  ObjectType  tm_type;
654
}
655
656
      ObjectTypeMap[] =
657
{
658
  {
659
    "table", OBJECT_TABLE
660
  },
661
  {
662
    "index", OBJECT_INDEX
663
  },
664
  {
665
    "sequence", OBJECT_SEQUENCE
666
  },
667
  {
668
    "toast table", -1
669
  },              /* unmapped */
670
  {
671
    "view", OBJECT_VIEW
672
  },
673
  {
674
    "materialized view", OBJECT_MATVIEW
675
  },
676
  {
677
    "composite type", -1
678
  },              /* unmapped */
679
  {
680
    "foreign table", OBJECT_FOREIGN_TABLE
681
  },
682
  {
683
    "table column", OBJECT_COLUMN
684
  },
685
  {
686
    "index column", -1
687
  },              /* unmapped */
688
  {
689
    "sequence column", -1
690
  },              /* unmapped */
691
  {
692
    "toast table column", -1
693
  },              /* unmapped */
694
  {
695
    "view column", -1
696
  },              /* unmapped */
697
  {
698
    "materialized view column", -1
699
  },              /* unmapped */
700
  {
701
    "composite type column", -1
702
  },              /* unmapped */
703
  {
704
    "foreign table column", OBJECT_COLUMN
705
  },
706
  {
707
    "aggregate", OBJECT_AGGREGATE
708
  },
709
  {
710
    "function", OBJECT_FUNCTION
711
  },
712
  {
713
    "procedure", OBJECT_PROCEDURE
714
  },
715
  {
716
    "type", OBJECT_TYPE
717
  },
718
  {
719
    "cast", OBJECT_CAST
720
  },
721
  {
722
    "collation", OBJECT_COLLATION
723
  },
724
  {
725
    "table constraint", OBJECT_TABCONSTRAINT
726
  },
727
  {
728
    "domain constraint", OBJECT_DOMCONSTRAINT
729
  },
730
  {
731
    "conversion", OBJECT_CONVERSION
732
  },
733
  {
734
    "default value", OBJECT_DEFAULT
735
  },
736
  {
737
    "language", OBJECT_LANGUAGE
738
  },
739
  {
740
    "large object", OBJECT_LARGEOBJECT
741
  },
742
  {
743
    "operator", OBJECT_OPERATOR
744
  },
745
  {
746
    "operator class", OBJECT_OPCLASS
747
  },
748
  {
749
    "operator family", OBJECT_OPFAMILY
750
  },
751
  {
752
    "access method", OBJECT_ACCESS_METHOD
753
  },
754
  {
755
    "operator of access method", OBJECT_AMOP
756
  },
757
  {
758
    "function of access method", OBJECT_AMPROC
759
  },
760
  {
761
    "rule", OBJECT_RULE
762
  },
763
  {
764
    "trigger", OBJECT_TRIGGER
765
  },
766
  {
767
    "schema", OBJECT_SCHEMA
768
  },
769
  {
770
    "text search parser", OBJECT_TSPARSER
771
  },
772
  {
773
    "text search dictionary", OBJECT_TSDICTIONARY
774
  },
775
  {
776
    "text search template", OBJECT_TSTEMPLATE
777
  },
778
  {
779
    "text search configuration", OBJECT_TSCONFIGURATION
780
  },
781
  {
782
    "role", OBJECT_ROLE
783
  },
784
  {
785
    "role membership", -1 /* unmapped */
786
  },
787
  {
788
    "database", OBJECT_DATABASE
789
  },
790
  {
791
    "tablespace", OBJECT_TABLESPACE
792
  },
793
  {
794
    "foreign-data wrapper", OBJECT_FDW
795
  },
796
  {
797
    "server", OBJECT_FOREIGN_SERVER
798
  },
799
  {
800
    "user mapping", OBJECT_USER_MAPPING
801
  },
802
  {
803
    "default acl", OBJECT_DEFACL
804
  },
805
  {
806
    "extension", OBJECT_EXTENSION
807
  },
808
  {
809
    "event trigger", OBJECT_EVENT_TRIGGER
810
  },
811
  {
812
    "parameter ACL", OBJECT_PARAMETER_ACL
813
  },
814
  {
815
    "policy", OBJECT_POLICY
816
  },
817
  {
818
    "publication", OBJECT_PUBLICATION
819
  },
820
  {
821
    "publication namespace", OBJECT_PUBLICATION_NAMESPACE
822
  },
823
  {
824
    "publication relation", OBJECT_PUBLICATION_REL
825
  },
826
  {
827
    "publication excluded relation", OBJECT_PUBLICATION_EXCLUDED_REL
828
  },
829
  {
830
    "subscription", OBJECT_SUBSCRIPTION
831
  },
832
  {
833
    "transform", OBJECT_TRANSFORM
834
  },
835
  {
836
    "statistics object", OBJECT_STATISTIC_EXT
837
  }
838
};
839
840
const ObjectAddress InvalidObjectAddress =
841
{
842
  InvalidOid,
843
  InvalidOid,
844
  0
845
};
846
847
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
848
                          String *strval, bool missing_ok);
849
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
850
                          List *object, Relation *relp,
851
                          LOCKMODE lockmode, bool missing_ok);
852
static ObjectAddress get_object_address_relobject(ObjectType objtype,
853
                          List *object, Relation *relp, bool missing_ok);
854
static ObjectAddress get_object_address_attribute(ObjectType objtype,
855
                          List *object, Relation *relp,
856
                          LOCKMODE lockmode, bool missing_ok);
857
static ObjectAddress get_object_address_attrdef(ObjectType objtype,
858
                        List *object, Relation *relp, LOCKMODE lockmode,
859
                        bool missing_ok);
860
static ObjectAddress get_object_address_type(ObjectType objtype,
861
                       TypeName *typename, bool missing_ok);
862
static ObjectAddress get_object_address_opcf(ObjectType objtype, List *object,
863
                       bool missing_ok);
864
static ObjectAddress get_object_address_opf_member(ObjectType objtype,
865
                           List *object, bool missing_ok);
866
867
static ObjectAddress get_object_address_usermapping(List *object,
868
                          bool missing_ok);
869
static ObjectAddress get_object_address_publication_rel(ObjectType objtype,
870
                            List *object,
871
                            Relation *relp,
872
                            bool missing_ok);
873
static ObjectAddress get_object_address_publication_schema(List *object,
874
                               bool missing_ok);
875
static ObjectAddress get_object_address_defacl(List *object,
876
                         bool missing_ok);
877
static const ObjectPropertyType *get_object_property_data(Oid class_id);
878
879
static void getRelationDescription(StringInfo buffer, Oid relid,
880
                   bool missing_ok);
881
static void getOpFamilyDescription(StringInfo buffer, Oid opfid,
882
                   bool missing_ok);
883
static void getRelationTypeDescription(StringInfo buffer, Oid relid,
884
                     int32 objectSubId, bool missing_ok);
885
static void getProcedureTypeDescription(StringInfo buffer, Oid procid,
886
                    bool missing_ok);
887
static void getPublicationRelationTypeDescription(StringInfo buffer,
888
                          Oid pubreloid,
889
                          bool missing_ok);
890
static void getConstraintTypeDescription(StringInfo buffer, Oid constroid,
891
                     bool missing_ok);
892
static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
893
                bool missing_ok);
894
static void getRelationIdentity(StringInfo buffer, Oid relid, List **object,
895
                bool missing_ok);
896
897
/*
898
 * Translate an object name and arguments (as passed by the parser) to an
899
 * ObjectAddress.
900
 *
901
 * The returned object will be locked using the specified lockmode.  If a
902
 * sub-object is looked up, the parent object will be locked instead.
903
 *
904
 * If the object is a relation or a child object of a relation (e.g. an
905
 * attribute or constraint), the relation is also opened and *relp receives
906
 * the open relcache entry pointer; otherwise, *relp is set to NULL.
907
 * (relp can be NULL if the caller never passes a relation-related object.)  This
908
 * is a bit grotty but it makes life simpler, since the caller will
909
 * typically need the relcache entry too.  Caller must close the relcache
910
 * entry when done with it.  The relation is locked with the specified lockmode
911
 * if the target object is the relation itself or an attribute, but for other
912
 * child objects, only AccessShareLock is acquired on the relation.
913
 *
914
 * If the object is not found, an error is thrown, unless missing_ok is
915
 * true.  In this case, no lock is acquired, relp is set to NULL, and the
916
 * returned address has objectId set to InvalidOid.
917
 *
918
 * We don't currently provide a function to release the locks acquired here;
919
 * typically, the lock must be held until commit to guard against a concurrent
920
 * drop operation.
921
 *
922
 * Note: If the object is not found, we don't give any indication of the
923
 * reason.  (It might have been a missing schema if the name was qualified, or
924
 * a nonexistent type name in case of a cast, function or operator; etc).
925
 * Currently there is only one caller that might be interested in such info, so
926
 * we don't spend much effort here.  If more callers start to care, it might be
927
 * better to add some support for that in this function.
928
 */
929
ObjectAddress
930
get_object_address(ObjectType objtype, Node *object,
931
           Relation *relp, LOCKMODE lockmode, bool missing_ok)
932
0
{
933
0
  ObjectAddress address = {InvalidOid, InvalidOid, 0};
934
0
  ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
935
0
  Relation  relation = NULL;
936
0
  uint64    inval_count;
937
938
  /* Some kind of lock must be taken. */
939
0
  Assert(lockmode != NoLock);
940
941
0
  for (;;)
942
0
  {
943
    /*
944
     * Remember this value, so that, after looking up the object name and
945
     * locking it, we can check whether any invalidation messages have
946
     * been processed that might require a do-over.
947
     */
948
0
    inval_count = SharedInvalidMessageCounter;
949
950
    /* Look up object address. */
951
0
    switch (objtype)
952
0
    {
953
0
      case OBJECT_INDEX:
954
0
      case OBJECT_SEQUENCE:
955
0
      case OBJECT_TABLE:
956
0
      case OBJECT_VIEW:
957
0
      case OBJECT_MATVIEW:
958
0
      case OBJECT_FOREIGN_TABLE:
959
0
        address =
960
0
          get_relation_by_qualified_name(objtype, castNode(List, object),
961
0
                           &relation, lockmode,
962
0
                           missing_ok);
963
0
        break;
964
0
      case OBJECT_ATTRIBUTE:
965
0
      case OBJECT_COLUMN:
966
0
        address =
967
0
          get_object_address_attribute(objtype, castNode(List, object),
968
0
                         &relation, lockmode,
969
0
                         missing_ok);
970
0
        break;
971
0
      case OBJECT_DEFAULT:
972
0
        address =
973
0
          get_object_address_attrdef(objtype, castNode(List, object),
974
0
                         &relation, lockmode,
975
0
                         missing_ok);
976
0
        break;
977
0
      case OBJECT_RULE:
978
0
      case OBJECT_TRIGGER:
979
0
      case OBJECT_TABCONSTRAINT:
980
0
      case OBJECT_POLICY:
981
0
        address = get_object_address_relobject(objtype, castNode(List, object),
982
0
                             &relation, missing_ok);
983
0
        break;
984
0
      case OBJECT_DOMCONSTRAINT:
985
0
        {
986
0
          List     *objlist;
987
0
          ObjectAddress domaddr;
988
0
          char     *constrname;
989
990
0
          objlist = castNode(List, object);
991
0
          domaddr = get_object_address_type(OBJECT_DOMAIN,
992
0
                            linitial_node(TypeName, objlist),
993
0
                            missing_ok);
994
0
          constrname = strVal(lsecond(objlist));
995
996
0
          address.classId = ConstraintRelationId;
997
0
          address.objectId = get_domain_constraint_oid(domaddr.objectId,
998
0
                                 constrname, missing_ok);
999
0
          address.objectSubId = 0;
1000
0
        }
1001
0
        break;
1002
0
      case OBJECT_DATABASE:
1003
0
      case OBJECT_EXTENSION:
1004
0
      case OBJECT_TABLESPACE:
1005
0
      case OBJECT_ROLE:
1006
0
      case OBJECT_SCHEMA:
1007
0
      case OBJECT_LANGUAGE:
1008
0
      case OBJECT_FDW:
1009
0
      case OBJECT_FOREIGN_SERVER:
1010
0
      case OBJECT_EVENT_TRIGGER:
1011
0
      case OBJECT_PARAMETER_ACL:
1012
0
      case OBJECT_ACCESS_METHOD:
1013
0
      case OBJECT_PUBLICATION:
1014
0
      case OBJECT_SUBSCRIPTION:
1015
0
        address = get_object_address_unqualified(objtype,
1016
0
                             castNode(String, object), missing_ok);
1017
0
        break;
1018
0
      case OBJECT_TYPE:
1019
0
      case OBJECT_DOMAIN:
1020
0
        address = get_object_address_type(objtype, castNode(TypeName, object), missing_ok);
1021
0
        break;
1022
0
      case OBJECT_AGGREGATE:
1023
0
      case OBJECT_FUNCTION:
1024
0
      case OBJECT_PROCEDURE:
1025
0
      case OBJECT_ROUTINE:
1026
0
        address.classId = ProcedureRelationId;
1027
0
        address.objectId = LookupFuncWithArgs(objtype, castNode(ObjectWithArgs, object), missing_ok);
1028
0
        address.objectSubId = 0;
1029
0
        break;
1030
0
      case OBJECT_OPERATOR:
1031
0
        address.classId = OperatorRelationId;
1032
0
        address.objectId = LookupOperWithArgs(castNode(ObjectWithArgs, object), missing_ok);
1033
0
        address.objectSubId = 0;
1034
0
        break;
1035
0
      case OBJECT_COLLATION:
1036
0
        address.classId = CollationRelationId;
1037
0
        address.objectId = get_collation_oid(castNode(List, object), missing_ok);
1038
0
        address.objectSubId = 0;
1039
0
        break;
1040
0
      case OBJECT_CONVERSION:
1041
0
        address.classId = ConversionRelationId;
1042
0
        address.objectId = get_conversion_oid(castNode(List, object), missing_ok);
1043
0
        address.objectSubId = 0;
1044
0
        break;
1045
0
      case OBJECT_OPCLASS:
1046
0
      case OBJECT_OPFAMILY:
1047
0
        address = get_object_address_opcf(objtype, castNode(List, object), missing_ok);
1048
0
        break;
1049
0
      case OBJECT_AMOP:
1050
0
      case OBJECT_AMPROC:
1051
0
        address = get_object_address_opf_member(objtype, castNode(List, object), missing_ok);
1052
0
        break;
1053
0
      case OBJECT_LARGEOBJECT:
1054
0
        address.classId = LargeObjectRelationId;
1055
0
        address.objectId = oidparse(object);
1056
0
        address.objectSubId = 0;
1057
0
        if (!LargeObjectExists(address.objectId))
1058
0
        {
1059
0
          if (!missing_ok)
1060
0
            ereport(ERROR,
1061
0
                (errcode(ERRCODE_UNDEFINED_OBJECT),
1062
0
                 errmsg("large object %u does not exist",
1063
0
                    address.objectId)));
1064
0
        }
1065
0
        break;
1066
0
      case OBJECT_CAST:
1067
0
        {
1068
0
          TypeName   *sourcetype = linitial_node(TypeName, castNode(List, object));
1069
0
          TypeName   *targettype = lsecond_node(TypeName, castNode(List, object));
1070
0
          Oid     sourcetypeid;
1071
0
          Oid     targettypeid;
1072
1073
0
          sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
1074
0
          targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
1075
0
          address.classId = CastRelationId;
1076
0
          address.objectId =
1077
0
            get_cast_oid(sourcetypeid, targettypeid, missing_ok);
1078
0
          address.objectSubId = 0;
1079
0
        }
1080
0
        break;
1081
0
      case OBJECT_TRANSFORM:
1082
0
        {
1083
0
          TypeName   *typename = linitial_node(TypeName, castNode(List, object));
1084
0
          char     *langname = strVal(lsecond(castNode(List, object)));
1085
0
          Oid     type_id = LookupTypeNameOid(NULL, typename, missing_ok);
1086
0
          Oid     lang_id = get_language_oid(langname, missing_ok);
1087
1088
0
          address.classId = TransformRelationId;
1089
0
          address.objectId =
1090
0
            get_transform_oid(type_id, lang_id, missing_ok);
1091
0
          address.objectSubId = 0;
1092
0
        }
1093
0
        break;
1094
0
      case OBJECT_TSPARSER:
1095
0
        address.classId = TSParserRelationId;
1096
0
        address.objectId = get_ts_parser_oid(castNode(List, object), missing_ok);
1097
0
        address.objectSubId = 0;
1098
0
        break;
1099
0
      case OBJECT_TSDICTIONARY:
1100
0
        address.classId = TSDictionaryRelationId;
1101
0
        address.objectId = get_ts_dict_oid(castNode(List, object), missing_ok);
1102
0
        address.objectSubId = 0;
1103
0
        break;
1104
0
      case OBJECT_TSTEMPLATE:
1105
0
        address.classId = TSTemplateRelationId;
1106
0
        address.objectId = get_ts_template_oid(castNode(List, object), missing_ok);
1107
0
        address.objectSubId = 0;
1108
0
        break;
1109
0
      case OBJECT_TSCONFIGURATION:
1110
0
        address.classId = TSConfigRelationId;
1111
0
        address.objectId = get_ts_config_oid(castNode(List, object), missing_ok);
1112
0
        address.objectSubId = 0;
1113
0
        break;
1114
0
      case OBJECT_USER_MAPPING:
1115
0
        address = get_object_address_usermapping(castNode(List, object),
1116
0
                             missing_ok);
1117
0
        break;
1118
0
      case OBJECT_PUBLICATION_NAMESPACE:
1119
0
        address = get_object_address_publication_schema(castNode(List, object),
1120
0
                                missing_ok);
1121
0
        break;
1122
0
      case OBJECT_PUBLICATION_EXCLUDED_REL:
1123
0
      case OBJECT_PUBLICATION_REL:
1124
0
        address = get_object_address_publication_rel(objtype,
1125
0
                               castNode(List, object),
1126
0
                               &relation,
1127
0
                               missing_ok);
1128
0
        break;
1129
0
      case OBJECT_DEFACL:
1130
0
        address = get_object_address_defacl(castNode(List, object),
1131
0
                          missing_ok);
1132
0
        break;
1133
0
      case OBJECT_STATISTIC_EXT:
1134
0
        address.classId = StatisticExtRelationId;
1135
0
        address.objectId = get_statistics_object_oid(castNode(List, object),
1136
0
                               missing_ok);
1137
0
        address.objectSubId = 0;
1138
0
        break;
1139
        /* no default, to let compiler warn about missing case */
1140
0
    }
1141
1142
0
    if (!address.classId)
1143
0
      elog(ERROR, "unrecognized object type: %d", (int) objtype);
1144
1145
    /*
1146
     * If we could not find the supplied object, return without locking.
1147
     */
1148
0
    if (!OidIsValid(address.objectId))
1149
0
    {
1150
0
      Assert(missing_ok);
1151
0
      return address;
1152
0
    }
1153
1154
    /*
1155
     * If we're retrying, see if we got the same answer as last time.  If
1156
     * so, we're done; if not, we locked the wrong thing, so give up our
1157
     * lock.
1158
     */
1159
0
    if (OidIsValid(old_address.classId))
1160
0
    {
1161
0
      if (old_address.classId == address.classId
1162
0
        && old_address.objectId == address.objectId
1163
0
        && old_address.objectSubId == address.objectSubId)
1164
0
        break;
1165
0
      if (old_address.classId != RelationRelationId)
1166
0
      {
1167
0
        if (IsSharedRelation(old_address.classId))
1168
0
          UnlockSharedObject(old_address.classId,
1169
0
                     old_address.objectId,
1170
0
                     0, lockmode);
1171
0
        else
1172
0
          UnlockDatabaseObject(old_address.classId,
1173
0
                     old_address.objectId,
1174
0
                     0, lockmode);
1175
0
      }
1176
0
    }
1177
1178
    /*
1179
     * If we're dealing with a relation or attribute, then the relation is
1180
     * already locked.  Otherwise, we lock it now.
1181
     */
1182
0
    if (address.classId != RelationRelationId)
1183
0
    {
1184
0
      if (IsSharedRelation(address.classId))
1185
0
        LockSharedObject(address.classId, address.objectId, 0,
1186
0
                 lockmode);
1187
0
      else
1188
0
        LockDatabaseObject(address.classId, address.objectId, 0,
1189
0
                   lockmode);
1190
0
    }
1191
1192
    /*
1193
     * At this point, we've resolved the name to an OID and locked the
1194
     * corresponding database object.  However, it's possible that by the
1195
     * time we acquire the lock on the object, concurrent DDL has modified
1196
     * the database in such a way that the name we originally looked up no
1197
     * longer resolves to that OID.
1198
     *
1199
     * We can be certain that this isn't an issue if (a) no shared
1200
     * invalidation messages have been processed or (b) we've locked a
1201
     * relation somewhere along the line.  All the relation name lookups
1202
     * in this module ultimately use RangeVarGetRelid() to acquire a
1203
     * relation lock, and that function protects against the same kinds of
1204
     * races we're worried about here.  Even when operating on a
1205
     * constraint, rule, or trigger, we still acquire AccessShareLock on
1206
     * the relation, which is enough to freeze out any concurrent DDL.
1207
     *
1208
     * In all other cases, however, it's possible that the name we looked
1209
     * up no longer refers to the object we locked, so we retry the lookup
1210
     * and see whether we get the same answer.
1211
     */
1212
0
    if (inval_count == SharedInvalidMessageCounter || relation != NULL)
1213
0
      break;
1214
0
    old_address = address;
1215
0
  }
1216
1217
  /* relp must be given if it's a relation */
1218
0
  Assert(!relation || relp);
1219
1220
  /* Return the object address and the relation. */
1221
0
  if (relp)
1222
0
    *relp = relation;
1223
0
  return address;
1224
0
}
1225
1226
/*
1227
 * Return an ObjectAddress based on a RangeVar and an object name. The
1228
 * name of the relation identified by the RangeVar is prepended to the
1229
 * (possibly empty) list passed in as object. This is useful to find
1230
 * the ObjectAddress of objects that depend on a relation. All other
1231
 * considerations are exactly as for get_object_address above.
1232
 */
1233
ObjectAddress
1234
get_object_address_rv(ObjectType objtype, RangeVar *rel, List *object,
1235
            Relation *relp, LOCKMODE lockmode,
1236
            bool missing_ok)
1237
0
{
1238
0
  if (rel)
1239
0
  {
1240
0
    object = lcons(makeString(rel->relname), object);
1241
0
    if (rel->schemaname)
1242
0
      object = lcons(makeString(rel->schemaname), object);
1243
0
    if (rel->catalogname)
1244
0
      object = lcons(makeString(rel->catalogname), object);
1245
0
  }
1246
1247
0
  return get_object_address(objtype, (Node *) object,
1248
0
                relp, lockmode, missing_ok);
1249
0
}
1250
1251
/*
1252
 * Find an ObjectAddress for a type of object that is identified by an
1253
 * unqualified name.
1254
 */
1255
static ObjectAddress
1256
get_object_address_unqualified(ObjectType objtype,
1257
                 String *strval, bool missing_ok)
1258
0
{
1259
0
  const char *name;
1260
0
  ObjectAddress address;
1261
1262
0
  name = strVal(strval);
1263
1264
  /* Translate name to OID. */
1265
0
  switch (objtype)
1266
0
  {
1267
0
    case OBJECT_ACCESS_METHOD:
1268
0
      address.classId = AccessMethodRelationId;
1269
0
      address.objectId = get_am_oid(name, missing_ok);
1270
0
      address.objectSubId = 0;
1271
0
      break;
1272
0
    case OBJECT_DATABASE:
1273
0
      address.classId = DatabaseRelationId;
1274
0
      address.objectId = get_database_oid(name, missing_ok);
1275
0
      address.objectSubId = 0;
1276
0
      break;
1277
0
    case OBJECT_EXTENSION:
1278
0
      address.classId = ExtensionRelationId;
1279
0
      address.objectId = get_extension_oid(name, missing_ok);
1280
0
      address.objectSubId = 0;
1281
0
      break;
1282
0
    case OBJECT_TABLESPACE:
1283
0
      address.classId = TableSpaceRelationId;
1284
0
      address.objectId = get_tablespace_oid(name, missing_ok);
1285
0
      address.objectSubId = 0;
1286
0
      break;
1287
0
    case OBJECT_ROLE:
1288
0
      address.classId = AuthIdRelationId;
1289
0
      address.objectId = get_role_oid(name, missing_ok);
1290
0
      address.objectSubId = 0;
1291
0
      break;
1292
0
    case OBJECT_SCHEMA:
1293
0
      address.classId = NamespaceRelationId;
1294
0
      address.objectId = get_namespace_oid(name, missing_ok);
1295
0
      address.objectSubId = 0;
1296
0
      break;
1297
0
    case OBJECT_LANGUAGE:
1298
0
      address.classId = LanguageRelationId;
1299
0
      address.objectId = get_language_oid(name, missing_ok);
1300
0
      address.objectSubId = 0;
1301
0
      break;
1302
0
    case OBJECT_FDW:
1303
0
      address.classId = ForeignDataWrapperRelationId;
1304
0
      address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
1305
0
      address.objectSubId = 0;
1306
0
      break;
1307
0
    case OBJECT_FOREIGN_SERVER:
1308
0
      address.classId = ForeignServerRelationId;
1309
0
      address.objectId = get_foreign_server_oid(name, missing_ok);
1310
0
      address.objectSubId = 0;
1311
0
      break;
1312
0
    case OBJECT_EVENT_TRIGGER:
1313
0
      address.classId = EventTriggerRelationId;
1314
0
      address.objectId = get_event_trigger_oid(name, missing_ok);
1315
0
      address.objectSubId = 0;
1316
0
      break;
1317
0
    case OBJECT_PARAMETER_ACL:
1318
0
      address.classId = ParameterAclRelationId;
1319
0
      address.objectId = ParameterAclLookup(name, missing_ok);
1320
0
      address.objectSubId = 0;
1321
0
      break;
1322
0
    case OBJECT_PUBLICATION:
1323
0
      address.classId = PublicationRelationId;
1324
0
      address.objectId = get_publication_oid(name, missing_ok);
1325
0
      address.objectSubId = 0;
1326
0
      break;
1327
0
    case OBJECT_SUBSCRIPTION:
1328
0
      address.classId = SubscriptionRelationId;
1329
0
      address.objectId = get_subscription_oid(name, missing_ok);
1330
0
      address.objectSubId = 0;
1331
0
      break;
1332
0
    default:
1333
0
      elog(ERROR, "unrecognized object type: %d", (int) objtype);
1334
      /* placate compiler, which doesn't know elog won't return */
1335
0
      address.classId = InvalidOid;
1336
0
      address.objectId = InvalidOid;
1337
0
      address.objectSubId = 0;
1338
0
  }
1339
1340
0
  return address;
1341
0
}
1342
1343
/*
1344
 * Locate a relation by qualified name.
1345
 */
1346
static ObjectAddress
1347
get_relation_by_qualified_name(ObjectType objtype, List *object,
1348
                 Relation *relp, LOCKMODE lockmode,
1349
                 bool missing_ok)
1350
0
{
1351
0
  Relation  relation;
1352
0
  ObjectAddress address;
1353
1354
0
  address.classId = RelationRelationId;
1355
0
  address.objectId = InvalidOid;
1356
0
  address.objectSubId = 0;
1357
1358
0
  relation = relation_openrv_extended(makeRangeVarFromNameList(object),
1359
0
                    lockmode, missing_ok);
1360
0
  if (!relation)
1361
0
    return address;
1362
1363
0
  switch (objtype)
1364
0
  {
1365
0
    case OBJECT_INDEX:
1366
0
      if (relation->rd_rel->relkind != RELKIND_INDEX &&
1367
0
        relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
1368
0
        ereport(ERROR,
1369
0
            (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1370
0
             errmsg("\"%s\" is not an index",
1371
0
                RelationGetRelationName(relation))));
1372
0
      break;
1373
0
    case OBJECT_SEQUENCE:
1374
0
      if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
1375
0
        ereport(ERROR,
1376
0
            (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1377
0
             errmsg("\"%s\" is not a sequence",
1378
0
                RelationGetRelationName(relation))));
1379
0
      break;
1380
0
    case OBJECT_TABLE:
1381
0
      if (relation->rd_rel->relkind != RELKIND_RELATION &&
1382
0
        relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1383
0
        ereport(ERROR,
1384
0
            (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1385
0
             errmsg("\"%s\" is not a table",
1386
0
                RelationGetRelationName(relation))));
1387
0
      break;
1388
0
    case OBJECT_VIEW:
1389
0
      if (relation->rd_rel->relkind != RELKIND_VIEW)
1390
0
        ereport(ERROR,
1391
0
            (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1392
0
             errmsg("\"%s\" is not a view",
1393
0
                RelationGetRelationName(relation))));
1394
0
      break;
1395
0
    case OBJECT_MATVIEW:
1396
0
      if (relation->rd_rel->relkind != RELKIND_MATVIEW)
1397
0
        ereport(ERROR,
1398
0
            (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1399
0
             errmsg("\"%s\" is not a materialized view",
1400
0
                RelationGetRelationName(relation))));
1401
0
      break;
1402
0
    case OBJECT_FOREIGN_TABLE:
1403
0
      if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
1404
0
        ereport(ERROR,
1405
0
            (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1406
0
             errmsg("\"%s\" is not a foreign table",
1407
0
                RelationGetRelationName(relation))));
1408
0
      break;
1409
0
    default:
1410
0
      elog(ERROR, "unrecognized object type: %d", (int) objtype);
1411
0
      break;
1412
0
  }
1413
1414
  /* Done. */
1415
0
  address.objectId = RelationGetRelid(relation);
1416
0
  *relp = relation;
1417
1418
0
  return address;
1419
0
}
1420
1421
/*
1422
 * Find object address for an object that is attached to a relation.
1423
 *
1424
 * Note that we take only an AccessShareLock on the relation.  We need not
1425
 * pass down the LOCKMODE from get_object_address(), because that is the lock
1426
 * mode for the object itself, not the relation to which it is attached.
1427
 */
1428
static ObjectAddress
1429
get_object_address_relobject(ObjectType objtype, List *object,
1430
               Relation *relp, bool missing_ok)
1431
0
{
1432
0
  ObjectAddress address;
1433
0
  Relation  relation = NULL;
1434
0
  int     nnames;
1435
0
  const char *depname;
1436
0
  List     *relname;
1437
0
  Oid     reloid;
1438
1439
  /* Extract name of dependent object. */
1440
0
  depname = strVal(llast(object));
1441
1442
  /* Separate relation name from dependent object name. */
1443
0
  nnames = list_length(object);
1444
0
  if (nnames < 2)
1445
0
    ereport(ERROR,
1446
0
        (errcode(ERRCODE_SYNTAX_ERROR),
1447
0
         errmsg("must specify relation and object name")));
1448
1449
  /* Extract relation name and open relation. */
1450
0
  relname = list_copy_head(object, nnames - 1);
1451
0
  relation = table_openrv_extended(makeRangeVarFromNameList(relname),
1452
0
                   AccessShareLock,
1453
0
                   missing_ok);
1454
1455
0
  reloid = relation ? RelationGetRelid(relation) : InvalidOid;
1456
1457
0
  switch (objtype)
1458
0
  {
1459
0
    case OBJECT_RULE:
1460
0
      address.classId = RewriteRelationId;
1461
0
      address.objectId = relation ?
1462
0
        get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
1463
0
      address.objectSubId = 0;
1464
0
      break;
1465
0
    case OBJECT_TRIGGER:
1466
0
      address.classId = TriggerRelationId;
1467
0
      address.objectId = relation ?
1468
0
        get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
1469
0
      address.objectSubId = 0;
1470
0
      break;
1471
0
    case OBJECT_TABCONSTRAINT:
1472
0
      address.classId = ConstraintRelationId;
1473
0
      address.objectId = relation ?
1474
0
        get_relation_constraint_oid(reloid, depname, missing_ok) :
1475
0
        InvalidOid;
1476
0
      address.objectSubId = 0;
1477
0
      break;
1478
0
    case OBJECT_POLICY:
1479
0
      address.classId = PolicyRelationId;
1480
0
      address.objectId = relation ?
1481
0
        get_relation_policy_oid(reloid, depname, missing_ok) :
1482
0
        InvalidOid;
1483
0
      address.objectSubId = 0;
1484
0
      break;
1485
0
    default:
1486
0
      elog(ERROR, "unrecognized object type: %d", (int) objtype);
1487
0
  }
1488
1489
  /* Avoid relcache leak when object not found. */
1490
0
  if (!OidIsValid(address.objectId))
1491
0
  {
1492
0
    if (relation != NULL)
1493
0
      table_close(relation, AccessShareLock);
1494
1495
0
    relation = NULL;   /* department of accident prevention */
1496
0
    return address;
1497
0
  }
1498
1499
  /* Done. */
1500
0
  *relp = relation;
1501
0
  return address;
1502
0
}
1503
1504
/*
1505
 * Find the ObjectAddress for an attribute.
1506
 */
1507
static ObjectAddress
1508
get_object_address_attribute(ObjectType objtype, List *object,
1509
               Relation *relp, LOCKMODE lockmode,
1510
               bool missing_ok)
1511
0
{
1512
0
  ObjectAddress address;
1513
0
  List     *relname;
1514
0
  Oid     reloid;
1515
0
  Relation  relation;
1516
0
  const char *attname;
1517
0
  AttrNumber  attnum;
1518
1519
  /* Extract relation name and open relation. */
1520
0
  if (list_length(object) < 2)
1521
0
    ereport(ERROR,
1522
0
        (errcode(ERRCODE_SYNTAX_ERROR),
1523
0
         errmsg("column name must be qualified")));
1524
0
  attname = strVal(llast(object));
1525
0
  relname = list_copy_head(object, list_length(object) - 1);
1526
  /* XXX no missing_ok support here */
1527
0
  relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1528
0
  reloid = RelationGetRelid(relation);
1529
1530
  /* Look up attribute and construct return value. */
1531
0
  attnum = get_attnum(reloid, attname);
1532
0
  if (attnum == InvalidAttrNumber)
1533
0
  {
1534
0
    if (!missing_ok)
1535
0
      ereport(ERROR,
1536
0
          (errcode(ERRCODE_UNDEFINED_COLUMN),
1537
0
           errmsg("column \"%s\" of relation \"%s\" does not exist",
1538
0
              attname, NameListToString(relname))));
1539
1540
0
    address.classId = RelationRelationId;
1541
0
    address.objectId = InvalidOid;
1542
0
    address.objectSubId = InvalidAttrNumber;
1543
0
    relation_close(relation, lockmode);
1544
0
    return address;
1545
0
  }
1546
1547
0
  address.classId = RelationRelationId;
1548
0
  address.objectId = reloid;
1549
0
  address.objectSubId = attnum;
1550
1551
0
  *relp = relation;
1552
0
  return address;
1553
0
}
1554
1555
/*
1556
 * Find the ObjectAddress for an attribute's default value.
1557
 */
1558
static ObjectAddress
1559
get_object_address_attrdef(ObjectType objtype, List *object,
1560
               Relation *relp, LOCKMODE lockmode,
1561
               bool missing_ok)
1562
0
{
1563
0
  ObjectAddress address;
1564
0
  List     *relname;
1565
0
  Oid     reloid;
1566
0
  Relation  relation;
1567
0
  const char *attname;
1568
0
  AttrNumber  attnum;
1569
0
  TupleDesc tupdesc;
1570
0
  Oid     defoid;
1571
1572
  /* Extract relation name and open relation. */
1573
0
  if (list_length(object) < 2)
1574
0
    ereport(ERROR,
1575
0
        (errcode(ERRCODE_SYNTAX_ERROR),
1576
0
         errmsg("column name must be qualified")));
1577
0
  attname = strVal(llast(object));
1578
0
  relname = list_copy_head(object, list_length(object) - 1);
1579
  /* XXX no missing_ok support here */
1580
0
  relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1581
0
  reloid = RelationGetRelid(relation);
1582
1583
0
  tupdesc = RelationGetDescr(relation);
1584
1585
  /* Look up attribute number and fetch the pg_attrdef OID */
1586
0
  attnum = get_attnum(reloid, attname);
1587
0
  defoid = InvalidOid;
1588
0
  if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
1589
0
    defoid = GetAttrDefaultOid(reloid, attnum);
1590
0
  if (!OidIsValid(defoid))
1591
0
  {
1592
0
    if (!missing_ok)
1593
0
      ereport(ERROR,
1594
0
          (errcode(ERRCODE_UNDEFINED_COLUMN),
1595
0
           errmsg("default value for column \"%s\" of relation \"%s\" does not exist",
1596
0
              attname, NameListToString(relname))));
1597
1598
0
    address.classId = AttrDefaultRelationId;
1599
0
    address.objectId = InvalidOid;
1600
0
    address.objectSubId = InvalidAttrNumber;
1601
0
    relation_close(relation, lockmode);
1602
0
    return address;
1603
0
  }
1604
1605
0
  address.classId = AttrDefaultRelationId;
1606
0
  address.objectId = defoid;
1607
0
  address.objectSubId = 0;
1608
1609
0
  *relp = relation;
1610
0
  return address;
1611
0
}
1612
1613
/*
1614
 * Find the ObjectAddress for a type or domain
1615
 */
1616
static ObjectAddress
1617
get_object_address_type(ObjectType objtype, TypeName *typename, bool missing_ok)
1618
0
{
1619
0
  ObjectAddress address;
1620
0
  Type    tup;
1621
1622
0
  address.classId = TypeRelationId;
1623
0
  address.objectId = InvalidOid;
1624
0
  address.objectSubId = 0;
1625
1626
0
  tup = LookupTypeName(NULL, typename, NULL, missing_ok);
1627
0
  if (!HeapTupleIsValid(tup))
1628
0
  {
1629
0
    if (!missing_ok)
1630
0
      ereport(ERROR,
1631
0
          (errcode(ERRCODE_UNDEFINED_OBJECT),
1632
0
           errmsg("type \"%s\" does not exist",
1633
0
              TypeNameToString(typename))));
1634
0
    return address;
1635
0
  }
1636
0
  address.objectId = typeTypeId(tup);
1637
1638
0
  if (objtype == OBJECT_DOMAIN)
1639
0
  {
1640
0
    if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
1641
0
      ereport(ERROR,
1642
0
          (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1643
0
           errmsg("\"%s\" is not a domain",
1644
0
              TypeNameToString(typename))));
1645
0
  }
1646
1647
0
  ReleaseSysCache(tup);
1648
1649
0
  return address;
1650
0
}
1651
1652
/*
1653
 * Find the ObjectAddress for an opclass or opfamily.
1654
 */
1655
static ObjectAddress
1656
get_object_address_opcf(ObjectType objtype, List *object, bool missing_ok)
1657
0
{
1658
0
  Oid     amoid;
1659
0
  ObjectAddress address;
1660
1661
  /* XXX no missing_ok support here */
1662
0
  amoid = get_index_am_oid(strVal(linitial(object)), false);
1663
0
  object = list_copy_tail(object, 1);
1664
1665
0
  switch (objtype)
1666
0
  {
1667
0
    case OBJECT_OPCLASS:
1668
0
      address.classId = OperatorClassRelationId;
1669
0
      address.objectId = get_opclass_oid(amoid, object, missing_ok);
1670
0
      address.objectSubId = 0;
1671
0
      break;
1672
0
    case OBJECT_OPFAMILY:
1673
0
      address.classId = OperatorFamilyRelationId;
1674
0
      address.objectId = get_opfamily_oid(amoid, object, missing_ok);
1675
0
      address.objectSubId = 0;
1676
0
      break;
1677
0
    default:
1678
0
      elog(ERROR, "unrecognized object type: %d", (int) objtype);
1679
      /* placate compiler, which doesn't know elog won't return */
1680
0
      address.classId = InvalidOid;
1681
0
      address.objectId = InvalidOid;
1682
0
      address.objectSubId = 0;
1683
0
  }
1684
1685
0
  return address;
1686
0
}
1687
1688
/*
1689
 * Find the ObjectAddress for an opclass/opfamily member.
1690
 *
1691
 * (The returned address corresponds to a pg_amop/pg_amproc object).
1692
 */
1693
static ObjectAddress
1694
get_object_address_opf_member(ObjectType objtype,
1695
                List *object, bool missing_ok)
1696
0
{
1697
0
  ObjectAddress famaddr;
1698
0
  ObjectAddress address;
1699
0
  ListCell   *cell;
1700
0
  List     *copy;
1701
0
  TypeName   *typenames[2];
1702
0
  Oid     typeoids[2];
1703
0
  int     membernum;
1704
0
  int     i;
1705
1706
  /*
1707
   * The last element of the object list contains the strategy or procedure
1708
   * number.  We need to strip that out before getting the opclass/family
1709
   * address.  The rest can be used directly by get_object_address_opcf().
1710
   */
1711
0
  membernum = atoi(strVal(llast(linitial(object))));
1712
0
  copy = list_copy_head(linitial(object), list_length(linitial(object)) - 1);
1713
1714
  /* no missing_ok support here */
1715
0
  famaddr = get_object_address_opcf(OBJECT_OPFAMILY, copy, false);
1716
1717
  /* find out left/right type names and OIDs */
1718
0
  typenames[0] = typenames[1] = NULL;
1719
0
  typeoids[0] = typeoids[1] = InvalidOid;
1720
0
  i = 0;
1721
0
  foreach(cell, lsecond(object))
1722
0
  {
1723
0
    ObjectAddress typaddr;
1724
1725
0
    typenames[i] = lfirst_node(TypeName, cell);
1726
0
    typaddr = get_object_address_type(OBJECT_TYPE, typenames[i], missing_ok);
1727
0
    typeoids[i] = typaddr.objectId;
1728
0
    if (++i >= 2)
1729
0
      break;
1730
0
  }
1731
1732
0
  switch (objtype)
1733
0
  {
1734
0
    case OBJECT_AMOP:
1735
0
      {
1736
0
        HeapTuple tp;
1737
1738
0
        ObjectAddressSet(address, AccessMethodOperatorRelationId,
1739
0
                 InvalidOid);
1740
1741
0
        tp = SearchSysCache4(AMOPSTRATEGY,
1742
0
                   ObjectIdGetDatum(famaddr.objectId),
1743
0
                   ObjectIdGetDatum(typeoids[0]),
1744
0
                   ObjectIdGetDatum(typeoids[1]),
1745
0
                   Int16GetDatum(membernum));
1746
0
        if (!HeapTupleIsValid(tp))
1747
0
        {
1748
0
          if (!missing_ok)
1749
0
            ereport(ERROR,
1750
0
                (errcode(ERRCODE_UNDEFINED_OBJECT),
1751
0
                 errmsg("operator %d (%s, %s) of %s does not exist",
1752
0
                    membernum,
1753
0
                    TypeNameToString(typenames[0]),
1754
0
                    TypeNameToString(typenames[1]),
1755
0
                    getObjectDescription(&famaddr, false))));
1756
0
        }
1757
0
        else
1758
0
        {
1759
0
          address.objectId = ((Form_pg_amop) GETSTRUCT(tp))->oid;
1760
0
          ReleaseSysCache(tp);
1761
0
        }
1762
0
      }
1763
0
      break;
1764
1765
0
    case OBJECT_AMPROC:
1766
0
      {
1767
0
        HeapTuple tp;
1768
1769
0
        ObjectAddressSet(address, AccessMethodProcedureRelationId,
1770
0
                 InvalidOid);
1771
1772
0
        tp = SearchSysCache4(AMPROCNUM,
1773
0
                   ObjectIdGetDatum(famaddr.objectId),
1774
0
                   ObjectIdGetDatum(typeoids[0]),
1775
0
                   ObjectIdGetDatum(typeoids[1]),
1776
0
                   Int16GetDatum(membernum));
1777
0
        if (!HeapTupleIsValid(tp))
1778
0
        {
1779
0
          if (!missing_ok)
1780
0
            ereport(ERROR,
1781
0
                (errcode(ERRCODE_UNDEFINED_OBJECT),
1782
0
                 errmsg("function %d (%s, %s) of %s does not exist",
1783
0
                    membernum,
1784
0
                    TypeNameToString(typenames[0]),
1785
0
                    TypeNameToString(typenames[1]),
1786
0
                    getObjectDescription(&famaddr, false))));
1787
0
        }
1788
0
        else
1789
0
        {
1790
0
          address.objectId = ((Form_pg_amproc) GETSTRUCT(tp))->oid;
1791
0
          ReleaseSysCache(tp);
1792
0
        }
1793
0
      }
1794
0
      break;
1795
0
    default:
1796
0
      elog(ERROR, "unrecognized object type: %d", (int) objtype);
1797
0
  }
1798
1799
0
  return address;
1800
0
}
1801
1802
/*
1803
 * Find the ObjectAddress for a user mapping.
1804
 */
1805
static ObjectAddress
1806
get_object_address_usermapping(List *object, bool missing_ok)
1807
0
{
1808
0
  ObjectAddress address;
1809
0
  Oid     userid;
1810
0
  char     *username;
1811
0
  char     *servername;
1812
0
  ForeignServer *server;
1813
0
  HeapTuple tp;
1814
1815
0
  ObjectAddressSet(address, UserMappingRelationId, InvalidOid);
1816
1817
  /* fetch string names from input lists, for error messages */
1818
0
  username = strVal(linitial(object));
1819
0
  servername = strVal(lsecond(object));
1820
1821
  /* look up pg_authid OID of mapped user; InvalidOid if PUBLIC */
1822
0
  if (strcmp(username, "public") == 0)
1823
0
    userid = InvalidOid;
1824
0
  else
1825
0
  {
1826
0
    tp = SearchSysCache1(AUTHNAME,
1827
0
               CStringGetDatum(username));
1828
0
    if (!HeapTupleIsValid(tp))
1829
0
    {
1830
0
      if (!missing_ok)
1831
0
        ereport(ERROR,
1832
0
            (errcode(ERRCODE_UNDEFINED_OBJECT),
1833
0
             errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1834
0
                username, servername)));
1835
0
      return address;
1836
0
    }
1837
0
    userid = ((Form_pg_authid) GETSTRUCT(tp))->oid;
1838
0
    ReleaseSysCache(tp);
1839
0
  }
1840
1841
  /* Now look up the pg_user_mapping tuple */
1842
0
  server = GetForeignServerByName(servername, true);
1843
0
  if (!server)
1844
0
  {
1845
0
    if (!missing_ok)
1846
0
      ereport(ERROR,
1847
0
          (errcode(ERRCODE_UNDEFINED_OBJECT),
1848
0
           errmsg("server \"%s\" does not exist", servername)));
1849
0
    return address;
1850
0
  }
1851
0
  tp = SearchSysCache2(USERMAPPINGUSERSERVER,
1852
0
             ObjectIdGetDatum(userid),
1853
0
             ObjectIdGetDatum(server->serverid));
1854
0
  if (!HeapTupleIsValid(tp))
1855
0
  {
1856
0
    if (!missing_ok)
1857
0
      ereport(ERROR,
1858
0
          (errcode(ERRCODE_UNDEFINED_OBJECT),
1859
0
           errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1860
0
              username, servername)));
1861
0
    return address;
1862
0
  }
1863
1864
0
  address.objectId = ((Form_pg_user_mapping) GETSTRUCT(tp))->oid;
1865
1866
0
  ReleaseSysCache(tp);
1867
1868
0
  return address;
1869
0
}
1870
1871
/*
1872
 * Find the ObjectAddress for a published or excluded publication relation.
1873
 * The first element of the object parameter is the relation name, the second
1874
 * is the publication name.
1875
 */
1876
static ObjectAddress
1877
get_object_address_publication_rel(ObjectType objtype, List *object,
1878
                   Relation *relp, bool missing_ok)
1879
0
{
1880
0
  ObjectAddress address;
1881
0
  Relation  relation;
1882
0
  List     *relname;
1883
0
  char     *pubname;
1884
0
  Publication *pub;
1885
0
  Form_pg_publication_rel prform;
1886
0
  HeapTuple tup;
1887
0
  bool    isexcept;
1888
1889
0
  Assert(objtype == OBJECT_PUBLICATION_REL ||
1890
0
       objtype == OBJECT_PUBLICATION_EXCLUDED_REL);
1891
1892
0
  ObjectAddressSet(address, PublicationRelRelationId, InvalidOid);
1893
1894
0
  relname = linitial(object);
1895
0
  relation = relation_openrv_extended(makeRangeVarFromNameList(relname),
1896
0
                    AccessShareLock, missing_ok);
1897
0
  if (!relation)
1898
0
    return address;
1899
1900
  /* fetch publication name from input list */
1901
0
  pubname = strVal(lsecond(object));
1902
1903
  /* Now look up the pg_publication tuple */
1904
0
  pub = GetPublicationByName(pubname, missing_ok);
1905
0
  if (!pub)
1906
0
  {
1907
0
    relation_close(relation, AccessShareLock);
1908
0
    return address;
1909
0
  }
1910
1911
  /*
1912
   * Find the publication relation mapping in syscache.  Fetch the tuple
1913
   * rather than just its OID, so that prexcept can be checked without a
1914
   * second lookup.
1915
   */
1916
0
  tup = SearchSysCache2(PUBLICATIONRELMAP,
1917
0
              ObjectIdGetDatum(RelationGetRelid(relation)),
1918
0
              ObjectIdGetDatum(pub->oid));
1919
0
  if (!HeapTupleIsValid(tup))
1920
0
  {
1921
0
    if (!missing_ok)
1922
0
    {
1923
0
      if (objtype == OBJECT_PUBLICATION_EXCLUDED_REL)
1924
0
        ereport(ERROR,
1925
0
            (errcode(ERRCODE_UNDEFINED_OBJECT),
1926
0
             errmsg("publication excluded relation \"%s\" in publication \"%s\" does not exist",
1927
0
                RelationGetRelationName(relation), pubname)));
1928
0
      else
1929
0
        ereport(ERROR,
1930
0
            (errcode(ERRCODE_UNDEFINED_OBJECT),
1931
0
             errmsg("publication relation \"%s\" in publication \"%s\" does not exist",
1932
0
                RelationGetRelationName(relation), pubname)));
1933
0
    }
1934
0
    relation_close(relation, AccessShareLock);
1935
0
    return address;
1936
0
  }
1937
1938
0
  prform = (Form_pg_publication_rel) GETSTRUCT(tup);
1939
0
  address.objectId = prform->oid;
1940
0
  isexcept = prform->prexcept;
1941
0
  ReleaseSysCache(tup);
1942
1943
  /*
1944
   * The same relation and publication pair identifies either a published or
1945
   * an excluded relation, so reject an entry of the kind that was not asked
1946
   * for.
1947
   */
1948
0
  if (objtype == OBJECT_PUBLICATION_EXCLUDED_REL && !isexcept)
1949
0
    ereport(ERROR,
1950
0
        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1951
0
         errmsg("\"%s\" is not an excluded relation of publication \"%s\"",
1952
0
            RelationGetRelationName(relation), pubname)));
1953
0
  else if (objtype == OBJECT_PUBLICATION_REL && isexcept)
1954
0
    ereport(ERROR,
1955
0
        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1956
0
         errmsg("\"%s\" is not a published relation of publication \"%s\"",
1957
0
            RelationGetRelationName(relation), pubname)));
1958
1959
0
  *relp = relation;
1960
0
  return address;
1961
0
}
1962
1963
/*
1964
 * Find the ObjectAddress for a publication schema. The first element of the
1965
 * object parameter is the schema name, the second is the publication name.
1966
 */
1967
static ObjectAddress
1968
get_object_address_publication_schema(List *object, bool missing_ok)
1969
0
{
1970
0
  ObjectAddress address;
1971
0
  Publication *pub;
1972
0
  char     *pubname;
1973
0
  char     *schemaname;
1974
0
  Oid     schemaid;
1975
1976
0
  ObjectAddressSet(address, PublicationNamespaceRelationId, InvalidOid);
1977
1978
  /* Fetch schema name and publication name from input list */
1979
0
  schemaname = strVal(linitial(object));
1980
0
  pubname = strVal(lsecond(object));
1981
1982
0
  schemaid = get_namespace_oid(schemaname, missing_ok);
1983
0
  if (!OidIsValid(schemaid))
1984
0
    return address;
1985
1986
  /* Now look up the pg_publication tuple */
1987
0
  pub = GetPublicationByName(pubname, missing_ok);
1988
0
  if (!pub)
1989
0
    return address;
1990
1991
  /* Find the publication schema mapping in syscache */
1992
0
  address.objectId =
1993
0
    GetSysCacheOid2(PUBLICATIONNAMESPACEMAP,
1994
0
            Anum_pg_publication_namespace_oid,
1995
0
            ObjectIdGetDatum(schemaid),
1996
0
            ObjectIdGetDatum(pub->oid));
1997
0
  if (!OidIsValid(address.objectId) && !missing_ok)
1998
0
    ereport(ERROR,
1999
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
2000
0
         errmsg("publication schema \"%s\" in publication \"%s\" does not exist",
2001
0
            schemaname, pubname)));
2002
2003
0
  return address;
2004
0
}
2005
2006
/*
2007
 * Find the ObjectAddress for a default ACL.
2008
 */
2009
static ObjectAddress
2010
get_object_address_defacl(List *object, bool missing_ok)
2011
0
{
2012
0
  HeapTuple tp;
2013
0
  Oid     userid;
2014
0
  Oid     schemaid;
2015
0
  char     *username;
2016
0
  char     *schema;
2017
0
  char    objtype;
2018
0
  char     *objtype_str;
2019
0
  ObjectAddress address;
2020
2021
0
  ObjectAddressSet(address, DefaultAclRelationId, InvalidOid);
2022
2023
  /*
2024
   * First figure out the textual attributes so that they can be used for
2025
   * error reporting.
2026
   */
2027
0
  username = strVal(lsecond(object));
2028
0
  if (list_length(object) >= 3)
2029
0
    schema = (char *) strVal(lthird(object));
2030
0
  else
2031
0
    schema = NULL;
2032
2033
  /*
2034
   * Decode defaclobjtype.  Only first char is considered; the rest of the
2035
   * string, if any, is blissfully ignored.
2036
   */
2037
0
  objtype = ((char *) strVal(linitial(object)))[0];
2038
0
  switch (objtype)
2039
0
  {
2040
0
    case DEFACLOBJ_RELATION:
2041
0
      objtype_str = "tables";
2042
0
      break;
2043
0
    case DEFACLOBJ_SEQUENCE:
2044
0
      objtype_str = "sequences";
2045
0
      break;
2046
0
    case DEFACLOBJ_FUNCTION:
2047
0
      objtype_str = "functions";
2048
0
      break;
2049
0
    case DEFACLOBJ_TYPE:
2050
0
      objtype_str = "types";
2051
0
      break;
2052
0
    case DEFACLOBJ_NAMESPACE:
2053
0
      objtype_str = "schemas";
2054
0
      break;
2055
0
    case DEFACLOBJ_LARGEOBJECT:
2056
0
      objtype_str = "large objects";
2057
0
      break;
2058
0
    default:
2059
0
      ereport(ERROR,
2060
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2061
0
           errmsg("unrecognized default ACL object type \"%c\"", objtype),
2062
0
           errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".",
2063
0
               DEFACLOBJ_RELATION,
2064
0
               DEFACLOBJ_SEQUENCE,
2065
0
               DEFACLOBJ_FUNCTION,
2066
0
               DEFACLOBJ_TYPE,
2067
0
               DEFACLOBJ_NAMESPACE,
2068
0
               DEFACLOBJ_LARGEOBJECT)));
2069
0
  }
2070
2071
  /*
2072
   * Look up user ID.  Behave as "default ACL not found" if the user doesn't
2073
   * exist.
2074
   */
2075
0
  tp = SearchSysCache1(AUTHNAME,
2076
0
             CStringGetDatum(username));
2077
0
  if (!HeapTupleIsValid(tp))
2078
0
    goto not_found;
2079
0
  userid = ((Form_pg_authid) GETSTRUCT(tp))->oid;
2080
0
  ReleaseSysCache(tp);
2081
2082
  /*
2083
   * If a schema name was given, look up its OID.  If it doesn't exist,
2084
   * behave as "default ACL not found".
2085
   */
2086
0
  if (schema)
2087
0
  {
2088
0
    schemaid = get_namespace_oid(schema, true);
2089
0
    if (schemaid == InvalidOid)
2090
0
      goto not_found;
2091
0
  }
2092
0
  else
2093
0
    schemaid = InvalidOid;
2094
2095
  /* Finally, look up the pg_default_acl object */
2096
0
  tp = SearchSysCache3(DEFACLROLENSPOBJ,
2097
0
             ObjectIdGetDatum(userid),
2098
0
             ObjectIdGetDatum(schemaid),
2099
0
             CharGetDatum(objtype));
2100
0
  if (!HeapTupleIsValid(tp))
2101
0
    goto not_found;
2102
2103
0
  address.objectId = ((Form_pg_default_acl) GETSTRUCT(tp))->oid;
2104
0
  ReleaseSysCache(tp);
2105
2106
0
  return address;
2107
2108
0
not_found:
2109
0
  if (!missing_ok)
2110
0
  {
2111
0
    if (schema)
2112
0
      ereport(ERROR,
2113
0
          (errcode(ERRCODE_UNDEFINED_OBJECT),
2114
0
           errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist",
2115
0
              username, schema, objtype_str)));
2116
0
    else
2117
0
      ereport(ERROR,
2118
0
          (errcode(ERRCODE_UNDEFINED_OBJECT),
2119
0
           errmsg("default ACL for user \"%s\" on %s does not exist",
2120
0
              username, objtype_str)));
2121
0
  }
2122
0
  return address;
2123
0
}
2124
2125
/*
2126
 * Convert an array of TEXT into a List of string Values, as emitted by the
2127
 * parser, which is what get_object_address uses as input.
2128
 */
2129
static List *
2130
textarray_to_strvaluelist(ArrayType *arr)
2131
0
{
2132
0
  Datum    *elems;
2133
0
  bool     *nulls;
2134
0
  int     nelems;
2135
0
  List     *list = NIL;
2136
0
  int     i;
2137
2138
0
  deconstruct_array_builtin(arr, TEXTOID, &elems, &nulls, &nelems);
2139
2140
0
  for (i = 0; i < nelems; i++)
2141
0
  {
2142
0
    if (nulls[i])
2143
0
      ereport(ERROR,
2144
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2145
0
           errmsg("name or argument lists may not contain nulls")));
2146
0
    list = lappend(list, makeString(TextDatumGetCString(elems[i])));
2147
0
  }
2148
2149
0
  return list;
2150
0
}
2151
2152
/*
2153
 * SQL-callable version of get_object_address
2154
 */
2155
Datum
2156
pg_get_object_address(PG_FUNCTION_ARGS)
2157
0
{
2158
0
  char     *ttype = TextDatumGetCString(PG_GETARG_DATUM(0));
2159
0
  ArrayType  *namearr = PG_GETARG_ARRAYTYPE_P(1);
2160
0
  ArrayType  *argsarr = PG_GETARG_ARRAYTYPE_P(2);
2161
0
  int     itype;
2162
0
  ObjectType  type;
2163
0
  List     *name = NIL;
2164
0
  TypeName   *typename = NULL;
2165
0
  List     *args = NIL;
2166
0
  Node     *objnode = NULL;
2167
0
  ObjectAddress addr;
2168
0
  TupleDesc tupdesc;
2169
0
  Datum   values[3];
2170
0
  bool    nulls[3];
2171
0
  HeapTuple htup;
2172
0
  Relation  relation;
2173
2174
  /* Decode object type, raise error if unknown */
2175
0
  itype = read_objtype_from_string(ttype);
2176
0
  if (itype < 0)
2177
0
    ereport(ERROR,
2178
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2179
0
         errmsg("unsupported object type \"%s\"", ttype)));
2180
0
  type = (ObjectType) itype;
2181
2182
  /*
2183
   * Convert the text array to the representation appropriate for the given
2184
   * object type.  Most use a simple string Values list, but there are some
2185
   * exceptions.
2186
   */
2187
0
  if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST ||
2188
0
    type == OBJECT_TRANSFORM || type == OBJECT_DOMCONSTRAINT)
2189
0
  {
2190
0
    Datum    *arr_elems;
2191
0
    bool     *arr_nulls;
2192
0
    int     nelems;
2193
2194
0
    deconstruct_array_builtin(namearr, TEXTOID, &arr_elems, &arr_nulls, &nelems);
2195
0
    if (nelems != 1)
2196
0
      ereport(ERROR,
2197
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2198
0
           errmsg("name list length must be exactly %d", 1)));
2199
0
    if (arr_nulls[0])
2200
0
      ereport(ERROR,
2201
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2202
0
           errmsg("name or argument lists may not contain nulls")));
2203
0
    typename = typeStringToTypeName(TextDatumGetCString(arr_elems[0]), NULL);
2204
0
  }
2205
0
  else if (type == OBJECT_LARGEOBJECT)
2206
0
  {
2207
0
    Datum    *arr_elems;
2208
0
    bool     *arr_nulls;
2209
0
    int     nelems;
2210
2211
0
    deconstruct_array_builtin(namearr, TEXTOID, &arr_elems, &arr_nulls, &nelems);
2212
0
    if (nelems != 1)
2213
0
      ereport(ERROR,
2214
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2215
0
           errmsg("name list length must be exactly %d", 1)));
2216
0
    if (arr_nulls[0])
2217
0
      ereport(ERROR,
2218
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2219
0
           errmsg("large object OID may not be null")));
2220
0
    objnode = (Node *) makeFloat(TextDatumGetCString(arr_elems[0]));
2221
0
  }
2222
0
  else
2223
0
  {
2224
0
    name = textarray_to_strvaluelist(namearr);
2225
0
    if (name == NIL)
2226
0
      ereport(ERROR,
2227
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2228
0
           errmsg("name list length must be at least %d", 1)));
2229
0
  }
2230
2231
  /*
2232
   * If args are given, decode them according to the object type.
2233
   */
2234
0
  if (type == OBJECT_AGGREGATE ||
2235
0
    type == OBJECT_FUNCTION ||
2236
0
    type == OBJECT_PROCEDURE ||
2237
0
    type == OBJECT_ROUTINE ||
2238
0
    type == OBJECT_OPERATOR ||
2239
0
    type == OBJECT_CAST ||
2240
0
    type == OBJECT_AMOP ||
2241
0
    type == OBJECT_AMPROC)
2242
0
  {
2243
    /* in these cases, the args list must be of TypeName */
2244
0
    Datum    *arr_elems;
2245
0
    bool     *arr_nulls;
2246
0
    int     nelems;
2247
0
    int     i;
2248
2249
0
    deconstruct_array_builtin(argsarr, TEXTOID, &arr_elems, &arr_nulls, &nelems);
2250
2251
0
    args = NIL;
2252
0
    for (i = 0; i < nelems; i++)
2253
0
    {
2254
0
      if (arr_nulls[i])
2255
0
        ereport(ERROR,
2256
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2257
0
             errmsg("name or argument lists may not contain nulls")));
2258
0
      args = lappend(args,
2259
0
               typeStringToTypeName(TextDatumGetCString(arr_elems[i]),
2260
0
                        NULL));
2261
0
    }
2262
0
  }
2263
0
  else
2264
0
  {
2265
    /* For all other object types, use string Values */
2266
0
    args = textarray_to_strvaluelist(argsarr);
2267
0
  }
2268
2269
  /*
2270
   * get_object_address is pretty sensitive to the length of its input
2271
   * lists; check that they're what it wants.
2272
   */
2273
0
  switch (type)
2274
0
  {
2275
0
    case OBJECT_PUBLICATION_NAMESPACE:
2276
0
    case OBJECT_USER_MAPPING:
2277
0
      if (list_length(name) != 1)
2278
0
        ereport(ERROR,
2279
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2280
0
             errmsg("name list length must be exactly %d", 1)));
2281
      /* fall through to check args length */
2282
0
      pg_fallthrough;
2283
0
    case OBJECT_DOMCONSTRAINT:
2284
0
    case OBJECT_CAST:
2285
0
    case OBJECT_PUBLICATION_EXCLUDED_REL:
2286
0
    case OBJECT_PUBLICATION_REL:
2287
0
    case OBJECT_DEFACL:
2288
0
    case OBJECT_TRANSFORM:
2289
0
      if (list_length(args) != 1)
2290
0
        ereport(ERROR,
2291
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2292
0
             errmsg("argument list length must be exactly %d", 1)));
2293
0
      break;
2294
0
    case OBJECT_OPFAMILY:
2295
0
    case OBJECT_OPCLASS:
2296
0
      if (list_length(name) < 2)
2297
0
        ereport(ERROR,
2298
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2299
0
             errmsg("name list length must be at least %d", 2)));
2300
0
      break;
2301
0
    case OBJECT_AMOP:
2302
0
    case OBJECT_AMPROC:
2303
0
      if (list_length(name) < 3)
2304
0
        ereport(ERROR,
2305
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2306
0
             errmsg("name list length must be at least %d", 3)));
2307
      /* fall through to check args length */
2308
0
      pg_fallthrough;
2309
0
    case OBJECT_OPERATOR:
2310
0
      if (list_length(args) != 2)
2311
0
        ereport(ERROR,
2312
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2313
0
             errmsg("argument list length must be exactly %d", 2)));
2314
0
      break;
2315
0
    default:
2316
0
      break;
2317
0
  }
2318
2319
  /*
2320
   * Now build the Node type that get_object_address() expects for the given
2321
   * type.
2322
   */
2323
0
  switch (type)
2324
0
  {
2325
0
    case OBJECT_TABLE:
2326
0
    case OBJECT_SEQUENCE:
2327
0
    case OBJECT_VIEW:
2328
0
    case OBJECT_MATVIEW:
2329
0
    case OBJECT_INDEX:
2330
0
    case OBJECT_FOREIGN_TABLE:
2331
0
    case OBJECT_COLUMN:
2332
0
    case OBJECT_ATTRIBUTE:
2333
0
    case OBJECT_COLLATION:
2334
0
    case OBJECT_CONVERSION:
2335
0
    case OBJECT_STATISTIC_EXT:
2336
0
    case OBJECT_TSPARSER:
2337
0
    case OBJECT_TSDICTIONARY:
2338
0
    case OBJECT_TSTEMPLATE:
2339
0
    case OBJECT_TSCONFIGURATION:
2340
0
    case OBJECT_DEFAULT:
2341
0
    case OBJECT_POLICY:
2342
0
    case OBJECT_RULE:
2343
0
    case OBJECT_TRIGGER:
2344
0
    case OBJECT_TABCONSTRAINT:
2345
0
    case OBJECT_OPCLASS:
2346
0
    case OBJECT_OPFAMILY:
2347
0
      objnode = (Node *) name;
2348
0
      break;
2349
0
    case OBJECT_ACCESS_METHOD:
2350
0
    case OBJECT_DATABASE:
2351
0
    case OBJECT_EVENT_TRIGGER:
2352
0
    case OBJECT_EXTENSION:
2353
0
    case OBJECT_FDW:
2354
0
    case OBJECT_FOREIGN_SERVER:
2355
0
    case OBJECT_LANGUAGE:
2356
0
    case OBJECT_PARAMETER_ACL:
2357
0
    case OBJECT_PUBLICATION:
2358
0
    case OBJECT_ROLE:
2359
0
    case OBJECT_SCHEMA:
2360
0
    case OBJECT_SUBSCRIPTION:
2361
0
    case OBJECT_TABLESPACE:
2362
0
      if (list_length(name) != 1)
2363
0
        ereport(ERROR,
2364
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2365
0
             errmsg("name list length must be exactly %d", 1)));
2366
0
      objnode = linitial(name);
2367
0
      break;
2368
0
    case OBJECT_TYPE:
2369
0
    case OBJECT_DOMAIN:
2370
0
      objnode = (Node *) typename;
2371
0
      break;
2372
0
    case OBJECT_CAST:
2373
0
    case OBJECT_DOMCONSTRAINT:
2374
0
    case OBJECT_TRANSFORM:
2375
0
      objnode = (Node *) list_make2(typename, linitial(args));
2376
0
      break;
2377
0
    case OBJECT_PUBLICATION_EXCLUDED_REL:
2378
0
    case OBJECT_PUBLICATION_REL:
2379
0
      objnode = (Node *) list_make2(name, linitial(args));
2380
0
      break;
2381
0
    case OBJECT_PUBLICATION_NAMESPACE:
2382
0
    case OBJECT_USER_MAPPING:
2383
0
      objnode = (Node *) list_make2(linitial(name), linitial(args));
2384
0
      break;
2385
0
    case OBJECT_DEFACL:
2386
0
      objnode = (Node *) lcons(linitial(args), name);
2387
0
      break;
2388
0
    case OBJECT_AMOP:
2389
0
    case OBJECT_AMPROC:
2390
0
      objnode = (Node *) list_make2(name, args);
2391
0
      break;
2392
0
    case OBJECT_FUNCTION:
2393
0
    case OBJECT_PROCEDURE:
2394
0
    case OBJECT_ROUTINE:
2395
0
    case OBJECT_AGGREGATE:
2396
0
    case OBJECT_OPERATOR:
2397
0
      {
2398
0
        ObjectWithArgs *owa = makeNode(ObjectWithArgs);
2399
2400
0
        owa->objname = name;
2401
0
        owa->objargs = args;
2402
0
        objnode = (Node *) owa;
2403
0
        break;
2404
0
      }
2405
0
    case OBJECT_LARGEOBJECT:
2406
      /* already handled above */
2407
0
      break;
2408
      /* no default, to let compiler warn about missing case */
2409
0
  }
2410
2411
0
  if (objnode == NULL)
2412
0
    elog(ERROR, "unrecognized object type: %d", type);
2413
2414
0
  addr = get_object_address(type, objnode,
2415
0
                &relation, AccessShareLock, false);
2416
2417
  /* We don't need the relcache entry, thank you very much */
2418
0
  if (relation)
2419
0
    relation_close(relation, AccessShareLock);
2420
2421
0
  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2422
0
    elog(ERROR, "return type must be a row type");
2423
2424
0
  values[0] = ObjectIdGetDatum(addr.classId);
2425
0
  values[1] = ObjectIdGetDatum(addr.objectId);
2426
0
  values[2] = Int32GetDatum(addr.objectSubId);
2427
0
  nulls[0] = false;
2428
0
  nulls[1] = false;
2429
0
  nulls[2] = false;
2430
2431
0
  htup = heap_form_tuple(tupdesc, values, nulls);
2432
2433
0
  PG_RETURN_DATUM(HeapTupleGetDatum(htup));
2434
0
}
2435
2436
/*
2437
 * Check ownership of an object previously identified by get_object_address.
2438
 */
2439
void
2440
check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
2441
             Node *object, Relation relation)
2442
0
{
2443
0
  switch (objtype)
2444
0
  {
2445
0
    case OBJECT_INDEX:
2446
0
    case OBJECT_SEQUENCE:
2447
0
    case OBJECT_TABLE:
2448
0
    case OBJECT_VIEW:
2449
0
    case OBJECT_MATVIEW:
2450
0
    case OBJECT_FOREIGN_TABLE:
2451
0
    case OBJECT_COLUMN:
2452
0
    case OBJECT_RULE:
2453
0
    case OBJECT_TRIGGER:
2454
0
    case OBJECT_POLICY:
2455
0
    case OBJECT_TABCONSTRAINT:
2456
0
      if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), roleid))
2457
0
        aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2458
0
                 RelationGetRelationName(relation));
2459
0
      break;
2460
0
    case OBJECT_TYPE:
2461
0
    case OBJECT_DOMAIN:
2462
0
    case OBJECT_ATTRIBUTE:
2463
0
      if (!object_ownercheck(address.classId, address.objectId, roleid))
2464
0
        aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId);
2465
0
      break;
2466
0
    case OBJECT_DOMCONSTRAINT:
2467
0
      {
2468
0
        HeapTuple tuple;
2469
0
        Oid     contypid;
2470
2471
0
        tuple = SearchSysCache1(CONSTROID,
2472
0
                    ObjectIdGetDatum(address.objectId));
2473
0
        if (!HeapTupleIsValid(tuple))
2474
0
          elog(ERROR, "constraint with OID %u does not exist",
2475
0
             address.objectId);
2476
2477
0
        contypid = ((Form_pg_constraint) GETSTRUCT(tuple))->contypid;
2478
2479
0
        ReleaseSysCache(tuple);
2480
2481
        /*
2482
         * Fallback to type ownership check in this case as this is
2483
         * what domain constraints rely on.
2484
         */
2485
0
        if (!object_ownercheck(TypeRelationId, contypid, roleid))
2486
0
          aclcheck_error_type(ACLCHECK_NOT_OWNER, contypid);
2487
0
      }
2488
0
      break;
2489
0
    case OBJECT_AGGREGATE:
2490
0
    case OBJECT_FUNCTION:
2491
0
    case OBJECT_PROCEDURE:
2492
0
    case OBJECT_ROUTINE:
2493
0
    case OBJECT_OPERATOR:
2494
0
      if (!object_ownercheck(address.classId, address.objectId, roleid))
2495
0
        aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2496
0
                 NameListToString((castNode(ObjectWithArgs, object))->objname));
2497
0
      break;
2498
0
    case OBJECT_DATABASE:
2499
0
    case OBJECT_EVENT_TRIGGER:
2500
0
    case OBJECT_EXTENSION:
2501
0
    case OBJECT_FDW:
2502
0
    case OBJECT_FOREIGN_SERVER:
2503
0
    case OBJECT_LANGUAGE:
2504
0
    case OBJECT_PUBLICATION:
2505
0
    case OBJECT_SCHEMA:
2506
0
    case OBJECT_SUBSCRIPTION:
2507
0
    case OBJECT_TABLESPACE:
2508
0
      if (!object_ownercheck(address.classId, address.objectId, roleid))
2509
0
        aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2510
0
                 strVal(object));
2511
0
      break;
2512
0
    case OBJECT_COLLATION:
2513
0
    case OBJECT_CONVERSION:
2514
0
    case OBJECT_OPCLASS:
2515
0
    case OBJECT_OPFAMILY:
2516
0
    case OBJECT_STATISTIC_EXT:
2517
0
    case OBJECT_TSDICTIONARY:
2518
0
    case OBJECT_TSCONFIGURATION:
2519
0
      if (!object_ownercheck(address.classId, address.objectId, roleid))
2520
0
        aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2521
0
                 NameListToString(castNode(List, object)));
2522
0
      break;
2523
0
    case OBJECT_LARGEOBJECT:
2524
0
      if (!lo_compat_privileges &&
2525
0
        !object_ownercheck(address.classId, address.objectId, roleid))
2526
0
        ereport(ERROR,
2527
0
            (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2528
0
             errmsg("must be owner of large object %u",
2529
0
                address.objectId)));
2530
0
      break;
2531
0
    case OBJECT_CAST:
2532
0
      {
2533
        /* We can only check permissions on the source/target types */
2534
0
        TypeName   *sourcetype = linitial_node(TypeName, castNode(List, object));
2535
0
        TypeName   *targettype = lsecond_node(TypeName, castNode(List, object));
2536
0
        Oid     sourcetypeid = typenameTypeId(NULL, sourcetype);
2537
0
        Oid     targettypeid = typenameTypeId(NULL, targettype);
2538
2539
0
        if (!object_ownercheck(TypeRelationId, sourcetypeid, roleid)
2540
0
          && !object_ownercheck(TypeRelationId, targettypeid, roleid))
2541
0
          ereport(ERROR,
2542
0
              (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2543
0
               errmsg("must be owner of type %s or type %s",
2544
0
                  format_type_be(sourcetypeid),
2545
0
                  format_type_be(targettypeid))));
2546
0
      }
2547
0
      break;
2548
0
    case OBJECT_TRANSFORM:
2549
0
      {
2550
0
        TypeName   *typename = linitial_node(TypeName, castNode(List, object));
2551
0
        Oid     typeid = typenameTypeId(NULL, typename);
2552
2553
0
        if (!object_ownercheck(TypeRelationId, typeid, roleid))
2554
0
          aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
2555
0
      }
2556
0
      break;
2557
0
    case OBJECT_ROLE:
2558
2559
      /*
2560
       * We treat roles as being "owned" by those with CREATEROLE priv,
2561
       * provided that they also have admin option on the role.
2562
       *
2563
       * However, superusers are only owned by superusers.
2564
       */
2565
0
      if (superuser_arg(address.objectId))
2566
0
      {
2567
0
        if (!superuser_arg(roleid))
2568
0
          ereport(ERROR,
2569
0
              (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2570
0
               errmsg("permission denied"),
2571
0
               errdetail("The current user must have the %s attribute.",
2572
0
                     "SUPERUSER")));
2573
0
      }
2574
0
      else
2575
0
      {
2576
0
        if (!has_createrole_privilege(roleid))
2577
0
          ereport(ERROR,
2578
0
              (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2579
0
               errmsg("permission denied"),
2580
0
               errdetail("The current user must have the %s attribute.",
2581
0
                     "CREATEROLE")));
2582
0
        if (!is_admin_of_role(roleid, address.objectId))
2583
0
          ereport(ERROR,
2584
0
              (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2585
0
               errmsg("permission denied"),
2586
0
               errdetail("The current user must have the %s option on role \"%s\".",
2587
0
                     "ADMIN",
2588
0
                     GetUserNameFromId(address.objectId,
2589
0
                             true))));
2590
0
      }
2591
0
      break;
2592
0
    case OBJECT_TSPARSER:
2593
0
    case OBJECT_TSTEMPLATE:
2594
0
    case OBJECT_ACCESS_METHOD:
2595
0
    case OBJECT_PARAMETER_ACL:
2596
      /* We treat these object types as being owned by superusers */
2597
0
      if (!superuser_arg(roleid))
2598
0
        ereport(ERROR,
2599
0
            (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2600
0
             errmsg("must be superuser")));
2601
0
      break;
2602
0
    case OBJECT_AMOP:
2603
0
    case OBJECT_AMPROC:
2604
0
    case OBJECT_DEFAULT:
2605
0
    case OBJECT_DEFACL:
2606
0
    case OBJECT_PUBLICATION_EXCLUDED_REL:
2607
0
    case OBJECT_PUBLICATION_NAMESPACE:
2608
0
    case OBJECT_PUBLICATION_REL:
2609
0
    case OBJECT_USER_MAPPING:
2610
      /* These are currently not supported or don't make sense here. */
2611
0
      elog(ERROR, "unsupported object type: %d", (int) objtype);
2612
0
      break;
2613
0
  }
2614
0
}
2615
2616
/*
2617
 * get_object_namespace
2618
 *
2619
 * Find the schema containing the specified object.  For non-schema objects,
2620
 * this function returns InvalidOid.
2621
 */
2622
Oid
2623
get_object_namespace(const ObjectAddress *address)
2624
0
{
2625
0
  SysCacheIdentifier cache;
2626
0
  HeapTuple tuple;
2627
0
  Oid     oid;
2628
0
  const ObjectPropertyType *property;
2629
2630
  /* If not owned by a namespace, just return InvalidOid. */
2631
0
  property = get_object_property_data(address->classId);
2632
0
  if (property->attnum_namespace == InvalidAttrNumber)
2633
0
    return InvalidOid;
2634
2635
  /* Currently, we can only handle object types with system caches. */
2636
0
  cache = property->oid_catcache_id;
2637
0
  Assert(cache != SYSCACHEID_INVALID);
2638
2639
  /* Fetch tuple from syscache and extract namespace attribute. */
2640
0
  tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
2641
0
  if (!HeapTupleIsValid(tuple))
2642
0
    elog(ERROR, "cache lookup failed for cache %d oid %u",
2643
0
       cache, address->objectId);
2644
0
  oid = DatumGetObjectId(SysCacheGetAttrNotNull(cache,
2645
0
                          tuple,
2646
0
                          property->attnum_namespace));
2647
0
  ReleaseSysCache(tuple);
2648
2649
0
  return oid;
2650
0
}
2651
2652
/*
2653
 * Return ObjectType for the given object type as given by
2654
 * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
2655
 * possible output type from getObjectTypeDescription, return -1.
2656
 * Otherwise, an error is thrown.
2657
 */
2658
int
2659
read_objtype_from_string(const char *objtype)
2660
0
{
2661
0
  for (size_t i = 0; i < lengthof(ObjectTypeMap); i++)
2662
0
  {
2663
0
    if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
2664
0
      return ObjectTypeMap[i].tm_type;
2665
0
  }
2666
0
  ereport(ERROR,
2667
0
      (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2668
0
       errmsg("unrecognized object type \"%s\"", objtype)));
2669
2670
0
  return -1;         /* keep compiler quiet */
2671
0
}
2672
2673
/*
2674
 * Interfaces to reference fields of ObjectPropertyType
2675
 */
2676
const char *
2677
get_object_class_descr(Oid class_id)
2678
0
{
2679
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2680
2681
0
  return prop->class_descr;
2682
0
}
2683
2684
Oid
2685
get_object_oid_index(Oid class_id)
2686
0
{
2687
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2688
2689
0
  return prop->oid_index_oid;
2690
0
}
2691
2692
SysCacheIdentifier
2693
get_object_catcache_oid(Oid class_id)
2694
0
{
2695
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2696
2697
0
  return prop->oid_catcache_id;
2698
0
}
2699
2700
SysCacheIdentifier
2701
get_object_catcache_name(Oid class_id)
2702
0
{
2703
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2704
2705
0
  return prop->name_catcache_id;
2706
0
}
2707
2708
AttrNumber
2709
get_object_attnum_oid(Oid class_id)
2710
0
{
2711
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2712
2713
0
  return prop->attnum_oid;
2714
0
}
2715
2716
AttrNumber
2717
get_object_attnum_name(Oid class_id)
2718
0
{
2719
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2720
2721
0
  return prop->attnum_name;
2722
0
}
2723
2724
AttrNumber
2725
get_object_attnum_namespace(Oid class_id)
2726
0
{
2727
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2728
2729
0
  return prop->attnum_namespace;
2730
0
}
2731
2732
AttrNumber
2733
get_object_attnum_owner(Oid class_id)
2734
0
{
2735
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2736
2737
0
  return prop->attnum_owner;
2738
0
}
2739
2740
AttrNumber
2741
get_object_attnum_acl(Oid class_id)
2742
0
{
2743
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2744
2745
0
  return prop->attnum_acl;
2746
0
}
2747
2748
/*
2749
 * get_object_type
2750
 *
2751
 * Return the object type associated with a given object.  This routine
2752
 * is primarily used to determine the object type to mention in ACL check
2753
 * error messages, so it's desirable for it to avoid failing.
2754
 */
2755
ObjectType
2756
get_object_type(Oid class_id, Oid object_id)
2757
0
{
2758
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2759
2760
0
  if (prop->objtype == OBJECT_TABLE)
2761
0
  {
2762
    /*
2763
     * If the property data says it's a table, dig a little deeper to get
2764
     * the real relation kind, so that callers can produce more precise
2765
     * error messages.
2766
     */
2767
0
    return get_relkind_objtype(get_rel_relkind(object_id));
2768
0
  }
2769
0
  else
2770
0
    return prop->objtype;
2771
0
}
2772
2773
bool
2774
get_object_namensp_unique(Oid class_id)
2775
0
{
2776
0
  const ObjectPropertyType *prop = get_object_property_data(class_id);
2777
2778
0
  return prop->is_nsp_name_unique;
2779
0
}
2780
2781
/*
2782
 * Return whether we have useful data for the given object class in the
2783
 * ObjectProperty table.
2784
 */
2785
bool
2786
is_objectclass_supported(Oid class_id)
2787
0
{
2788
0
  for (size_t index = 0; index < lengthof(ObjectProperty); index++)
2789
0
  {
2790
0
    if (ObjectProperty[index].class_oid == class_id)
2791
0
      return true;
2792
0
  }
2793
2794
0
  return false;
2795
0
}
2796
2797
/*
2798
 * Find ObjectProperty structure by class_id.
2799
 */
2800
static const ObjectPropertyType *
2801
get_object_property_data(Oid class_id)
2802
0
{
2803
0
  static const ObjectPropertyType *prop_last = NULL;
2804
2805
  /*
2806
   * A shortcut to speed up multiple consecutive lookups of a particular
2807
   * object class.
2808
   */
2809
0
  if (prop_last && prop_last->class_oid == class_id)
2810
0
    return prop_last;
2811
2812
0
  for (size_t index = 0; index < lengthof(ObjectProperty); index++)
2813
0
  {
2814
0
    if (ObjectProperty[index].class_oid == class_id)
2815
0
    {
2816
0
      prop_last = &ObjectProperty[index];
2817
0
      return &ObjectProperty[index];
2818
0
    }
2819
0
  }
2820
2821
0
  ereport(ERROR,
2822
0
      (errmsg_internal("unrecognized class ID: %u", class_id)));
2823
2824
0
  return NULL;       /* keep MSC compiler happy */
2825
0
}
2826
2827
/*
2828
 * Return a copy of the tuple for the object with the given object OID, from
2829
 * the given catalog (which must have been opened by the caller and suitably
2830
 * locked).  NULL is returned if the OID is not found.
2831
 *
2832
 * We try a syscache first, if available.
2833
 */
2834
HeapTuple
2835
get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
2836
0
{
2837
0
  return
2838
0
    get_catalog_object_by_oid_extended(catalog, oidcol, objectId, false);
2839
0
}
2840
2841
/*
2842
 * Same as get_catalog_object_by_oid(), but with an additional "locktup"
2843
 * argument controlling whether to acquire a LOCKTAG_TUPLE at mode
2844
 * InplaceUpdateTupleLock.  See README.tuplock section "Locking to write
2845
 * inplace-updated tables".
2846
 */
2847
HeapTuple
2848
get_catalog_object_by_oid_extended(Relation catalog,
2849
                   AttrNumber oidcol,
2850
                   Oid objectId,
2851
                   bool locktup)
2852
0
{
2853
0
  HeapTuple tuple;
2854
0
  Oid     classId = RelationGetRelid(catalog);
2855
0
  SysCacheIdentifier oidCacheId = get_object_catcache_oid(classId);
2856
2857
0
  if (oidCacheId >= 0)
2858
0
  {
2859
0
    if (locktup)
2860
0
      tuple = SearchSysCacheLockedCopy1(oidCacheId,
2861
0
                        ObjectIdGetDatum(objectId));
2862
0
    else
2863
0
      tuple = SearchSysCacheCopy1(oidCacheId,
2864
0
                    ObjectIdGetDatum(objectId));
2865
0
    if (!HeapTupleIsValid(tuple))  /* should not happen */
2866
0
      return NULL;
2867
0
  }
2868
0
  else
2869
0
  {
2870
0
    Oid     oidIndexId = get_object_oid_index(classId);
2871
0
    SysScanDesc scan;
2872
0
    ScanKeyData skey;
2873
2874
0
    Assert(OidIsValid(oidIndexId));
2875
2876
0
    ScanKeyInit(&skey,
2877
0
          oidcol,
2878
0
          BTEqualStrategyNumber, F_OIDEQ,
2879
0
          ObjectIdGetDatum(objectId));
2880
2881
0
    scan = systable_beginscan(catalog, oidIndexId, true,
2882
0
                  NULL, 1, &skey);
2883
0
    tuple = systable_getnext(scan);
2884
0
    if (!HeapTupleIsValid(tuple))
2885
0
    {
2886
0
      systable_endscan(scan);
2887
0
      return NULL;
2888
0
    }
2889
2890
0
    if (locktup)
2891
0
      LockTuple(catalog, &tuple->t_self, InplaceUpdateTupleLock);
2892
2893
0
    tuple = heap_copytuple(tuple);
2894
2895
0
    systable_endscan(scan);
2896
0
  }
2897
2898
0
  return tuple;
2899
0
}
2900
2901
/*
2902
 * getPublicationSchemaInfo
2903
 *
2904
 * Get publication name and schema name from the object address into pubname and
2905
 * nspname. Both pubname and nspname are palloc'd strings which will be freed by
2906
 * the caller.
2907
 */
2908
static bool
2909
getPublicationSchemaInfo(const ObjectAddress *object, bool missing_ok,
2910
             char **pubname, char **nspname)
2911
0
{
2912
0
  HeapTuple tup;
2913
0
  Form_pg_publication_namespace pnform;
2914
2915
0
  tup = SearchSysCache1(PUBLICATIONNAMESPACE,
2916
0
              ObjectIdGetDatum(object->objectId));
2917
0
  if (!HeapTupleIsValid(tup))
2918
0
  {
2919
0
    if (!missing_ok)
2920
0
      elog(ERROR, "cache lookup failed for publication schema %u",
2921
0
         object->objectId);
2922
0
    return false;
2923
0
  }
2924
2925
0
  pnform = (Form_pg_publication_namespace) GETSTRUCT(tup);
2926
0
  *pubname = get_publication_name(pnform->pnpubid, missing_ok);
2927
0
  if (!(*pubname))
2928
0
  {
2929
0
    ReleaseSysCache(tup);
2930
0
    return false;
2931
0
  }
2932
2933
0
  *nspname = get_namespace_name(pnform->pnnspid);
2934
0
  if (!(*nspname))
2935
0
  {
2936
0
    Oid     schemaid = pnform->pnnspid;
2937
2938
0
    pfree(*pubname);
2939
0
    ReleaseSysCache(tup);
2940
0
    if (!missing_ok)
2941
0
      elog(ERROR, "cache lookup failed for schema %u",
2942
0
         schemaid);
2943
0
    return false;
2944
0
  }
2945
2946
0
  ReleaseSysCache(tup);
2947
0
  return true;
2948
0
}
2949
2950
/*
2951
 * getObjectDescription: build an object description for messages
2952
 *
2953
 * The result is a palloc'd string.  NULL is returned for an undefined
2954
 * object if missing_ok is true, else an error is generated.
2955
 */
2956
char *
2957
getObjectDescription(const ObjectAddress *object, bool missing_ok)
2958
0
{
2959
0
  StringInfoData buffer;
2960
2961
0
  initStringInfo(&buffer);
2962
2963
0
  switch (object->classId)
2964
0
  {
2965
0
    case RelationRelationId:
2966
0
      if (object->objectSubId == 0)
2967
0
        getRelationDescription(&buffer, object->objectId, missing_ok);
2968
0
      else
2969
0
      {
2970
        /* column, not whole relation */
2971
0
        StringInfoData rel;
2972
0
        char     *attname = get_attname(object->objectId,
2973
0
                          object->objectSubId,
2974
0
                          missing_ok);
2975
2976
0
        if (!attname)
2977
0
          break;
2978
2979
0
        initStringInfo(&rel);
2980
0
        getRelationDescription(&rel, object->objectId, missing_ok);
2981
        /* translator: second %s is, e.g., "table %s" */
2982
0
        appendStringInfo(&buffer, _("column %s of %s"),
2983
0
                 attname, rel.data);
2984
0
        pfree(rel.data);
2985
0
      }
2986
0
      break;
2987
2988
0
    case ProcedureRelationId:
2989
0
      {
2990
0
        uint16    flags = FORMAT_PROC_INVALID_AS_NULL;
2991
0
        char     *proname = format_procedure_extended(object->objectId,
2992
0
                                flags);
2993
2994
0
        if (proname == NULL)
2995
0
          break;
2996
2997
0
        appendStringInfo(&buffer, _("function %s"), proname);
2998
0
        break;
2999
0
      }
3000
3001
0
    case TypeRelationId:
3002
0
      {
3003
0
        uint16    flags = FORMAT_TYPE_INVALID_AS_NULL;
3004
0
        char     *typname = format_type_extended(object->objectId, -1,
3005
0
                               flags);
3006
3007
0
        if (typname == NULL)
3008
0
          break;
3009
3010
0
        appendStringInfo(&buffer, _("type %s"), typname);
3011
0
        break;
3012
0
      }
3013
3014
0
    case CastRelationId:
3015
0
      {
3016
0
        Relation  castDesc;
3017
0
        ScanKeyData skey[1];
3018
0
        SysScanDesc rcscan;
3019
0
        HeapTuple tup;
3020
0
        Form_pg_cast castForm;
3021
3022
0
        castDesc = table_open(CastRelationId, AccessShareLock);
3023
3024
0
        ScanKeyInit(&skey[0],
3025
0
              Anum_pg_cast_oid,
3026
0
              BTEqualStrategyNumber, F_OIDEQ,
3027
0
              ObjectIdGetDatum(object->objectId));
3028
3029
0
        rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
3030
0
                      NULL, 1, skey);
3031
3032
0
        tup = systable_getnext(rcscan);
3033
3034
0
        if (!HeapTupleIsValid(tup))
3035
0
        {
3036
0
          if (!missing_ok)
3037
0
            elog(ERROR, "could not find tuple for cast %u",
3038
0
               object->objectId);
3039
3040
0
          systable_endscan(rcscan);
3041
0
          table_close(castDesc, AccessShareLock);
3042
0
          break;
3043
0
        }
3044
3045
0
        castForm = (Form_pg_cast) GETSTRUCT(tup);
3046
3047
0
        appendStringInfo(&buffer, _("cast from %s to %s"),
3048
0
                 format_type_be(castForm->castsource),
3049
0
                 format_type_be(castForm->casttarget));
3050
3051
0
        systable_endscan(rcscan);
3052
0
        table_close(castDesc, AccessShareLock);
3053
0
        break;
3054
0
      }
3055
3056
0
    case CollationRelationId:
3057
0
      {
3058
0
        HeapTuple collTup;
3059
0
        Form_pg_collation coll;
3060
0
        char     *nspname;
3061
3062
0
        collTup = SearchSysCache1(COLLOID,
3063
0
                      ObjectIdGetDatum(object->objectId));
3064
0
        if (!HeapTupleIsValid(collTup))
3065
0
        {
3066
0
          if (!missing_ok)
3067
0
            elog(ERROR, "cache lookup failed for collation %u",
3068
0
               object->objectId);
3069
0
          break;
3070
0
        }
3071
3072
0
        coll = (Form_pg_collation) GETSTRUCT(collTup);
3073
3074
        /* Qualify the name if not visible in search path */
3075
0
        if (CollationIsVisible(object->objectId))
3076
0
          nspname = NULL;
3077
0
        else
3078
0
          nspname = get_namespace_name(coll->collnamespace);
3079
3080
0
        appendStringInfo(&buffer, _("collation %s"),
3081
0
                 quote_qualified_identifier(nspname,
3082
0
                              NameStr(coll->collname)));
3083
0
        ReleaseSysCache(collTup);
3084
0
        break;
3085
0
      }
3086
3087
0
    case ConstraintRelationId:
3088
0
      {
3089
0
        HeapTuple conTup;
3090
0
        Form_pg_constraint con;
3091
3092
0
        conTup = SearchSysCache1(CONSTROID,
3093
0
                     ObjectIdGetDatum(object->objectId));
3094
0
        if (!HeapTupleIsValid(conTup))
3095
0
        {
3096
0
          if (!missing_ok)
3097
0
            elog(ERROR, "cache lookup failed for constraint %u",
3098
0
               object->objectId);
3099
0
          break;
3100
0
        }
3101
3102
0
        con = (Form_pg_constraint) GETSTRUCT(conTup);
3103
3104
0
        if (OidIsValid(con->conrelid))
3105
0
        {
3106
0
          StringInfoData rel;
3107
3108
0
          initStringInfo(&rel);
3109
0
          getRelationDescription(&rel, con->conrelid, false);
3110
          /* translator: second %s is, e.g., "table %s" */
3111
0
          appendStringInfo(&buffer, _("constraint %s on %s"),
3112
0
                   NameStr(con->conname), rel.data);
3113
0
          pfree(rel.data);
3114
0
        }
3115
0
        else
3116
0
        {
3117
0
          appendStringInfo(&buffer, _("constraint %s"),
3118
0
                   NameStr(con->conname));
3119
0
        }
3120
3121
0
        ReleaseSysCache(conTup);
3122
0
        break;
3123
0
      }
3124
3125
0
    case ConversionRelationId:
3126
0
      {
3127
0
        HeapTuple conTup;
3128
0
        Form_pg_conversion conv;
3129
0
        char     *nspname;
3130
3131
0
        conTup = SearchSysCache1(CONVOID,
3132
0
                     ObjectIdGetDatum(object->objectId));
3133
0
        if (!HeapTupleIsValid(conTup))
3134
0
        {
3135
0
          if (!missing_ok)
3136
0
            elog(ERROR, "cache lookup failed for conversion %u",
3137
0
               object->objectId);
3138
0
          break;
3139
0
        }
3140
3141
0
        conv = (Form_pg_conversion) GETSTRUCT(conTup);
3142
3143
        /* Qualify the name if not visible in search path */
3144
0
        if (ConversionIsVisible(object->objectId))
3145
0
          nspname = NULL;
3146
0
        else
3147
0
          nspname = get_namespace_name(conv->connamespace);
3148
3149
0
        appendStringInfo(&buffer, _("conversion %s"),
3150
0
                 quote_qualified_identifier(nspname,
3151
0
                              NameStr(conv->conname)));
3152
0
        ReleaseSysCache(conTup);
3153
0
        break;
3154
0
      }
3155
3156
0
    case AttrDefaultRelationId:
3157
0
      {
3158
0
        ObjectAddress colobject;
3159
3160
0
        colobject = GetAttrDefaultColumnAddress(object->objectId);
3161
3162
0
        if (!OidIsValid(colobject.objectId))
3163
0
        {
3164
0
          if (!missing_ok)
3165
0
            elog(ERROR, "could not find tuple for attrdef %u",
3166
0
               object->objectId);
3167
0
          break;
3168
0
        }
3169
3170
        /* translator: %s is typically "column %s of table %s" */
3171
0
        appendStringInfo(&buffer, _("default value for %s"),
3172
0
                 getObjectDescription(&colobject, false));
3173
0
        break;
3174
0
      }
3175
3176
0
    case LanguageRelationId:
3177
0
      {
3178
0
        char     *langname = get_language_name(object->objectId,
3179
0
                             missing_ok);
3180
3181
0
        if (langname)
3182
0
          appendStringInfo(&buffer, _("language %s"),
3183
0
                   get_language_name(object->objectId, false));
3184
0
        break;
3185
0
      }
3186
3187
0
    case LargeObjectRelationId:
3188
0
      if (!LargeObjectExists(object->objectId))
3189
0
        break;
3190
0
      appendStringInfo(&buffer, _("large object %u"),
3191
0
               object->objectId);
3192
0
      break;
3193
3194
0
    case OperatorRelationId:
3195
0
      {
3196
0
        uint16    flags = FORMAT_OPERATOR_INVALID_AS_NULL;
3197
0
        char     *oprname = format_operator_extended(object->objectId,
3198
0
                                 flags);
3199
3200
0
        if (oprname == NULL)
3201
0
          break;
3202
3203
0
        appendStringInfo(&buffer, _("operator %s"), oprname);
3204
0
        break;
3205
0
      }
3206
3207
0
    case OperatorClassRelationId:
3208
0
      {
3209
0
        HeapTuple opcTup;
3210
0
        Form_pg_opclass opcForm;
3211
0
        HeapTuple amTup;
3212
0
        Form_pg_am  amForm;
3213
0
        char     *nspname;
3214
3215
0
        opcTup = SearchSysCache1(CLAOID,
3216
0
                     ObjectIdGetDatum(object->objectId));
3217
0
        if (!HeapTupleIsValid(opcTup))
3218
0
        {
3219
0
          if (!missing_ok)
3220
0
            elog(ERROR, "cache lookup failed for opclass %u",
3221
0
               object->objectId);
3222
0
          break;
3223
0
        }
3224
3225
0
        opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
3226
3227
0
        amTup = SearchSysCache1(AMOID,
3228
0
                    ObjectIdGetDatum(opcForm->opcmethod));
3229
0
        if (!HeapTupleIsValid(amTup))
3230
0
          elog(ERROR, "cache lookup failed for access method %u",
3231
0
             opcForm->opcmethod);
3232
0
        amForm = (Form_pg_am) GETSTRUCT(amTup);
3233
3234
        /* Qualify the name if not visible in search path */
3235
0
        if (OpclassIsVisible(object->objectId))
3236
0
          nspname = NULL;
3237
0
        else
3238
0
          nspname = get_namespace_name(opcForm->opcnamespace);
3239
3240
0
        appendStringInfo(&buffer, _("operator class %s for access method %s"),
3241
0
                 quote_qualified_identifier(nspname,
3242
0
                              NameStr(opcForm->opcname)),
3243
0
                 NameStr(amForm->amname));
3244
3245
0
        ReleaseSysCache(amTup);
3246
0
        ReleaseSysCache(opcTup);
3247
0
        break;
3248
0
      }
3249
3250
0
    case OperatorFamilyRelationId:
3251
0
      getOpFamilyDescription(&buffer, object->objectId, missing_ok);
3252
0
      break;
3253
3254
0
    case AccessMethodRelationId:
3255
0
      {
3256
0
        HeapTuple tup;
3257
3258
0
        tup = SearchSysCache1(AMOID,
3259
0
                    ObjectIdGetDatum(object->objectId));
3260
0
        if (!HeapTupleIsValid(tup))
3261
0
        {
3262
0
          if (!missing_ok)
3263
0
            elog(ERROR, "cache lookup failed for access method %u",
3264
0
               object->objectId);
3265
0
          break;
3266
0
        }
3267
3268
0
        appendStringInfo(&buffer, _("access method %s"),
3269
0
                 NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
3270
0
        ReleaseSysCache(tup);
3271
0
        break;
3272
0
      }
3273
3274
0
    case AccessMethodOperatorRelationId:
3275
0
      {
3276
0
        Relation  amopDesc;
3277
0
        HeapTuple tup;
3278
0
        ScanKeyData skey[1];
3279
0
        SysScanDesc amscan;
3280
0
        Form_pg_amop amopForm;
3281
0
        StringInfoData opfam;
3282
3283
0
        amopDesc = table_open(AccessMethodOperatorRelationId,
3284
0
                    AccessShareLock);
3285
3286
0
        ScanKeyInit(&skey[0],
3287
0
              Anum_pg_amop_oid,
3288
0
              BTEqualStrategyNumber, F_OIDEQ,
3289
0
              ObjectIdGetDatum(object->objectId));
3290
3291
0
        amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
3292
0
                      NULL, 1, skey);
3293
3294
0
        tup = systable_getnext(amscan);
3295
3296
0
        if (!HeapTupleIsValid(tup))
3297
0
        {
3298
0
          if (!missing_ok)
3299
0
            elog(ERROR, "could not find tuple for amop entry %u",
3300
0
               object->objectId);
3301
3302
0
          systable_endscan(amscan);
3303
0
          table_close(amopDesc, AccessShareLock);
3304
0
          break;
3305
0
        }
3306
3307
0
        amopForm = (Form_pg_amop) GETSTRUCT(tup);
3308
3309
0
        initStringInfo(&opfam);
3310
0
        getOpFamilyDescription(&opfam, amopForm->amopfamily, false);
3311
3312
        /*
3313
         * We use FORMAT_TYPE_ALLOW_INVALID here so as not to fail
3314
         * completely if the type links are dangling, which is a form
3315
         * of catalog corruption that could occur due to old bugs.
3316
         */
3317
3318
        /*------
3319
           translator: %d is the operator strategy (a number), the
3320
           first two %s's are data type names, the third %s is the
3321
           description of the operator family, and the last %s is the
3322
           textual form of the operator with arguments.  */
3323
0
        appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
3324
0
                 amopForm->amopstrategy,
3325
0
                 format_type_extended(amopForm->amoplefttype,
3326
0
                            -1, FORMAT_TYPE_ALLOW_INVALID),
3327
0
                 format_type_extended(amopForm->amoprighttype,
3328
0
                            -1, FORMAT_TYPE_ALLOW_INVALID),
3329
0
                 opfam.data,
3330
0
                 format_operator(amopForm->amopopr));
3331
3332
0
        pfree(opfam.data);
3333
3334
0
        systable_endscan(amscan);
3335
0
        table_close(amopDesc, AccessShareLock);
3336
0
        break;
3337
0
      }
3338
3339
0
    case AccessMethodProcedureRelationId:
3340
0
      {
3341
0
        Relation  amprocDesc;
3342
0
        ScanKeyData skey[1];
3343
0
        SysScanDesc amscan;
3344
0
        HeapTuple tup;
3345
0
        Form_pg_amproc amprocForm;
3346
0
        StringInfoData opfam;
3347
3348
0
        amprocDesc = table_open(AccessMethodProcedureRelationId,
3349
0
                    AccessShareLock);
3350
3351
0
        ScanKeyInit(&skey[0],
3352
0
              Anum_pg_amproc_oid,
3353
0
              BTEqualStrategyNumber, F_OIDEQ,
3354
0
              ObjectIdGetDatum(object->objectId));
3355
3356
0
        amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
3357
0
                      NULL, 1, skey);
3358
3359
0
        tup = systable_getnext(amscan);
3360
3361
0
        if (!HeapTupleIsValid(tup))
3362
0
        {
3363
0
          if (!missing_ok)
3364
0
            elog(ERROR, "could not find tuple for amproc entry %u",
3365
0
               object->objectId);
3366
3367
0
          systable_endscan(amscan);
3368
0
          table_close(amprocDesc, AccessShareLock);
3369
0
          break;
3370
0
        }
3371
3372
0
        amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
3373
3374
0
        initStringInfo(&opfam);
3375
0
        getOpFamilyDescription(&opfam, amprocForm->amprocfamily, false);
3376
3377
        /*
3378
         * We use FORMAT_TYPE_ALLOW_INVALID here so as not to fail
3379
         * completely if the type links are dangling, which is a form
3380
         * of catalog corruption that could occur due to old bugs.
3381
         */
3382
3383
        /*------
3384
           translator: %d is the function number, the first two %s's
3385
           are data type names, the third %s is the description of the
3386
           operator family, and the last %s is the textual form of the
3387
           function with arguments.  */
3388
0
        appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
3389
0
                 amprocForm->amprocnum,
3390
0
                 format_type_extended(amprocForm->amproclefttype,
3391
0
                            -1, FORMAT_TYPE_ALLOW_INVALID),
3392
0
                 format_type_extended(amprocForm->amprocrighttype,
3393
0
                            -1, FORMAT_TYPE_ALLOW_INVALID),
3394
0
                 opfam.data,
3395
0
                 format_procedure(amprocForm->amproc));
3396
3397
0
        pfree(opfam.data);
3398
3399
0
        systable_endscan(amscan);
3400
0
        table_close(amprocDesc, AccessShareLock);
3401
0
        break;
3402
0
      }
3403
3404
0
    case RewriteRelationId:
3405
0
      {
3406
0
        Relation  ruleDesc;
3407
0
        ScanKeyData skey[1];
3408
0
        SysScanDesc rcscan;
3409
0
        HeapTuple tup;
3410
0
        Form_pg_rewrite rule;
3411
0
        StringInfoData rel;
3412
3413
0
        ruleDesc = table_open(RewriteRelationId, AccessShareLock);
3414
3415
0
        ScanKeyInit(&skey[0],
3416
0
              Anum_pg_rewrite_oid,
3417
0
              BTEqualStrategyNumber, F_OIDEQ,
3418
0
              ObjectIdGetDatum(object->objectId));
3419
3420
0
        rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
3421
0
                      NULL, 1, skey);
3422
3423
0
        tup = systable_getnext(rcscan);
3424
3425
0
        if (!HeapTupleIsValid(tup))
3426
0
        {
3427
0
          if (!missing_ok)
3428
0
            elog(ERROR, "could not find tuple for rule %u",
3429
0
               object->objectId);
3430
3431
0
          systable_endscan(rcscan);
3432
0
          table_close(ruleDesc, AccessShareLock);
3433
0
          break;
3434
0
        }
3435
3436
0
        rule = (Form_pg_rewrite) GETSTRUCT(tup);
3437
3438
0
        initStringInfo(&rel);
3439
0
        getRelationDescription(&rel, rule->ev_class, false);
3440
3441
        /* translator: second %s is, e.g., "table %s" */
3442
0
        appendStringInfo(&buffer, _("rule %s on %s"),
3443
0
                 NameStr(rule->rulename), rel.data);
3444
0
        pfree(rel.data);
3445
0
        systable_endscan(rcscan);
3446
0
        table_close(ruleDesc, AccessShareLock);
3447
0
        break;
3448
0
      }
3449
3450
0
    case TriggerRelationId:
3451
0
      {
3452
0
        Relation  trigDesc;
3453
0
        ScanKeyData skey[1];
3454
0
        SysScanDesc tgscan;
3455
0
        HeapTuple tup;
3456
0
        Form_pg_trigger trig;
3457
0
        StringInfoData rel;
3458
3459
0
        trigDesc = table_open(TriggerRelationId, AccessShareLock);
3460
3461
0
        ScanKeyInit(&skey[0],
3462
0
              Anum_pg_trigger_oid,
3463
0
              BTEqualStrategyNumber, F_OIDEQ,
3464
0
              ObjectIdGetDatum(object->objectId));
3465
3466
0
        tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
3467
0
                      NULL, 1, skey);
3468
3469
0
        tup = systable_getnext(tgscan);
3470
3471
0
        if (!HeapTupleIsValid(tup))
3472
0
        {
3473
0
          if (!missing_ok)
3474
0
            elog(ERROR, "could not find tuple for trigger %u",
3475
0
               object->objectId);
3476
3477
0
          systable_endscan(tgscan);
3478
0
          table_close(trigDesc, AccessShareLock);
3479
0
          break;
3480
0
        }
3481
3482
0
        trig = (Form_pg_trigger) GETSTRUCT(tup);
3483
3484
0
        initStringInfo(&rel);
3485
0
        getRelationDescription(&rel, trig->tgrelid, false);
3486
3487
        /* translator: second %s is, e.g., "table %s" */
3488
0
        appendStringInfo(&buffer, _("trigger %s on %s"),
3489
0
                 NameStr(trig->tgname), rel.data);
3490
0
        pfree(rel.data);
3491
0
        systable_endscan(tgscan);
3492
0
        table_close(trigDesc, AccessShareLock);
3493
0
        break;
3494
0
      }
3495
3496
0
    case NamespaceRelationId:
3497
0
      {
3498
0
        char     *nspname;
3499
3500
0
        nspname = get_namespace_name(object->objectId);
3501
0
        if (!nspname)
3502
0
        {
3503
0
          if (!missing_ok)
3504
0
            elog(ERROR, "cache lookup failed for namespace %u",
3505
0
               object->objectId);
3506
0
          break;
3507
0
        }
3508
0
        appendStringInfo(&buffer, _("schema %s"), nspname);
3509
0
        break;
3510
0
      }
3511
3512
0
    case StatisticExtRelationId:
3513
0
      {
3514
0
        HeapTuple stxTup;
3515
0
        Form_pg_statistic_ext stxForm;
3516
0
        char     *nspname;
3517
3518
0
        stxTup = SearchSysCache1(STATEXTOID,
3519
0
                     ObjectIdGetDatum(object->objectId));
3520
0
        if (!HeapTupleIsValid(stxTup))
3521
0
        {
3522
0
          if (!missing_ok)
3523
0
            elog(ERROR, "could not find tuple for statistics object %u",
3524
0
               object->objectId);
3525
0
          break;
3526
0
        }
3527
3528
0
        stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup);
3529
3530
        /* Qualify the name if not visible in search path */
3531
0
        if (StatisticsObjIsVisible(object->objectId))
3532
0
          nspname = NULL;
3533
0
        else
3534
0
          nspname = get_namespace_name(stxForm->stxnamespace);
3535
3536
0
        appendStringInfo(&buffer, _("statistics object %s"),
3537
0
                 quote_qualified_identifier(nspname,
3538
0
                              NameStr(stxForm->stxname)));
3539
3540
0
        ReleaseSysCache(stxTup);
3541
0
        break;
3542
0
      }
3543
3544
0
    case TSParserRelationId:
3545
0
      {
3546
0
        HeapTuple tup;
3547
0
        Form_pg_ts_parser prsForm;
3548
0
        char     *nspname;
3549
3550
0
        tup = SearchSysCache1(TSPARSEROID,
3551
0
                    ObjectIdGetDatum(object->objectId));
3552
0
        if (!HeapTupleIsValid(tup))
3553
0
        {
3554
0
          if (!missing_ok)
3555
0
            elog(ERROR, "cache lookup failed for text search parser %u",
3556
0
               object->objectId);
3557
0
          break;
3558
0
        }
3559
0
        prsForm = (Form_pg_ts_parser) GETSTRUCT(tup);
3560
3561
        /* Qualify the name if not visible in search path */
3562
0
        if (TSParserIsVisible(object->objectId))
3563
0
          nspname = NULL;
3564
0
        else
3565
0
          nspname = get_namespace_name(prsForm->prsnamespace);
3566
3567
0
        appendStringInfo(&buffer, _("text search parser %s"),
3568
0
                 quote_qualified_identifier(nspname,
3569
0
                              NameStr(prsForm->prsname)));
3570
0
        ReleaseSysCache(tup);
3571
0
        break;
3572
0
      }
3573
3574
0
    case TSDictionaryRelationId:
3575
0
      {
3576
0
        HeapTuple tup;
3577
0
        Form_pg_ts_dict dictForm;
3578
0
        char     *nspname;
3579
3580
0
        tup = SearchSysCache1(TSDICTOID,
3581
0
                    ObjectIdGetDatum(object->objectId));
3582
0
        if (!HeapTupleIsValid(tup))
3583
0
        {
3584
0
          if (!missing_ok)
3585
0
            elog(ERROR, "cache lookup failed for text search dictionary %u",
3586
0
               object->objectId);
3587
0
          break;
3588
0
        }
3589
3590
0
        dictForm = (Form_pg_ts_dict) GETSTRUCT(tup);
3591
3592
        /* Qualify the name if not visible in search path */
3593
0
        if (TSDictionaryIsVisible(object->objectId))
3594
0
          nspname = NULL;
3595
0
        else
3596
0
          nspname = get_namespace_name(dictForm->dictnamespace);
3597
3598
0
        appendStringInfo(&buffer, _("text search dictionary %s"),
3599
0
                 quote_qualified_identifier(nspname,
3600
0
                              NameStr(dictForm->dictname)));
3601
0
        ReleaseSysCache(tup);
3602
0
        break;
3603
0
      }
3604
3605
0
    case TSTemplateRelationId:
3606
0
      {
3607
0
        HeapTuple tup;
3608
0
        Form_pg_ts_template tmplForm;
3609
0
        char     *nspname;
3610
3611
0
        tup = SearchSysCache1(TSTEMPLATEOID,
3612
0
                    ObjectIdGetDatum(object->objectId));
3613
0
        if (!HeapTupleIsValid(tup))
3614
0
        {
3615
0
          if (!missing_ok)
3616
0
            elog(ERROR, "cache lookup failed for text search template %u",
3617
0
               object->objectId);
3618
0
          break;
3619
0
        }
3620
3621
0
        tmplForm = (Form_pg_ts_template) GETSTRUCT(tup);
3622
3623
        /* Qualify the name if not visible in search path */
3624
0
        if (TSTemplateIsVisible(object->objectId))
3625
0
          nspname = NULL;
3626
0
        else
3627
0
          nspname = get_namespace_name(tmplForm->tmplnamespace);
3628
3629
0
        appendStringInfo(&buffer, _("text search template %s"),
3630
0
                 quote_qualified_identifier(nspname,
3631
0
                              NameStr(tmplForm->tmplname)));
3632
0
        ReleaseSysCache(tup);
3633
0
        break;
3634
0
      }
3635
3636
0
    case TSConfigRelationId:
3637
0
      {
3638
0
        HeapTuple tup;
3639
0
        Form_pg_ts_config cfgForm;
3640
0
        char     *nspname;
3641
3642
0
        tup = SearchSysCache1(TSCONFIGOID,
3643
0
                    ObjectIdGetDatum(object->objectId));
3644
0
        if (!HeapTupleIsValid(tup))
3645
0
        {
3646
0
          if (!missing_ok)
3647
0
            elog(ERROR, "cache lookup failed for text search configuration %u",
3648
0
               object->objectId);
3649
0
          break;
3650
0
        }
3651
3652
0
        cfgForm = (Form_pg_ts_config) GETSTRUCT(tup);
3653
3654
        /* Qualify the name if not visible in search path */
3655
0
        if (TSConfigIsVisible(object->objectId))
3656
0
          nspname = NULL;
3657
0
        else
3658
0
          nspname = get_namespace_name(cfgForm->cfgnamespace);
3659
3660
0
        appendStringInfo(&buffer, _("text search configuration %s"),
3661
0
                 quote_qualified_identifier(nspname,
3662
0
                              NameStr(cfgForm->cfgname)));
3663
0
        ReleaseSysCache(tup);
3664
0
        break;
3665
0
      }
3666
3667
0
    case AuthIdRelationId:
3668
0
      {
3669
0
        char     *username = GetUserNameFromId(object->objectId,
3670
0
                             missing_ok);
3671
3672
0
        if (username)
3673
0
          appendStringInfo(&buffer, _("role %s"), username);
3674
0
        break;
3675
0
      }
3676
3677
0
    case AuthMemRelationId:
3678
0
      {
3679
0
        Relation  amDesc;
3680
0
        ScanKeyData skey[1];
3681
0
        SysScanDesc rcscan;
3682
0
        HeapTuple tup;
3683
0
        Form_pg_auth_members amForm;
3684
3685
0
        amDesc = table_open(AuthMemRelationId, AccessShareLock);
3686
3687
0
        ScanKeyInit(&skey[0],
3688
0
              Anum_pg_auth_members_oid,
3689
0
              BTEqualStrategyNumber, F_OIDEQ,
3690
0
              ObjectIdGetDatum(object->objectId));
3691
3692
0
        rcscan = systable_beginscan(amDesc, AuthMemOidIndexId, true,
3693
0
                      NULL, 1, skey);
3694
3695
0
        tup = systable_getnext(rcscan);
3696
3697
0
        if (!HeapTupleIsValid(tup))
3698
0
        {
3699
0
          if (!missing_ok)
3700
0
            elog(ERROR, "could not find tuple for role membership %u",
3701
0
               object->objectId);
3702
3703
0
          systable_endscan(rcscan);
3704
0
          table_close(amDesc, AccessShareLock);
3705
0
          break;
3706
0
        }
3707
3708
0
        amForm = (Form_pg_auth_members) GETSTRUCT(tup);
3709
3710
0
        appendStringInfo(&buffer, _("membership of role %s in role %s"),
3711
0
                 GetUserNameFromId(amForm->member, false),
3712
0
                 GetUserNameFromId(amForm->roleid, false));
3713
3714
0
        systable_endscan(rcscan);
3715
0
        table_close(amDesc, AccessShareLock);
3716
0
        break;
3717
0
      }
3718
3719
0
    case DatabaseRelationId:
3720
0
      {
3721
0
        char     *datname;
3722
3723
0
        datname = get_database_name(object->objectId);
3724
0
        if (!datname)
3725
0
        {
3726
0
          if (!missing_ok)
3727
0
            elog(ERROR, "cache lookup failed for database %u",
3728
0
               object->objectId);
3729
0
          break;
3730
0
        }
3731
0
        appendStringInfo(&buffer, _("database %s"), datname);
3732
0
        break;
3733
0
      }
3734
3735
0
    case TableSpaceRelationId:
3736
0
      {
3737
0
        char     *tblspace;
3738
3739
0
        tblspace = get_tablespace_name(object->objectId);
3740
0
        if (!tblspace)
3741
0
        {
3742
0
          if (!missing_ok)
3743
0
            elog(ERROR, "cache lookup failed for tablespace %u",
3744
0
               object->objectId);
3745
0
          break;
3746
0
        }
3747
0
        appendStringInfo(&buffer, _("tablespace %s"), tblspace);
3748
0
        break;
3749
0
      }
3750
3751
0
    case ForeignDataWrapperRelationId:
3752
0
      {
3753
0
        ForeignDataWrapper *fdw;
3754
3755
0
        fdw = GetForeignDataWrapperExtended(object->objectId,
3756
0
                          missing_ok);
3757
0
        if (fdw)
3758
0
          appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
3759
0
        break;
3760
0
      }
3761
3762
0
    case ForeignServerRelationId:
3763
0
      {
3764
0
        ForeignServer *srv;
3765
3766
0
        srv = GetForeignServerExtended(object->objectId, missing_ok);
3767
0
        if (srv)
3768
0
          appendStringInfo(&buffer, _("server %s"), srv->servername);
3769
0
        break;
3770
0
      }
3771
3772
0
    case UserMappingRelationId:
3773
0
      {
3774
0
        HeapTuple tup;
3775
0
        Oid     useid;
3776
0
        char     *usename;
3777
0
        Form_pg_user_mapping umform;
3778
0
        ForeignServer *srv;
3779
3780
0
        tup = SearchSysCache1(USERMAPPINGOID,
3781
0
                    ObjectIdGetDatum(object->objectId));
3782
0
        if (!HeapTupleIsValid(tup))
3783
0
        {
3784
0
          if (!missing_ok)
3785
0
            elog(ERROR, "cache lookup failed for user mapping %u",
3786
0
               object->objectId);
3787
0
          break;
3788
0
        }
3789
3790
0
        umform = (Form_pg_user_mapping) GETSTRUCT(tup);
3791
0
        useid = umform->umuser;
3792
0
        srv = GetForeignServer(umform->umserver);
3793
3794
0
        ReleaseSysCache(tup);
3795
3796
0
        if (OidIsValid(useid))
3797
0
          usename = GetUserNameFromId(useid, false);
3798
0
        else
3799
0
          usename = "public";
3800
3801
0
        appendStringInfo(&buffer, _("user mapping for %s on server %s"), usename,
3802
0
                 srv->servername);
3803
0
        break;
3804
0
      }
3805
3806
0
    case DefaultAclRelationId:
3807
0
      {
3808
0
        Relation  defaclrel;
3809
0
        ScanKeyData skey[1];
3810
0
        SysScanDesc rcscan;
3811
0
        HeapTuple tup;
3812
0
        Form_pg_default_acl defacl;
3813
0
        char     *rolename;
3814
0
        char     *nspname;
3815
3816
0
        defaclrel = table_open(DefaultAclRelationId, AccessShareLock);
3817
3818
0
        ScanKeyInit(&skey[0],
3819
0
              Anum_pg_default_acl_oid,
3820
0
              BTEqualStrategyNumber, F_OIDEQ,
3821
0
              ObjectIdGetDatum(object->objectId));
3822
3823
0
        rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
3824
0
                      true, NULL, 1, skey);
3825
3826
0
        tup = systable_getnext(rcscan);
3827
3828
0
        if (!HeapTupleIsValid(tup))
3829
0
        {
3830
0
          if (!missing_ok)
3831
0
            elog(ERROR, "could not find tuple for default ACL %u",
3832
0
               object->objectId);
3833
3834
0
          systable_endscan(rcscan);
3835
0
          table_close(defaclrel, AccessShareLock);
3836
0
          break;
3837
0
        }
3838
3839
0
        defacl = (Form_pg_default_acl) GETSTRUCT(tup);
3840
3841
0
        rolename = GetUserNameFromId(defacl->defaclrole, false);
3842
3843
0
        if (OidIsValid(defacl->defaclnamespace))
3844
0
          nspname = get_namespace_name(defacl->defaclnamespace);
3845
0
        else
3846
0
          nspname = NULL;
3847
3848
0
        switch (defacl->defaclobjtype)
3849
0
        {
3850
0
          case DEFACLOBJ_RELATION:
3851
0
            if (nspname)
3852
0
              appendStringInfo(&buffer,
3853
0
                       _("default privileges on new relations belonging to role %s in schema %s"),
3854
0
                       rolename, nspname);
3855
0
            else
3856
0
              appendStringInfo(&buffer,
3857
0
                       _("default privileges on new relations belonging to role %s"),
3858
0
                       rolename);
3859
0
            break;
3860
0
          case DEFACLOBJ_SEQUENCE:
3861
0
            if (nspname)
3862
0
              appendStringInfo(&buffer,
3863
0
                       _("default privileges on new sequences belonging to role %s in schema %s"),
3864
0
                       rolename, nspname);
3865
0
            else
3866
0
              appendStringInfo(&buffer,
3867
0
                       _("default privileges on new sequences belonging to role %s"),
3868
0
                       rolename);
3869
0
            break;
3870
0
          case DEFACLOBJ_FUNCTION:
3871
0
            if (nspname)
3872
0
              appendStringInfo(&buffer,
3873
0
                       _("default privileges on new functions belonging to role %s in schema %s"),
3874
0
                       rolename, nspname);
3875
0
            else
3876
0
              appendStringInfo(&buffer,
3877
0
                       _("default privileges on new functions belonging to role %s"),
3878
0
                       rolename);
3879
0
            break;
3880
0
          case DEFACLOBJ_TYPE:
3881
0
            if (nspname)
3882
0
              appendStringInfo(&buffer,
3883
0
                       _("default privileges on new types belonging to role %s in schema %s"),
3884
0
                       rolename, nspname);
3885
0
            else
3886
0
              appendStringInfo(&buffer,
3887
0
                       _("default privileges on new types belonging to role %s"),
3888
0
                       rolename);
3889
0
            break;
3890
0
          case DEFACLOBJ_NAMESPACE:
3891
0
            Assert(!nspname);
3892
0
            appendStringInfo(&buffer,
3893
0
                     _("default privileges on new schemas belonging to role %s"),
3894
0
                     rolename);
3895
0
            break;
3896
0
          case DEFACLOBJ_LARGEOBJECT:
3897
0
            Assert(!nspname);
3898
0
            appendStringInfo(&buffer,
3899
0
                     _("default privileges on new large objects belonging to role %s"),
3900
0
                     rolename);
3901
0
            break;
3902
0
          default:
3903
            /* shouldn't get here */
3904
0
            if (nspname)
3905
0
              appendStringInfo(&buffer,
3906
0
                       _("default privileges belonging to role %s in schema %s"),
3907
0
                       rolename, nspname);
3908
0
            else
3909
0
              appendStringInfo(&buffer,
3910
0
                       _("default privileges belonging to role %s"),
3911
0
                       rolename);
3912
0
            break;
3913
0
        }
3914
3915
0
        systable_endscan(rcscan);
3916
0
        table_close(defaclrel, AccessShareLock);
3917
0
        break;
3918
0
      }
3919
3920
0
    case ExtensionRelationId:
3921
0
      {
3922
0
        char     *extname;
3923
3924
0
        extname = get_extension_name(object->objectId);
3925
0
        if (!extname)
3926
0
        {
3927
0
          if (!missing_ok)
3928
0
            elog(ERROR, "cache lookup failed for extension %u",
3929
0
               object->objectId);
3930
0
          break;
3931
0
        }
3932
0
        appendStringInfo(&buffer, _("extension %s"), extname);
3933
0
        break;
3934
0
      }
3935
3936
0
    case EventTriggerRelationId:
3937
0
      {
3938
0
        HeapTuple tup;
3939
3940
0
        tup = SearchSysCache1(EVENTTRIGGEROID,
3941
0
                    ObjectIdGetDatum(object->objectId));
3942
0
        if (!HeapTupleIsValid(tup))
3943
0
        {
3944
0
          if (!missing_ok)
3945
0
            elog(ERROR, "cache lookup failed for event trigger %u",
3946
0
               object->objectId);
3947
0
          break;
3948
0
        }
3949
0
        appendStringInfo(&buffer, _("event trigger %s"),
3950
0
                 NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
3951
0
        ReleaseSysCache(tup);
3952
0
        break;
3953
0
      }
3954
3955
0
    case ParameterAclRelationId:
3956
0
      {
3957
0
        HeapTuple tup;
3958
0
        Datum   nameDatum;
3959
0
        char     *parname;
3960
3961
0
        tup = SearchSysCache1(PARAMETERACLOID,
3962
0
                    ObjectIdGetDatum(object->objectId));
3963
0
        if (!HeapTupleIsValid(tup))
3964
0
        {
3965
0
          if (!missing_ok)
3966
0
            elog(ERROR, "cache lookup failed for parameter ACL %u",
3967
0
               object->objectId);
3968
0
          break;
3969
0
        }
3970
0
        nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tup,
3971
0
                           Anum_pg_parameter_acl_parname);
3972
0
        parname = TextDatumGetCString(nameDatum);
3973
0
        appendStringInfo(&buffer, _("parameter %s"), parname);
3974
0
        ReleaseSysCache(tup);
3975
0
        break;
3976
0
      }
3977
3978
0
    case PolicyRelationId:
3979
0
      {
3980
0
        Relation  policy_rel;
3981
0
        ScanKeyData skey[1];
3982
0
        SysScanDesc sscan;
3983
0
        HeapTuple tuple;
3984
0
        Form_pg_policy form_policy;
3985
0
        StringInfoData rel;
3986
3987
0
        policy_rel = table_open(PolicyRelationId, AccessShareLock);
3988
3989
0
        ScanKeyInit(&skey[0],
3990
0
              Anum_pg_policy_oid,
3991
0
              BTEqualStrategyNumber, F_OIDEQ,
3992
0
              ObjectIdGetDatum(object->objectId));
3993
3994
0
        sscan = systable_beginscan(policy_rel, PolicyOidIndexId,
3995
0
                       true, NULL, 1, skey);
3996
3997
0
        tuple = systable_getnext(sscan);
3998
3999
0
        if (!HeapTupleIsValid(tuple))
4000
0
        {
4001
0
          if (!missing_ok)
4002
0
            elog(ERROR, "could not find tuple for policy %u",
4003
0
               object->objectId);
4004
4005
0
          systable_endscan(sscan);
4006
0
          table_close(policy_rel, AccessShareLock);
4007
0
          break;
4008
0
        }
4009
4010
0
        form_policy = (Form_pg_policy) GETSTRUCT(tuple);
4011
4012
0
        initStringInfo(&rel);
4013
0
        getRelationDescription(&rel, form_policy->polrelid, false);
4014
4015
        /* translator: second %s is, e.g., "table %s" */
4016
0
        appendStringInfo(&buffer, _("policy %s on %s"),
4017
0
                 NameStr(form_policy->polname), rel.data);
4018
0
        pfree(rel.data);
4019
0
        systable_endscan(sscan);
4020
0
        table_close(policy_rel, AccessShareLock);
4021
0
        break;
4022
0
      }
4023
4024
0
    case PublicationRelationId:
4025
0
      {
4026
0
        char     *pubname = get_publication_name(object->objectId,
4027
0
                               missing_ok);
4028
4029
0
        if (pubname)
4030
0
          appendStringInfo(&buffer, _("publication %s"), pubname);
4031
0
        break;
4032
0
      }
4033
4034
0
    case PublicationNamespaceRelationId:
4035
0
      {
4036
0
        char     *pubname;
4037
0
        char     *nspname;
4038
4039
0
        if (!getPublicationSchemaInfo(object, missing_ok,
4040
0
                        &pubname, &nspname))
4041
0
          break;
4042
4043
0
        appendStringInfo(&buffer, _("publication of schema %s in publication %s"),
4044
0
                 nspname, pubname);
4045
0
        pfree(pubname);
4046
0
        pfree(nspname);
4047
0
        break;
4048
0
      }
4049
4050
0
    case PublicationRelRelationId:
4051
0
      {
4052
0
        HeapTuple tup;
4053
0
        char     *pubname;
4054
0
        Form_pg_publication_rel prform;
4055
0
        StringInfoData rel;
4056
4057
0
        tup = SearchSysCache1(PUBLICATIONREL,
4058
0
                    ObjectIdGetDatum(object->objectId));
4059
0
        if (!HeapTupleIsValid(tup))
4060
0
        {
4061
0
          if (!missing_ok)
4062
0
            elog(ERROR, "cache lookup failed for publication table %u",
4063
0
               object->objectId);
4064
0
          break;
4065
0
        }
4066
4067
0
        prform = (Form_pg_publication_rel) GETSTRUCT(tup);
4068
0
        pubname = get_publication_name(prform->prpubid, false);
4069
4070
0
        initStringInfo(&rel);
4071
0
        getRelationDescription(&rel, prform->prrelid, false);
4072
4073
0
        if (prform->prexcept)
4074
0
        {
4075
          /* translator: first %s is, e.g., "table %s" */
4076
0
          appendStringInfo(&buffer, _("exclusion of %s from publication %s"),
4077
0
                   rel.data, pubname);
4078
0
        }
4079
0
        else
4080
0
        {
4081
          /* translator: first %s is, e.g., "table %s" */
4082
0
          appendStringInfo(&buffer, _("publication of %s in publication %s"),
4083
0
                   rel.data, pubname);
4084
0
        }
4085
0
        pfree(rel.data);
4086
0
        ReleaseSysCache(tup);
4087
0
        break;
4088
0
      }
4089
4090
0
    case SubscriptionRelationId:
4091
0
      {
4092
0
        char     *subname = get_subscription_name(object->objectId,
4093
0
                              missing_ok);
4094
4095
0
        if (subname)
4096
0
          appendStringInfo(&buffer, _("subscription %s"), subname);
4097
0
        break;
4098
0
      }
4099
4100
0
    case TransformRelationId:
4101
0
      {
4102
0
        HeapTuple trfTup;
4103
0
        Form_pg_transform trfForm;
4104
4105
0
        trfTup = SearchSysCache1(TRFOID,
4106
0
                     ObjectIdGetDatum(object->objectId));
4107
0
        if (!HeapTupleIsValid(trfTup))
4108
0
        {
4109
0
          if (!missing_ok)
4110
0
            elog(ERROR, "could not find tuple for transform %u",
4111
0
               object->objectId);
4112
0
          break;
4113
0
        }
4114
4115
0
        trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
4116
4117
0
        appendStringInfo(&buffer, _("transform for %s language %s"),
4118
0
                 format_type_be(trfForm->trftype),
4119
0
                 get_language_name(trfForm->trflang, false));
4120
4121
0
        ReleaseSysCache(trfTup);
4122
0
        break;
4123
0
      }
4124
4125
0
    default:
4126
0
      ereport(ERROR,
4127
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4128
0
           errmsg("unsupported object class: %u", object->classId)));
4129
0
  }
4130
4131
  /* an empty buffer is equivalent to no object found */
4132
0
  if (buffer.len == 0)
4133
0
    return NULL;
4134
4135
0
  return buffer.data;
4136
0
}
4137
4138
/*
4139
 * getObjectDescriptionOids: as above, except the object is specified by Oids
4140
 */
4141
char *
4142
getObjectDescriptionOids(Oid classid, Oid objid)
4143
0
{
4144
0
  ObjectAddress address;
4145
4146
0
  address.classId = classid;
4147
0
  address.objectId = objid;
4148
0
  address.objectSubId = 0;
4149
4150
0
  return getObjectDescription(&address, false);
4151
0
}
4152
4153
/*
4154
 * subroutine for getObjectDescription: describe a relation
4155
 *
4156
 * The result is appended to "buffer".
4157
 */
4158
static void
4159
getRelationDescription(StringInfo buffer, Oid relid, bool missing_ok)
4160
0
{
4161
0
  HeapTuple relTup;
4162
0
  Form_pg_class relForm;
4163
0
  char     *nspname;
4164
0
  char     *relname;
4165
4166
0
  relTup = SearchSysCache1(RELOID,
4167
0
               ObjectIdGetDatum(relid));
4168
0
  if (!HeapTupleIsValid(relTup))
4169
0
  {
4170
0
    if (!missing_ok)
4171
0
      elog(ERROR, "cache lookup failed for relation %u", relid);
4172
0
    return;
4173
0
  }
4174
0
  relForm = (Form_pg_class) GETSTRUCT(relTup);
4175
4176
  /* Qualify the name if not visible in search path */
4177
0
  if (RelationIsVisible(relid))
4178
0
    nspname = NULL;
4179
0
  else
4180
0
    nspname = get_namespace_name(relForm->relnamespace);
4181
4182
0
  relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
4183
4184
0
  switch (relForm->relkind)
4185
0
  {
4186
0
    case RELKIND_RELATION:
4187
0
    case RELKIND_PARTITIONED_TABLE:
4188
0
      appendStringInfo(buffer, _("table %s"),
4189
0
               relname);
4190
0
      break;
4191
0
    case RELKIND_INDEX:
4192
0
    case RELKIND_PARTITIONED_INDEX:
4193
0
      appendStringInfo(buffer, _("index %s"),
4194
0
               relname);
4195
0
      break;
4196
0
    case RELKIND_SEQUENCE:
4197
0
      appendStringInfo(buffer, _("sequence %s"),
4198
0
               relname);
4199
0
      break;
4200
0
    case RELKIND_TOASTVALUE:
4201
0
      appendStringInfo(buffer, _("toast table %s"),
4202
0
               relname);
4203
0
      break;
4204
0
    case RELKIND_VIEW:
4205
0
      appendStringInfo(buffer, _("view %s"),
4206
0
               relname);
4207
0
      break;
4208
0
    case RELKIND_MATVIEW:
4209
0
      appendStringInfo(buffer, _("materialized view %s"),
4210
0
               relname);
4211
0
      break;
4212
0
    case RELKIND_COMPOSITE_TYPE:
4213
0
      appendStringInfo(buffer, _("composite type %s"),
4214
0
               relname);
4215
0
      break;
4216
0
    case RELKIND_FOREIGN_TABLE:
4217
0
      appendStringInfo(buffer, _("foreign table %s"),
4218
0
               relname);
4219
0
      break;
4220
0
    default:
4221
      /* shouldn't get here */
4222
0
      appendStringInfo(buffer, _("relation %s"),
4223
0
               relname);
4224
0
      break;
4225
0
  }
4226
4227
0
  ReleaseSysCache(relTup);
4228
0
}
4229
4230
/*
4231
 * subroutine for getObjectDescription: describe an operator family
4232
 */
4233
static void
4234
getOpFamilyDescription(StringInfo buffer, Oid opfid, bool missing_ok)
4235
0
{
4236
0
  HeapTuple opfTup;
4237
0
  Form_pg_opfamily opfForm;
4238
0
  HeapTuple amTup;
4239
0
  Form_pg_am  amForm;
4240
0
  char     *nspname;
4241
4242
0
  opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
4243
0
  if (!HeapTupleIsValid(opfTup))
4244
0
  {
4245
0
    if (!missing_ok)
4246
0
      elog(ERROR, "cache lookup failed for opfamily %u", opfid);
4247
0
    return;
4248
0
  }
4249
0
  opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
4250
4251
0
  amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
4252
0
  if (!HeapTupleIsValid(amTup))
4253
0
    elog(ERROR, "cache lookup failed for access method %u",
4254
0
       opfForm->opfmethod);
4255
0
  amForm = (Form_pg_am) GETSTRUCT(amTup);
4256
4257
  /* Qualify the name if not visible in search path */
4258
0
  if (OpfamilyIsVisible(opfid))
4259
0
    nspname = NULL;
4260
0
  else
4261
0
    nspname = get_namespace_name(opfForm->opfnamespace);
4262
4263
0
  appendStringInfo(buffer, _("operator family %s for access method %s"),
4264
0
           quote_qualified_identifier(nspname,
4265
0
                        NameStr(opfForm->opfname)),
4266
0
           NameStr(amForm->amname));
4267
4268
0
  ReleaseSysCache(amTup);
4269
0
  ReleaseSysCache(opfTup);
4270
0
}
4271
4272
/*
4273
 * SQL-level callable version of getObjectDescription
4274
 */
4275
Datum
4276
pg_describe_object(PG_FUNCTION_ARGS)
4277
0
{
4278
0
  Oid     classid = PG_GETARG_OID(0);
4279
0
  Oid     objid = PG_GETARG_OID(1);
4280
0
  int32   objsubid = PG_GETARG_INT32(2);
4281
0
  char     *description;
4282
0
  ObjectAddress address;
4283
4284
  /* for "pinned" items in pg_depend, return null */
4285
0
  if (!OidIsValid(classid) && !OidIsValid(objid))
4286
0
    PG_RETURN_NULL();
4287
4288
0
  address.classId = classid;
4289
0
  address.objectId = objid;
4290
0
  address.objectSubId = objsubid;
4291
4292
0
  description = getObjectDescription(&address, true);
4293
4294
0
  if (description == NULL)
4295
0
    PG_RETURN_NULL();
4296
4297
0
  PG_RETURN_TEXT_P(cstring_to_text(description));
4298
0
}
4299
4300
/*
4301
 * SQL-level callable function to obtain object type + identity
4302
 */
4303
Datum
4304
pg_identify_object(PG_FUNCTION_ARGS)
4305
0
{
4306
0
  Oid     classid = PG_GETARG_OID(0);
4307
0
  Oid     objid = PG_GETARG_OID(1);
4308
0
  int32   objsubid = PG_GETARG_INT32(2);
4309
0
  Oid     schema_oid = InvalidOid;
4310
0
  const char *objname = NULL;
4311
0
  char     *objidentity;
4312
0
  ObjectAddress address;
4313
0
  Datum   values[4];
4314
0
  bool    nulls[4];
4315
0
  TupleDesc tupdesc;
4316
0
  HeapTuple htup;
4317
4318
0
  address.classId = classid;
4319
0
  address.objectId = objid;
4320
0
  address.objectSubId = objsubid;
4321
4322
0
  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
4323
0
    elog(ERROR, "return type must be a row type");
4324
4325
0
  if (is_objectclass_supported(address.classId))
4326
0
  {
4327
0
    HeapTuple objtup;
4328
0
    Relation  catalog = table_open(address.classId, AccessShareLock);
4329
4330
0
    objtup = get_catalog_object_by_oid(catalog,
4331
0
                       get_object_attnum_oid(address.classId),
4332
0
                       address.objectId);
4333
0
    if (objtup != NULL)
4334
0
    {
4335
0
      bool    isnull;
4336
0
      AttrNumber  nspAttnum;
4337
0
      AttrNumber  nameAttnum;
4338
4339
0
      nspAttnum = get_object_attnum_namespace(address.classId);
4340
0
      if (nspAttnum != InvalidAttrNumber)
4341
0
      {
4342
0
        schema_oid = DatumGetObjectId(heap_getattr(objtup, nspAttnum,
4343
0
                               RelationGetDescr(catalog), &isnull));
4344
0
        if (isnull)
4345
0
          elog(ERROR, "invalid null namespace in object %u/%u/%d",
4346
0
             address.classId, address.objectId, address.objectSubId);
4347
0
      }
4348
4349
      /*
4350
       * We only return the object name if it can be used (together with
4351
       * the schema name, if any) as a unique identifier.
4352
       */
4353
0
      if (get_object_namensp_unique(address.classId))
4354
0
      {
4355
0
        nameAttnum = get_object_attnum_name(address.classId);
4356
0
        if (nameAttnum != InvalidAttrNumber)
4357
0
        {
4358
0
          Datum   nameDatum;
4359
4360
0
          nameDatum = heap_getattr(objtup, nameAttnum,
4361
0
                       RelationGetDescr(catalog), &isnull);
4362
0
          if (isnull)
4363
0
            elog(ERROR, "invalid null name in object %u/%u/%d",
4364
0
               address.classId, address.objectId, address.objectSubId);
4365
0
          objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
4366
0
        }
4367
0
      }
4368
0
    }
4369
4370
0
    table_close(catalog, AccessShareLock);
4371
0
  }
4372
4373
  /* object type, which can never be NULL */
4374
0
  values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
4375
0
  nulls[0] = false;
4376
4377
  /*
4378
   * Before doing anything, extract the object identity.  If the identity
4379
   * could not be found, set all the fields except the object type to NULL.
4380
   */
4381
0
  objidentity = getObjectIdentity(&address, true);
4382
4383
  /* schema name */
4384
0
  nulls[1] = true;
4385
0
  if (OidIsValid(schema_oid) && objidentity)
4386
0
  {
4387
0
    char     *nspname = get_namespace_name(schema_oid);
4388
4389
    /* The schema may have been dropped concurrently; report it as NULL */
4390
0
    if (nspname != NULL)
4391
0
    {
4392
0
      values[1] = CStringGetTextDatum(quote_identifier(nspname));
4393
0
      nulls[1] = false;
4394
0
    }
4395
0
  }
4396
4397
  /* object name */
4398
0
  if (objname && objidentity)
4399
0
  {
4400
0
    values[2] = CStringGetTextDatum(objname);
4401
0
    nulls[2] = false;
4402
0
  }
4403
0
  else
4404
0
    nulls[2] = true;
4405
4406
  /* object identity */
4407
0
  if (objidentity)
4408
0
  {
4409
0
    values[3] = CStringGetTextDatum(objidentity);
4410
0
    nulls[3] = false;
4411
0
  }
4412
0
  else
4413
0
    nulls[3] = true;
4414
4415
0
  htup = heap_form_tuple(tupdesc, values, nulls);
4416
4417
0
  PG_RETURN_DATUM(HeapTupleGetDatum(htup));
4418
0
}
4419
4420
/*
4421
 * SQL-level callable function to obtain object type + identity
4422
 */
4423
Datum
4424
pg_identify_object_as_address(PG_FUNCTION_ARGS)
4425
0
{
4426
0
  Oid     classid = PG_GETARG_OID(0);
4427
0
  Oid     objid = PG_GETARG_OID(1);
4428
0
  int32   objsubid = PG_GETARG_INT32(2);
4429
0
  ObjectAddress address;
4430
0
  char     *identity;
4431
0
  List     *names;
4432
0
  List     *args;
4433
0
  Datum   values[3];
4434
0
  bool    nulls[3];
4435
0
  TupleDesc tupdesc;
4436
0
  HeapTuple htup;
4437
4438
0
  address.classId = classid;
4439
0
  address.objectId = objid;
4440
0
  address.objectSubId = objsubid;
4441
4442
0
  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
4443
0
    elog(ERROR, "return type must be a row type");
4444
4445
  /* object type, which can never be NULL */
4446
0
  values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
4447
0
  nulls[0] = false;
4448
4449
  /* object identity */
4450
0
  identity = getObjectIdentityParts(&address, &names, &args, true);
4451
0
  if (identity == NULL)
4452
0
  {
4453
0
    nulls[1] = true;
4454
0
    nulls[2] = true;
4455
0
  }
4456
0
  else
4457
0
  {
4458
0
    pfree(identity);
4459
4460
    /* object_names */
4461
0
    if (names != NIL)
4462
0
      values[1] = PointerGetDatum(strlist_to_textarray(names));
4463
0
    else
4464
0
      values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
4465
0
    nulls[1] = false;
4466
4467
    /* object_args */
4468
0
    if (args)
4469
0
      values[2] = PointerGetDatum(strlist_to_textarray(args));
4470
0
    else
4471
0
      values[2] = PointerGetDatum(construct_empty_array(TEXTOID));
4472
0
    nulls[2] = false;
4473
0
  }
4474
4475
0
  htup = heap_form_tuple(tupdesc, values, nulls);
4476
4477
0
  PG_RETURN_DATUM(HeapTupleGetDatum(htup));
4478
0
}
4479
4480
/*
4481
 * SQL-level callable function to obtain the ACL of a specified object, given
4482
 * its catalog OID, object OID and sub-object ID.
4483
 */
4484
Datum
4485
pg_get_acl(PG_FUNCTION_ARGS)
4486
0
{
4487
0
  Oid     classId = PG_GETARG_OID(0);
4488
0
  Oid     objectId = PG_GETARG_OID(1);
4489
0
  int32   objsubid = PG_GETARG_INT32(2);
4490
0
  Oid     catalogId;
4491
0
  AttrNumber  Anum_acl;
4492
0
  Datum   datum;
4493
0
  bool    isnull;
4494
0
  HeapTuple tup;
4495
4496
  /* for "pinned" items in pg_depend, return null */
4497
0
  if (!OidIsValid(classId) && !OidIsValid(objectId))
4498
0
    PG_RETURN_NULL();
4499
4500
  /* for large objects, the catalog to look at is pg_largeobject_metadata */
4501
0
  catalogId = (classId == LargeObjectRelationId) ?
4502
0
    LargeObjectMetadataRelationId : classId;
4503
0
  Anum_acl = get_object_attnum_acl(catalogId);
4504
4505
  /* return NULL if no ACL field for this catalog */
4506
0
  if (Anum_acl == InvalidAttrNumber)
4507
0
    PG_RETURN_NULL();
4508
4509
  /*
4510
   * If dealing with a relation's attribute (objsubid is set), the ACL is
4511
   * retrieved from pg_attribute.
4512
   */
4513
0
  if (classId == RelationRelationId && objsubid != 0)
4514
0
  {
4515
0
    AttrNumber  attnum = (AttrNumber) objsubid;
4516
4517
0
    tup = SearchSysCacheCopyAttNum(objectId, attnum);
4518
4519
0
    if (!HeapTupleIsValid(tup))
4520
0
      PG_RETURN_NULL();
4521
4522
0
    datum = SysCacheGetAttr(ATTNUM, tup, Anum_pg_attribute_attacl,
4523
0
                &isnull);
4524
0
  }
4525
0
  else
4526
0
  {
4527
0
    Relation  rel;
4528
4529
0
    rel = table_open(catalogId, AccessShareLock);
4530
4531
0
    tup = get_catalog_object_by_oid(rel, get_object_attnum_oid(catalogId),
4532
0
                    objectId);
4533
0
    if (!HeapTupleIsValid(tup))
4534
0
    {
4535
0
      table_close(rel, AccessShareLock);
4536
0
      PG_RETURN_NULL();
4537
0
    }
4538
4539
0
    datum = heap_getattr(tup, Anum_acl, RelationGetDescr(rel), &isnull);
4540
0
    table_close(rel, AccessShareLock);
4541
0
  }
4542
4543
0
  if (isnull)
4544
0
    PG_RETURN_NULL();
4545
4546
0
  PG_RETURN_DATUM(datum);
4547
0
}
4548
4549
/*
4550
 * Return a palloc'ed string that describes the type of object that the
4551
 * passed address is for.
4552
 *
4553
 * Keep ObjectTypeMap in sync with this.
4554
 */
4555
char *
4556
getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
4557
0
{
4558
0
  StringInfoData buffer;
4559
4560
0
  initStringInfo(&buffer);
4561
4562
0
  switch (object->classId)
4563
0
  {
4564
0
    case RelationRelationId:
4565
0
      getRelationTypeDescription(&buffer, object->objectId,
4566
0
                     object->objectSubId,
4567
0
                     missing_ok);
4568
0
      break;
4569
4570
0
    case ProcedureRelationId:
4571
0
      getProcedureTypeDescription(&buffer, object->objectId,
4572
0
                    missing_ok);
4573
0
      break;
4574
4575
0
    case TypeRelationId:
4576
0
      appendStringInfoString(&buffer, "type");
4577
0
      break;
4578
4579
0
    case CastRelationId:
4580
0
      appendStringInfoString(&buffer, "cast");
4581
0
      break;
4582
4583
0
    case CollationRelationId:
4584
0
      appendStringInfoString(&buffer, "collation");
4585
0
      break;
4586
4587
0
    case ConstraintRelationId:
4588
0
      getConstraintTypeDescription(&buffer, object->objectId,
4589
0
                     missing_ok);
4590
0
      break;
4591
4592
0
    case ConversionRelationId:
4593
0
      appendStringInfoString(&buffer, "conversion");
4594
0
      break;
4595
4596
0
    case AttrDefaultRelationId:
4597
0
      appendStringInfoString(&buffer, "default value");
4598
0
      break;
4599
4600
0
    case LanguageRelationId:
4601
0
      appendStringInfoString(&buffer, "language");
4602
0
      break;
4603
4604
0
    case LargeObjectRelationId:
4605
0
      appendStringInfoString(&buffer, "large object");
4606
0
      break;
4607
4608
0
    case OperatorRelationId:
4609
0
      appendStringInfoString(&buffer, "operator");
4610
0
      break;
4611
4612
0
    case OperatorClassRelationId:
4613
0
      appendStringInfoString(&buffer, "operator class");
4614
0
      break;
4615
4616
0
    case OperatorFamilyRelationId:
4617
0
      appendStringInfoString(&buffer, "operator family");
4618
0
      break;
4619
4620
0
    case AccessMethodRelationId:
4621
0
      appendStringInfoString(&buffer, "access method");
4622
0
      break;
4623
4624
0
    case AccessMethodOperatorRelationId:
4625
0
      appendStringInfoString(&buffer, "operator of access method");
4626
0
      break;
4627
4628
0
    case AccessMethodProcedureRelationId:
4629
0
      appendStringInfoString(&buffer, "function of access method");
4630
0
      break;
4631
4632
0
    case RewriteRelationId:
4633
0
      appendStringInfoString(&buffer, "rule");
4634
0
      break;
4635
4636
0
    case TriggerRelationId:
4637
0
      appendStringInfoString(&buffer, "trigger");
4638
0
      break;
4639
4640
0
    case NamespaceRelationId:
4641
0
      appendStringInfoString(&buffer, "schema");
4642
0
      break;
4643
4644
0
    case StatisticExtRelationId:
4645
0
      appendStringInfoString(&buffer, "statistics object");
4646
0
      break;
4647
4648
0
    case TSParserRelationId:
4649
0
      appendStringInfoString(&buffer, "text search parser");
4650
0
      break;
4651
4652
0
    case TSDictionaryRelationId:
4653
0
      appendStringInfoString(&buffer, "text search dictionary");
4654
0
      break;
4655
4656
0
    case TSTemplateRelationId:
4657
0
      appendStringInfoString(&buffer, "text search template");
4658
0
      break;
4659
4660
0
    case TSConfigRelationId:
4661
0
      appendStringInfoString(&buffer, "text search configuration");
4662
0
      break;
4663
4664
0
    case AuthIdRelationId:
4665
0
      appendStringInfoString(&buffer, "role");
4666
0
      break;
4667
4668
0
    case AuthMemRelationId:
4669
0
      appendStringInfoString(&buffer, "role membership");
4670
0
      break;
4671
4672
0
    case DatabaseRelationId:
4673
0
      appendStringInfoString(&buffer, "database");
4674
0
      break;
4675
4676
0
    case TableSpaceRelationId:
4677
0
      appendStringInfoString(&buffer, "tablespace");
4678
0
      break;
4679
4680
0
    case ForeignDataWrapperRelationId:
4681
0
      appendStringInfoString(&buffer, "foreign-data wrapper");
4682
0
      break;
4683
4684
0
    case ForeignServerRelationId:
4685
0
      appendStringInfoString(&buffer, "server");
4686
0
      break;
4687
4688
0
    case UserMappingRelationId:
4689
0
      appendStringInfoString(&buffer, "user mapping");
4690
0
      break;
4691
4692
0
    case DefaultAclRelationId:
4693
0
      appendStringInfoString(&buffer, "default acl");
4694
0
      break;
4695
4696
0
    case ExtensionRelationId:
4697
0
      appendStringInfoString(&buffer, "extension");
4698
0
      break;
4699
4700
0
    case EventTriggerRelationId:
4701
0
      appendStringInfoString(&buffer, "event trigger");
4702
0
      break;
4703
4704
0
    case ParameterAclRelationId:
4705
0
      appendStringInfoString(&buffer, "parameter ACL");
4706
0
      break;
4707
4708
0
    case PolicyRelationId:
4709
0
      appendStringInfoString(&buffer, "policy");
4710
0
      break;
4711
4712
0
    case PublicationRelationId:
4713
0
      appendStringInfoString(&buffer, "publication");
4714
0
      break;
4715
4716
0
    case PublicationNamespaceRelationId:
4717
0
      appendStringInfoString(&buffer, "publication namespace");
4718
0
      break;
4719
4720
0
    case PublicationRelRelationId:
4721
0
      getPublicationRelationTypeDescription(&buffer, object->objectId,
4722
0
                          missing_ok);
4723
0
      break;
4724
4725
0
    case SubscriptionRelationId:
4726
0
      appendStringInfoString(&buffer, "subscription");
4727
0
      break;
4728
4729
0
    case TransformRelationId:
4730
0
      appendStringInfoString(&buffer, "transform");
4731
0
      break;
4732
4733
0
    default:
4734
0
      elog(ERROR, "unsupported object class: %u", object->classId);
4735
0
  }
4736
4737
  /* the result can never be empty */
4738
0
  Assert(buffer.len > 0);
4739
4740
0
  return buffer.data;
4741
0
}
4742
4743
/*
4744
 * subroutine for getObjectTypeDescription: describe a relation type
4745
 */
4746
static void
4747
getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId,
4748
               bool missing_ok)
4749
0
{
4750
0
  HeapTuple relTup;
4751
0
  Form_pg_class relForm;
4752
4753
0
  relTup = SearchSysCache1(RELOID,
4754
0
               ObjectIdGetDatum(relid));
4755
0
  if (!HeapTupleIsValid(relTup))
4756
0
  {
4757
0
    if (!missing_ok)
4758
0
      elog(ERROR, "cache lookup failed for relation %u", relid);
4759
4760
    /* fallback to "relation" for an undefined object */
4761
0
    appendStringInfoString(buffer, "relation");
4762
0
    return;
4763
0
  }
4764
0
  relForm = (Form_pg_class) GETSTRUCT(relTup);
4765
4766
0
  switch (relForm->relkind)
4767
0
  {
4768
0
    case RELKIND_RELATION:
4769
0
    case RELKIND_PARTITIONED_TABLE:
4770
0
      appendStringInfoString(buffer, "table");
4771
0
      break;
4772
0
    case RELKIND_INDEX:
4773
0
    case RELKIND_PARTITIONED_INDEX:
4774
0
      appendStringInfoString(buffer, "index");
4775
0
      break;
4776
0
    case RELKIND_SEQUENCE:
4777
0
      appendStringInfoString(buffer, "sequence");
4778
0
      break;
4779
0
    case RELKIND_TOASTVALUE:
4780
0
      appendStringInfoString(buffer, "toast table");
4781
0
      break;
4782
0
    case RELKIND_VIEW:
4783
0
      appendStringInfoString(buffer, "view");
4784
0
      break;
4785
0
    case RELKIND_MATVIEW:
4786
0
      appendStringInfoString(buffer, "materialized view");
4787
0
      break;
4788
0
    case RELKIND_COMPOSITE_TYPE:
4789
0
      appendStringInfoString(buffer, "composite type");
4790
0
      break;
4791
0
    case RELKIND_FOREIGN_TABLE:
4792
0
      appendStringInfoString(buffer, "foreign table");
4793
0
      break;
4794
0
    default:
4795
      /* shouldn't get here */
4796
0
      appendStringInfoString(buffer, "relation");
4797
0
      break;
4798
0
  }
4799
4800
0
  if (objectSubId != 0)
4801
0
    appendStringInfoString(buffer, " column");
4802
4803
0
  ReleaseSysCache(relTup);
4804
0
}
4805
4806
/*
4807
 * subroutine for getObjectTypeDescription: describe a constraint type
4808
 */
4809
static void
4810
getConstraintTypeDescription(StringInfo buffer, Oid constroid, bool missing_ok)
4811
0
{
4812
0
  Relation  constrRel;
4813
0
  HeapTuple constrTup;
4814
0
  Form_pg_constraint constrForm;
4815
4816
0
  constrRel = table_open(ConstraintRelationId, AccessShareLock);
4817
0
  constrTup = get_catalog_object_by_oid(constrRel, Anum_pg_constraint_oid,
4818
0
                      constroid);
4819
0
  if (!HeapTupleIsValid(constrTup))
4820
0
  {
4821
0
    if (!missing_ok)
4822
0
      elog(ERROR, "cache lookup failed for constraint %u", constroid);
4823
4824
0
    table_close(constrRel, AccessShareLock);
4825
4826
    /* fallback to "constraint" for an undefined object */
4827
0
    appendStringInfoString(buffer, "constraint");
4828
0
    return;
4829
0
  }
4830
4831
0
  constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
4832
4833
0
  if (OidIsValid(constrForm->conrelid))
4834
0
    appendStringInfoString(buffer, "table constraint");
4835
0
  else if (OidIsValid(constrForm->contypid))
4836
0
    appendStringInfoString(buffer, "domain constraint");
4837
0
  else
4838
0
    elog(ERROR, "invalid constraint %u", constrForm->oid);
4839
4840
0
  table_close(constrRel, AccessShareLock);
4841
0
}
4842
4843
/*
4844
 * subroutine for getObjectTypeDescription: describe a procedure type
4845
 */
4846
static void
4847
getProcedureTypeDescription(StringInfo buffer, Oid procid,
4848
              bool missing_ok)
4849
0
{
4850
0
  HeapTuple procTup;
4851
0
  Form_pg_proc procForm;
4852
4853
0
  procTup = SearchSysCache1(PROCOID,
4854
0
                ObjectIdGetDatum(procid));
4855
0
  if (!HeapTupleIsValid(procTup))
4856
0
  {
4857
0
    if (!missing_ok)
4858
0
      elog(ERROR, "cache lookup failed for procedure %u", procid);
4859
4860
    /* fallback to "procedure" for an undefined object */
4861
0
    appendStringInfoString(buffer, "routine");
4862
0
    return;
4863
0
  }
4864
0
  procForm = (Form_pg_proc) GETSTRUCT(procTup);
4865
4866
0
  if (procForm->prokind == PROKIND_AGGREGATE)
4867
0
    appendStringInfoString(buffer, "aggregate");
4868
0
  else if (procForm->prokind == PROKIND_PROCEDURE)
4869
0
    appendStringInfoString(buffer, "procedure");
4870
0
  else            /* function or window function */
4871
0
    appendStringInfoString(buffer, "function");
4872
4873
0
  ReleaseSysCache(procTup);
4874
0
}
4875
4876
/*
4877
 * subroutine for getObjectTypeDescription: describe a publication relation
4878
 *
4879
 * Appends "publication excluded relation" for EXCEPT entries, or
4880
 * "publication relation" for published relations, to buffer.
4881
 */
4882
static void
4883
getPublicationRelationTypeDescription(StringInfo buffer, Oid pubreloid,
4884
                    bool missing_ok)
4885
0
{
4886
0
  HeapTuple tup;
4887
0
  Form_pg_publication_rel prform;
4888
4889
0
  tup = SearchSysCache1(PUBLICATIONREL, ObjectIdGetDatum(pubreloid));
4890
0
  if (!HeapTupleIsValid(tup))
4891
0
  {
4892
0
    if (!missing_ok)
4893
0
      elog(ERROR, "cache lookup failed for publication table %u",
4894
0
         pubreloid);
4895
4896
    /* fallback to "publication relation" for an undefined object */
4897
0
    appendStringInfoString(buffer, "publication relation");
4898
0
    return;
4899
0
  }
4900
4901
0
  prform = (Form_pg_publication_rel) GETSTRUCT(tup);
4902
4903
0
  if (prform->prexcept)
4904
0
    appendStringInfoString(buffer, "publication excluded relation");
4905
0
  else
4906
0
    appendStringInfoString(buffer, "publication relation");
4907
4908
0
  ReleaseSysCache(tup);
4909
0
}
4910
4911
/*
4912
 * Obtain a given object's identity, as a palloc'ed string.
4913
 *
4914
 * This is for machine consumption, so it's not translated.  All elements are
4915
 * schema-qualified when appropriate.  Returns NULL if the object could not
4916
 * be found.
4917
 */
4918
char *
4919
getObjectIdentity(const ObjectAddress *object, bool missing_ok)
4920
0
{
4921
0
  return getObjectIdentityParts(object, NULL, NULL, missing_ok);
4922
0
}
4923
4924
/*
4925
 * As above, but more detailed.
4926
 *
4927
 * There are two sets of return values: the identity itself as a palloc'd
4928
 * string is returned.  objname and objargs, if not NULL, are output parameters
4929
 * that receive lists of C-strings that are useful to give back to
4930
 * get_object_address() to reconstruct the ObjectAddress.  Returns NULL if
4931
 * the object could not be found.
4932
 */
4933
char *
4934
getObjectIdentityParts(const ObjectAddress *object,
4935
             List **objname, List **objargs,
4936
             bool missing_ok)
4937
0
{
4938
0
  StringInfoData buffer;
4939
4940
0
  initStringInfo(&buffer);
4941
4942
  /*
4943
   * Make sure that both objname and objargs were passed, or none was; and
4944
   * initialize them to empty lists.  For objname this is useless because it
4945
   * will be initialized in all cases inside the switch; but we do it anyway
4946
   * so that we can test below that no branch leaves it unset.
4947
   */
4948
0
  Assert((objname != NULL) == (objargs != NULL));
4949
0
  if (objname)
4950
0
  {
4951
0
    *objname = NIL;
4952
0
    *objargs = NIL;
4953
0
  }
4954
4955
0
  switch (object->classId)
4956
0
  {
4957
0
    case RelationRelationId:
4958
0
      {
4959
0
        char     *attr = NULL;
4960
4961
        /*
4962
         * Check for the attribute first, so as if it is missing we
4963
         * can skip the entire relation description.
4964
         */
4965
0
        if (object->objectSubId != 0)
4966
0
        {
4967
0
          attr = get_attname(object->objectId,
4968
0
                     object->objectSubId,
4969
0
                     missing_ok);
4970
4971
0
          if (missing_ok && attr == NULL)
4972
0
            break;
4973
0
        }
4974
4975
0
        getRelationIdentity(&buffer, object->objectId, objname,
4976
0
                  missing_ok);
4977
0
        if (objname && *objname == NIL)
4978
0
          break;
4979
4980
0
        if (attr)
4981
0
        {
4982
0
          appendStringInfo(&buffer, ".%s",
4983
0
                   quote_identifier(attr));
4984
0
          if (objname)
4985
0
            *objname = lappend(*objname, attr);
4986
0
        }
4987
0
      }
4988
0
      break;
4989
4990
0
    case ProcedureRelationId:
4991
0
      {
4992
0
        uint16    flags = FORMAT_PROC_FORCE_QUALIFY | FORMAT_PROC_INVALID_AS_NULL;
4993
0
        char     *proname = format_procedure_extended(object->objectId,
4994
0
                                flags);
4995
4996
0
        if (proname == NULL)
4997
0
          break;
4998
4999
0
        appendStringInfoString(&buffer, proname);
5000
0
        if (objname)
5001
0
          format_procedure_parts(object->objectId, objname, objargs,
5002
0
                       missing_ok);
5003
0
        break;
5004
0
      }
5005
5006
0
    case TypeRelationId:
5007
0
      {
5008
0
        uint16    flags = FORMAT_TYPE_INVALID_AS_NULL | FORMAT_TYPE_FORCE_QUALIFY;
5009
0
        char     *typeout;
5010
5011
0
        typeout = format_type_extended(object->objectId, -1, flags);
5012
5013
0
        if (typeout == NULL)
5014
0
          break;
5015
5016
0
        appendStringInfoString(&buffer, typeout);
5017
0
        if (objname)
5018
0
          *objname = list_make1(typeout);
5019
0
      }
5020
0
      break;
5021
5022
0
    case CastRelationId:
5023
0
      {
5024
0
        Relation  castRel;
5025
0
        HeapTuple tup;
5026
0
        Form_pg_cast castForm;
5027
5028
0
        castRel = table_open(CastRelationId, AccessShareLock);
5029
5030
0
        tup = get_catalog_object_by_oid(castRel, Anum_pg_cast_oid,
5031
0
                        object->objectId);
5032
5033
0
        if (!HeapTupleIsValid(tup))
5034
0
        {
5035
0
          if (!missing_ok)
5036
0
            elog(ERROR, "could not find tuple for cast %u",
5037
0
               object->objectId);
5038
5039
0
          table_close(castRel, AccessShareLock);
5040
0
          break;
5041
0
        }
5042
5043
0
        castForm = (Form_pg_cast) GETSTRUCT(tup);
5044
5045
0
        appendStringInfo(&buffer, "(%s AS %s)",
5046
0
                 format_type_be_qualified(castForm->castsource),
5047
0
                 format_type_be_qualified(castForm->casttarget));
5048
5049
0
        if (objname)
5050
0
        {
5051
0
          *objname = list_make1(format_type_be_qualified(castForm->castsource));
5052
0
          *objargs = list_make1(format_type_be_qualified(castForm->casttarget));
5053
0
        }
5054
5055
0
        table_close(castRel, AccessShareLock);
5056
0
        break;
5057
0
      }
5058
5059
0
    case CollationRelationId:
5060
0
      {
5061
0
        HeapTuple collTup;
5062
0
        Form_pg_collation coll;
5063
0
        char     *schema;
5064
5065
0
        collTup = SearchSysCache1(COLLOID,
5066
0
                      ObjectIdGetDatum(object->objectId));
5067
0
        if (!HeapTupleIsValid(collTup))
5068
0
        {
5069
0
          if (!missing_ok)
5070
0
            elog(ERROR, "cache lookup failed for collation %u",
5071
0
               object->objectId);
5072
0
          break;
5073
0
        }
5074
0
        coll = (Form_pg_collation) GETSTRUCT(collTup);
5075
0
        schema = get_namespace_name_or_temp(coll->collnamespace);
5076
0
        appendStringInfoString(&buffer,
5077
0
                     quote_qualified_identifier(schema,
5078
0
                                  NameStr(coll->collname)));
5079
0
        if (objname)
5080
0
          *objname = list_make2(schema,
5081
0
                      pstrdup(NameStr(coll->collname)));
5082
0
        ReleaseSysCache(collTup);
5083
0
        break;
5084
0
      }
5085
5086
0
    case ConstraintRelationId:
5087
0
      {
5088
0
        HeapTuple conTup;
5089
0
        Form_pg_constraint con;
5090
5091
0
        conTup = SearchSysCache1(CONSTROID,
5092
0
                     ObjectIdGetDatum(object->objectId));
5093
0
        if (!HeapTupleIsValid(conTup))
5094
0
        {
5095
0
          if (!missing_ok)
5096
0
            elog(ERROR, "cache lookup failed for constraint %u",
5097
0
               object->objectId);
5098
0
          break;
5099
0
        }
5100
0
        con = (Form_pg_constraint) GETSTRUCT(conTup);
5101
5102
0
        if (OidIsValid(con->conrelid))
5103
0
        {
5104
0
          appendStringInfo(&buffer, "%s on ",
5105
0
                   quote_identifier(NameStr(con->conname)));
5106
0
          getRelationIdentity(&buffer, con->conrelid, objname,
5107
0
                    false);
5108
0
          if (objname)
5109
0
            *objname = lappend(*objname, pstrdup(NameStr(con->conname)));
5110
0
        }
5111
0
        else
5112
0
        {
5113
0
          ObjectAddress domain;
5114
5115
0
          Assert(OidIsValid(con->contypid));
5116
0
          domain.classId = TypeRelationId;
5117
0
          domain.objectId = con->contypid;
5118
0
          domain.objectSubId = 0;
5119
5120
0
          appendStringInfo(&buffer, "%s on %s",
5121
0
                   quote_identifier(NameStr(con->conname)),
5122
0
                   getObjectIdentityParts(&domain, objname,
5123
0
                              objargs, false));
5124
5125
0
          if (objname)
5126
0
            *objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
5127
0
        }
5128
5129
0
        ReleaseSysCache(conTup);
5130
0
        break;
5131
0
      }
5132
5133
0
    case ConversionRelationId:
5134
0
      {
5135
0
        HeapTuple conTup;
5136
0
        Form_pg_conversion conForm;
5137
0
        char     *schema;
5138
5139
0
        conTup = SearchSysCache1(CONVOID,
5140
0
                     ObjectIdGetDatum(object->objectId));
5141
0
        if (!HeapTupleIsValid(conTup))
5142
0
        {
5143
0
          if (!missing_ok)
5144
0
            elog(ERROR, "cache lookup failed for conversion %u",
5145
0
               object->objectId);
5146
0
          break;
5147
0
        }
5148
0
        conForm = (Form_pg_conversion) GETSTRUCT(conTup);
5149
0
        schema = get_namespace_name_or_temp(conForm->connamespace);
5150
0
        appendStringInfoString(&buffer,
5151
0
                     quote_qualified_identifier(schema,
5152
0
                                  NameStr(conForm->conname)));
5153
0
        if (objname)
5154
0
          *objname = list_make2(schema,
5155
0
                      pstrdup(NameStr(conForm->conname)));
5156
0
        ReleaseSysCache(conTup);
5157
0
        break;
5158
0
      }
5159
5160
0
    case AttrDefaultRelationId:
5161
0
      {
5162
0
        ObjectAddress colobject;
5163
5164
0
        colobject = GetAttrDefaultColumnAddress(object->objectId);
5165
5166
0
        if (!OidIsValid(colobject.objectId))
5167
0
        {
5168
0
          if (!missing_ok)
5169
0
            elog(ERROR, "could not find tuple for attrdef %u",
5170
0
               object->objectId);
5171
0
          break;
5172
0
        }
5173
5174
0
        appendStringInfo(&buffer, "for %s",
5175
0
                 getObjectIdentityParts(&colobject,
5176
0
                            objname, objargs,
5177
0
                            false));
5178
0
        break;
5179
0
      }
5180
5181
0
    case LanguageRelationId:
5182
0
      {
5183
0
        HeapTuple langTup;
5184
0
        Form_pg_language langForm;
5185
5186
0
        langTup = SearchSysCache1(LANGOID,
5187
0
                      ObjectIdGetDatum(object->objectId));
5188
0
        if (!HeapTupleIsValid(langTup))
5189
0
        {
5190
0
          if (!missing_ok)
5191
0
            elog(ERROR, "cache lookup failed for language %u",
5192
0
               object->objectId);
5193
0
          break;
5194
0
        }
5195
0
        langForm = (Form_pg_language) GETSTRUCT(langTup);
5196
0
        appendStringInfoString(&buffer,
5197
0
                     quote_identifier(NameStr(langForm->lanname)));
5198
0
        if (objname)
5199
0
          *objname = list_make1(pstrdup(NameStr(langForm->lanname)));
5200
0
        ReleaseSysCache(langTup);
5201
0
        break;
5202
0
      }
5203
5204
0
    case LargeObjectRelationId:
5205
0
      if (!LargeObjectExists(object->objectId))
5206
0
        break;
5207
0
      appendStringInfo(&buffer, "%u",
5208
0
               object->objectId);
5209
0
      if (objname)
5210
0
        *objname = list_make1(psprintf("%u", object->objectId));
5211
0
      break;
5212
5213
0
    case OperatorRelationId:
5214
0
      {
5215
0
        uint16    flags = FORMAT_OPERATOR_FORCE_QUALIFY | FORMAT_OPERATOR_INVALID_AS_NULL;
5216
0
        char     *oprname = format_operator_extended(object->objectId,
5217
0
                                 flags);
5218
5219
0
        if (oprname == NULL)
5220
0
          break;
5221
5222
0
        appendStringInfoString(&buffer, oprname);
5223
0
        if (objname)
5224
0
          format_operator_parts(object->objectId, objname, objargs, missing_ok);
5225
0
        break;
5226
0
      }
5227
5228
0
    case OperatorClassRelationId:
5229
0
      {
5230
0
        HeapTuple opcTup;
5231
0
        Form_pg_opclass opcForm;
5232
0
        HeapTuple amTup;
5233
0
        Form_pg_am  amForm;
5234
0
        char     *schema;
5235
5236
0
        opcTup = SearchSysCache1(CLAOID,
5237
0
                     ObjectIdGetDatum(object->objectId));
5238
0
        if (!HeapTupleIsValid(opcTup))
5239
0
        {
5240
0
          if (!missing_ok)
5241
0
            elog(ERROR, "cache lookup failed for opclass %u",
5242
0
               object->objectId);
5243
0
          break;
5244
0
        }
5245
0
        opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
5246
0
        schema = get_namespace_name_or_temp(opcForm->opcnamespace);
5247
5248
0
        amTup = SearchSysCache1(AMOID,
5249
0
                    ObjectIdGetDatum(opcForm->opcmethod));
5250
0
        if (!HeapTupleIsValid(amTup))
5251
0
          elog(ERROR, "cache lookup failed for access method %u",
5252
0
             opcForm->opcmethod);
5253
0
        amForm = (Form_pg_am) GETSTRUCT(amTup);
5254
5255
0
        appendStringInfo(&buffer, "%s USING %s",
5256
0
                 quote_qualified_identifier(schema,
5257
0
                              NameStr(opcForm->opcname)),
5258
0
                 quote_identifier(NameStr(amForm->amname)));
5259
0
        if (objname)
5260
0
          *objname = list_make3(pstrdup(NameStr(amForm->amname)),
5261
0
                      schema,
5262
0
                      pstrdup(NameStr(opcForm->opcname)));
5263
5264
0
        ReleaseSysCache(amTup);
5265
0
        ReleaseSysCache(opcTup);
5266
0
        break;
5267
0
      }
5268
5269
0
    case OperatorFamilyRelationId:
5270
0
      getOpFamilyIdentity(&buffer, object->objectId, objname,
5271
0
                missing_ok);
5272
0
      break;
5273
5274
0
    case AccessMethodRelationId:
5275
0
      {
5276
0
        char     *amname;
5277
5278
0
        amname = get_am_name(object->objectId);
5279
0
        if (!amname)
5280
0
        {
5281
0
          if (!missing_ok)
5282
0
            elog(ERROR, "cache lookup failed for access method %u",
5283
0
               object->objectId);
5284
0
          break;
5285
0
        }
5286
0
        appendStringInfoString(&buffer, quote_identifier(amname));
5287
0
        if (objname)
5288
0
          *objname = list_make1(amname);
5289
0
      }
5290
0
      break;
5291
5292
0
    case AccessMethodOperatorRelationId:
5293
0
      {
5294
0
        Relation  amopDesc;
5295
0
        HeapTuple tup;
5296
0
        ScanKeyData skey[1];
5297
0
        SysScanDesc amscan;
5298
0
        Form_pg_amop amopForm;
5299
0
        StringInfoData opfam;
5300
0
        char     *ltype;
5301
0
        char     *rtype;
5302
5303
0
        amopDesc = table_open(AccessMethodOperatorRelationId,
5304
0
                    AccessShareLock);
5305
5306
0
        ScanKeyInit(&skey[0],
5307
0
              Anum_pg_amop_oid,
5308
0
              BTEqualStrategyNumber, F_OIDEQ,
5309
0
              ObjectIdGetDatum(object->objectId));
5310
5311
0
        amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
5312
0
                      NULL, 1, skey);
5313
5314
0
        tup = systable_getnext(amscan);
5315
5316
0
        if (!HeapTupleIsValid(tup))
5317
0
        {
5318
0
          if (!missing_ok)
5319
0
            elog(ERROR, "could not find tuple for amop entry %u",
5320
0
               object->objectId);
5321
5322
0
          systable_endscan(amscan);
5323
0
          table_close(amopDesc, AccessShareLock);
5324
0
          break;
5325
0
        }
5326
5327
0
        amopForm = (Form_pg_amop) GETSTRUCT(tup);
5328
5329
0
        initStringInfo(&opfam);
5330
0
        getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname,
5331
0
                  false);
5332
5333
0
        ltype = format_type_be_qualified(amopForm->amoplefttype);
5334
0
        rtype = format_type_be_qualified(amopForm->amoprighttype);
5335
5336
0
        if (objname)
5337
0
        {
5338
0
          *objname = lappend(*objname,
5339
0
                     psprintf("%d", amopForm->amopstrategy));
5340
0
          *objargs = list_make2(ltype, rtype);
5341
0
        }
5342
5343
0
        appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
5344
0
                 amopForm->amopstrategy,
5345
0
                 ltype, rtype, opfam.data);
5346
5347
0
        pfree(opfam.data);
5348
5349
0
        systable_endscan(amscan);
5350
0
        table_close(amopDesc, AccessShareLock);
5351
0
        break;
5352
0
      }
5353
5354
0
    case AccessMethodProcedureRelationId:
5355
0
      {
5356
0
        Relation  amprocDesc;
5357
0
        ScanKeyData skey[1];
5358
0
        SysScanDesc amscan;
5359
0
        HeapTuple tup;
5360
0
        Form_pg_amproc amprocForm;
5361
0
        StringInfoData opfam;
5362
0
        char     *ltype;
5363
0
        char     *rtype;
5364
5365
0
        amprocDesc = table_open(AccessMethodProcedureRelationId,
5366
0
                    AccessShareLock);
5367
5368
0
        ScanKeyInit(&skey[0],
5369
0
              Anum_pg_amproc_oid,
5370
0
              BTEqualStrategyNumber, F_OIDEQ,
5371
0
              ObjectIdGetDatum(object->objectId));
5372
5373
0
        amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
5374
0
                      NULL, 1, skey);
5375
5376
0
        tup = systable_getnext(amscan);
5377
5378
0
        if (!HeapTupleIsValid(tup))
5379
0
        {
5380
0
          if (!missing_ok)
5381
0
            elog(ERROR, "could not find tuple for amproc entry %u",
5382
0
               object->objectId);
5383
5384
0
          systable_endscan(amscan);
5385
0
          table_close(amprocDesc, AccessShareLock);
5386
0
          break;
5387
0
        }
5388
5389
0
        amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
5390
5391
0
        initStringInfo(&opfam);
5392
0
        getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname,
5393
0
                  false);
5394
5395
0
        ltype = format_type_be_qualified(amprocForm->amproclefttype);
5396
0
        rtype = format_type_be_qualified(amprocForm->amprocrighttype);
5397
5398
0
        if (objname)
5399
0
        {
5400
0
          *objname = lappend(*objname,
5401
0
                     psprintf("%d", amprocForm->amprocnum));
5402
0
          *objargs = list_make2(ltype, rtype);
5403
0
        }
5404
5405
0
        appendStringInfo(&buffer, "function %d (%s, %s) of %s",
5406
0
                 amprocForm->amprocnum,
5407
0
                 ltype, rtype, opfam.data);
5408
5409
0
        pfree(opfam.data);
5410
5411
0
        systable_endscan(amscan);
5412
0
        table_close(amprocDesc, AccessShareLock);
5413
0
        break;
5414
0
      }
5415
5416
0
    case RewriteRelationId:
5417
0
      {
5418
0
        Relation  ruleDesc;
5419
0
        HeapTuple tup;
5420
0
        Form_pg_rewrite rule;
5421
5422
0
        ruleDesc = table_open(RewriteRelationId, AccessShareLock);
5423
5424
0
        tup = get_catalog_object_by_oid(ruleDesc, Anum_pg_rewrite_oid,
5425
0
                        object->objectId);
5426
5427
0
        if (!HeapTupleIsValid(tup))
5428
0
        {
5429
0
          if (!missing_ok)
5430
0
            elog(ERROR, "could not find tuple for rule %u",
5431
0
               object->objectId);
5432
5433
0
          table_close(ruleDesc, AccessShareLock);
5434
0
          break;
5435
0
        }
5436
5437
0
        rule = (Form_pg_rewrite) GETSTRUCT(tup);
5438
5439
0
        appendStringInfo(&buffer, "%s on ",
5440
0
                 quote_identifier(NameStr(rule->rulename)));
5441
0
        getRelationIdentity(&buffer, rule->ev_class, objname, false);
5442
0
        if (objname)
5443
0
          *objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
5444
5445
0
        table_close(ruleDesc, AccessShareLock);
5446
0
        break;
5447
0
      }
5448
5449
0
    case TriggerRelationId:
5450
0
      {
5451
0
        Relation  trigDesc;
5452
0
        HeapTuple tup;
5453
0
        Form_pg_trigger trig;
5454
5455
0
        trigDesc = table_open(TriggerRelationId, AccessShareLock);
5456
5457
0
        tup = get_catalog_object_by_oid(trigDesc, Anum_pg_trigger_oid,
5458
0
                        object->objectId);
5459
5460
0
        if (!HeapTupleIsValid(tup))
5461
0
        {
5462
0
          if (!missing_ok)
5463
0
            elog(ERROR, "could not find tuple for trigger %u",
5464
0
               object->objectId);
5465
5466
0
          table_close(trigDesc, AccessShareLock);
5467
0
          break;
5468
0
        }
5469
5470
0
        trig = (Form_pg_trigger) GETSTRUCT(tup);
5471
5472
0
        appendStringInfo(&buffer, "%s on ",
5473
0
                 quote_identifier(NameStr(trig->tgname)));
5474
0
        getRelationIdentity(&buffer, trig->tgrelid, objname, false);
5475
0
        if (objname)
5476
0
          *objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
5477
5478
0
        table_close(trigDesc, AccessShareLock);
5479
0
        break;
5480
0
      }
5481
5482
0
    case NamespaceRelationId:
5483
0
      {
5484
0
        char     *nspname;
5485
5486
0
        nspname = get_namespace_name_or_temp(object->objectId);
5487
0
        if (!nspname)
5488
0
        {
5489
0
          if (!missing_ok)
5490
0
            elog(ERROR, "cache lookup failed for namespace %u",
5491
0
               object->objectId);
5492
0
          break;
5493
0
        }
5494
0
        appendStringInfoString(&buffer,
5495
0
                     quote_identifier(nspname));
5496
0
        if (objname)
5497
0
          *objname = list_make1(nspname);
5498
0
        break;
5499
0
      }
5500
5501
0
    case StatisticExtRelationId:
5502
0
      {
5503
0
        HeapTuple tup;
5504
0
        Form_pg_statistic_ext formStatistic;
5505
0
        char     *schema;
5506
5507
0
        tup = SearchSysCache1(STATEXTOID,
5508
0
                    ObjectIdGetDatum(object->objectId));
5509
0
        if (!HeapTupleIsValid(tup))
5510
0
        {
5511
0
          if (!missing_ok)
5512
0
            elog(ERROR, "cache lookup failed for statistics object %u",
5513
0
               object->objectId);
5514
0
          break;
5515
0
        }
5516
0
        formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup);
5517
0
        schema = get_namespace_name_or_temp(formStatistic->stxnamespace);
5518
0
        appendStringInfoString(&buffer,
5519
0
                     quote_qualified_identifier(schema,
5520
0
                                  NameStr(formStatistic->stxname)));
5521
0
        if (objname)
5522
0
          *objname = list_make2(schema,
5523
0
                      pstrdup(NameStr(formStatistic->stxname)));
5524
0
        ReleaseSysCache(tup);
5525
0
      }
5526
0
      break;
5527
5528
0
    case TSParserRelationId:
5529
0
      {
5530
0
        HeapTuple tup;
5531
0
        Form_pg_ts_parser formParser;
5532
0
        char     *schema;
5533
5534
0
        tup = SearchSysCache1(TSPARSEROID,
5535
0
                    ObjectIdGetDatum(object->objectId));
5536
0
        if (!HeapTupleIsValid(tup))
5537
0
        {
5538
0
          if (!missing_ok)
5539
0
            elog(ERROR, "cache lookup failed for text search parser %u",
5540
0
               object->objectId);
5541
0
          break;
5542
0
        }
5543
0
        formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
5544
0
        schema = get_namespace_name_or_temp(formParser->prsnamespace);
5545
0
        appendStringInfoString(&buffer,
5546
0
                     quote_qualified_identifier(schema,
5547
0
                                  NameStr(formParser->prsname)));
5548
0
        if (objname)
5549
0
          *objname = list_make2(schema,
5550
0
                      pstrdup(NameStr(formParser->prsname)));
5551
0
        ReleaseSysCache(tup);
5552
0
        break;
5553
0
      }
5554
5555
0
    case TSDictionaryRelationId:
5556
0
      {
5557
0
        HeapTuple tup;
5558
0
        Form_pg_ts_dict formDict;
5559
0
        char     *schema;
5560
5561
0
        tup = SearchSysCache1(TSDICTOID,
5562
0
                    ObjectIdGetDatum(object->objectId));
5563
0
        if (!HeapTupleIsValid(tup))
5564
0
        {
5565
0
          if (!missing_ok)
5566
0
            elog(ERROR, "cache lookup failed for text search dictionary %u",
5567
0
               object->objectId);
5568
0
          break;
5569
0
        }
5570
0
        formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
5571
0
        schema = get_namespace_name_or_temp(formDict->dictnamespace);
5572
0
        appendStringInfoString(&buffer,
5573
0
                     quote_qualified_identifier(schema,
5574
0
                                  NameStr(formDict->dictname)));
5575
0
        if (objname)
5576
0
          *objname = list_make2(schema,
5577
0
                      pstrdup(NameStr(formDict->dictname)));
5578
0
        ReleaseSysCache(tup);
5579
0
        break;
5580
0
      }
5581
5582
0
    case TSTemplateRelationId:
5583
0
      {
5584
0
        HeapTuple tup;
5585
0
        Form_pg_ts_template formTmpl;
5586
0
        char     *schema;
5587
5588
0
        tup = SearchSysCache1(TSTEMPLATEOID,
5589
0
                    ObjectIdGetDatum(object->objectId));
5590
0
        if (!HeapTupleIsValid(tup))
5591
0
        {
5592
0
          if (!missing_ok)
5593
0
            elog(ERROR, "cache lookup failed for text search template %u",
5594
0
               object->objectId);
5595
0
          break;
5596
0
        }
5597
0
        formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
5598
0
        schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
5599
0
        appendStringInfoString(&buffer,
5600
0
                     quote_qualified_identifier(schema,
5601
0
                                  NameStr(formTmpl->tmplname)));
5602
0
        if (objname)
5603
0
          *objname = list_make2(schema,
5604
0
                      pstrdup(NameStr(formTmpl->tmplname)));
5605
0
        ReleaseSysCache(tup);
5606
0
        break;
5607
0
      }
5608
5609
0
    case TSConfigRelationId:
5610
0
      {
5611
0
        HeapTuple tup;
5612
0
        Form_pg_ts_config formCfg;
5613
0
        char     *schema;
5614
5615
0
        tup = SearchSysCache1(TSCONFIGOID,
5616
0
                    ObjectIdGetDatum(object->objectId));
5617
0
        if (!HeapTupleIsValid(tup))
5618
0
        {
5619
0
          if (!missing_ok)
5620
0
            elog(ERROR, "cache lookup failed for text search configuration %u",
5621
0
               object->objectId);
5622
0
          break;
5623
0
        }
5624
0
        formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
5625
0
        schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
5626
0
        appendStringInfoString(&buffer,
5627
0
                     quote_qualified_identifier(schema,
5628
0
                                  NameStr(formCfg->cfgname)));
5629
0
        if (objname)
5630
0
          *objname = list_make2(schema,
5631
0
                      pstrdup(NameStr(formCfg->cfgname)));
5632
0
        ReleaseSysCache(tup);
5633
0
        break;
5634
0
      }
5635
5636
0
    case AuthIdRelationId:
5637
0
      {
5638
0
        char     *username;
5639
5640
0
        username = GetUserNameFromId(object->objectId, missing_ok);
5641
0
        if (!username)
5642
0
          break;
5643
0
        if (objname)
5644
0
          *objname = list_make1(username);
5645
0
        appendStringInfoString(&buffer,
5646
0
                     quote_identifier(username));
5647
0
        break;
5648
0
      }
5649
5650
0
    case AuthMemRelationId:
5651
0
      {
5652
0
        Relation  authMemDesc;
5653
0
        ScanKeyData skey[1];
5654
0
        SysScanDesc amscan;
5655
0
        HeapTuple tup;
5656
0
        Form_pg_auth_members amForm;
5657
5658
0
        authMemDesc = table_open(AuthMemRelationId,
5659
0
                     AccessShareLock);
5660
5661
0
        ScanKeyInit(&skey[0],
5662
0
              Anum_pg_auth_members_oid,
5663
0
              BTEqualStrategyNumber, F_OIDEQ,
5664
0
              ObjectIdGetDatum(object->objectId));
5665
5666
0
        amscan = systable_beginscan(authMemDesc, AuthMemOidIndexId, true,
5667
0
                      NULL, 1, skey);
5668
5669
0
        tup = systable_getnext(amscan);
5670
5671
0
        if (!HeapTupleIsValid(tup))
5672
0
        {
5673
0
          if (!missing_ok)
5674
0
            elog(ERROR, "could not find tuple for pg_auth_members entry %u",
5675
0
               object->objectId);
5676
5677
0
          systable_endscan(amscan);
5678
0
          table_close(authMemDesc, AccessShareLock);
5679
0
          break;
5680
0
        }
5681
5682
0
        amForm = (Form_pg_auth_members) GETSTRUCT(tup);
5683
5684
0
        appendStringInfo(&buffer, "membership of role %s in role %s",
5685
0
                 GetUserNameFromId(amForm->member, false),
5686
0
                 GetUserNameFromId(amForm->roleid, false));
5687
5688
0
        systable_endscan(amscan);
5689
0
        table_close(authMemDesc, AccessShareLock);
5690
0
        break;
5691
0
      }
5692
5693
0
    case DatabaseRelationId:
5694
0
      {
5695
0
        char     *datname;
5696
5697
0
        datname = get_database_name(object->objectId);
5698
0
        if (!datname)
5699
0
        {
5700
0
          if (!missing_ok)
5701
0
            elog(ERROR, "cache lookup failed for database %u",
5702
0
               object->objectId);
5703
0
          break;
5704
0
        }
5705
0
        if (objname)
5706
0
          *objname = list_make1(datname);
5707
0
        appendStringInfoString(&buffer,
5708
0
                     quote_identifier(datname));
5709
0
        break;
5710
0
      }
5711
5712
0
    case TableSpaceRelationId:
5713
0
      {
5714
0
        char     *tblspace;
5715
5716
0
        tblspace = get_tablespace_name(object->objectId);
5717
0
        if (!tblspace)
5718
0
        {
5719
0
          if (!missing_ok)
5720
0
            elog(ERROR, "cache lookup failed for tablespace %u",
5721
0
               object->objectId);
5722
0
          break;
5723
0
        }
5724
0
        if (objname)
5725
0
          *objname = list_make1(tblspace);
5726
0
        appendStringInfoString(&buffer,
5727
0
                     quote_identifier(tblspace));
5728
0
        break;
5729
0
      }
5730
5731
0
    case ForeignDataWrapperRelationId:
5732
0
      {
5733
0
        ForeignDataWrapper *fdw;
5734
5735
0
        fdw = GetForeignDataWrapperExtended(object->objectId,
5736
0
                          missing_ok);
5737
0
        if (fdw)
5738
0
        {
5739
0
          appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
5740
0
          if (objname)
5741
0
            *objname = list_make1(pstrdup(fdw->fdwname));
5742
0
        }
5743
0
        break;
5744
0
      }
5745
5746
0
    case ForeignServerRelationId:
5747
0
      {
5748
0
        ForeignServer *srv;
5749
5750
0
        srv = GetForeignServerExtended(object->objectId,
5751
0
                         missing_ok);
5752
0
        if (srv)
5753
0
        {
5754
0
          appendStringInfoString(&buffer,
5755
0
                       quote_identifier(srv->servername));
5756
0
          if (objname)
5757
0
            *objname = list_make1(pstrdup(srv->servername));
5758
0
        }
5759
0
        break;
5760
0
      }
5761
5762
0
    case UserMappingRelationId:
5763
0
      {
5764
0
        HeapTuple tup;
5765
0
        Oid     useid;
5766
0
        Form_pg_user_mapping umform;
5767
0
        ForeignServer *srv;
5768
0
        const char *usename;
5769
5770
0
        tup = SearchSysCache1(USERMAPPINGOID,
5771
0
                    ObjectIdGetDatum(object->objectId));
5772
0
        if (!HeapTupleIsValid(tup))
5773
0
        {
5774
0
          if (!missing_ok)
5775
0
            elog(ERROR, "cache lookup failed for user mapping %u",
5776
0
               object->objectId);
5777
0
          break;
5778
0
        }
5779
0
        umform = (Form_pg_user_mapping) GETSTRUCT(tup);
5780
0
        useid = umform->umuser;
5781
0
        srv = GetForeignServer(umform->umserver);
5782
5783
0
        ReleaseSysCache(tup);
5784
5785
0
        if (OidIsValid(useid))
5786
0
          usename = GetUserNameFromId(useid, false);
5787
0
        else
5788
0
          usename = "public";
5789
5790
0
        if (objname)
5791
0
        {
5792
0
          *objname = list_make1(pstrdup(usename));
5793
0
          *objargs = list_make1(pstrdup(srv->servername));
5794
0
        }
5795
5796
0
        appendStringInfo(&buffer, "%s on server %s",
5797
0
                 quote_identifier(usename),
5798
0
                 srv->servername);
5799
0
        break;
5800
0
      }
5801
5802
0
    case DefaultAclRelationId:
5803
0
      {
5804
0
        Relation  defaclrel;
5805
0
        ScanKeyData skey[1];
5806
0
        SysScanDesc rcscan;
5807
0
        HeapTuple tup;
5808
0
        Form_pg_default_acl defacl;
5809
0
        char     *schema;
5810
0
        char     *username;
5811
5812
0
        defaclrel = table_open(DefaultAclRelationId, AccessShareLock);
5813
5814
0
        ScanKeyInit(&skey[0],
5815
0
              Anum_pg_default_acl_oid,
5816
0
              BTEqualStrategyNumber, F_OIDEQ,
5817
0
              ObjectIdGetDatum(object->objectId));
5818
5819
0
        rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
5820
0
                      true, NULL, 1, skey);
5821
5822
0
        tup = systable_getnext(rcscan);
5823
5824
0
        if (!HeapTupleIsValid(tup))
5825
0
        {
5826
0
          if (!missing_ok)
5827
0
            elog(ERROR, "could not find tuple for default ACL %u",
5828
0
               object->objectId);
5829
5830
0
          systable_endscan(rcscan);
5831
0
          table_close(defaclrel, AccessShareLock);
5832
0
          break;
5833
0
        }
5834
5835
0
        defacl = (Form_pg_default_acl) GETSTRUCT(tup);
5836
5837
0
        username = GetUserNameFromId(defacl->defaclrole, false);
5838
0
        appendStringInfo(&buffer,
5839
0
                 "for role %s",
5840
0
                 quote_identifier(username));
5841
5842
0
        if (OidIsValid(defacl->defaclnamespace))
5843
0
        {
5844
0
          schema = get_namespace_name_or_temp(defacl->defaclnamespace);
5845
0
          appendStringInfo(&buffer,
5846
0
                   " in schema %s",
5847
0
                   quote_identifier(schema));
5848
0
        }
5849
0
        else
5850
0
          schema = NULL;
5851
5852
0
        switch (defacl->defaclobjtype)
5853
0
        {
5854
0
          case DEFACLOBJ_RELATION:
5855
0
            appendStringInfoString(&buffer,
5856
0
                         " on tables");
5857
0
            break;
5858
0
          case DEFACLOBJ_SEQUENCE:
5859
0
            appendStringInfoString(&buffer,
5860
0
                         " on sequences");
5861
0
            break;
5862
0
          case DEFACLOBJ_FUNCTION:
5863
0
            appendStringInfoString(&buffer,
5864
0
                         " on functions");
5865
0
            break;
5866
0
          case DEFACLOBJ_TYPE:
5867
0
            appendStringInfoString(&buffer,
5868
0
                         " on types");
5869
0
            break;
5870
0
          case DEFACLOBJ_NAMESPACE:
5871
0
            appendStringInfoString(&buffer,
5872
0
                         " on schemas");
5873
0
            break;
5874
0
          case DEFACLOBJ_LARGEOBJECT:
5875
0
            appendStringInfoString(&buffer,
5876
0
                         " on large objects");
5877
0
            break;
5878
0
        }
5879
5880
0
        if (objname)
5881
0
        {
5882
0
          *objname = list_make1(username);
5883
0
          if (schema)
5884
0
            *objname = lappend(*objname, schema);
5885
0
          *objargs = list_make1(psprintf("%c", defacl->defaclobjtype));
5886
0
        }
5887
5888
0
        systable_endscan(rcscan);
5889
0
        table_close(defaclrel, AccessShareLock);
5890
0
        break;
5891
0
      }
5892
5893
0
    case ExtensionRelationId:
5894
0
      {
5895
0
        char     *extname;
5896
5897
0
        extname = get_extension_name(object->objectId);
5898
0
        if (!extname)
5899
0
        {
5900
0
          if (!missing_ok)
5901
0
            elog(ERROR, "cache lookup failed for extension %u",
5902
0
               object->objectId);
5903
0
          break;
5904
0
        }
5905
0
        appendStringInfoString(&buffer, quote_identifier(extname));
5906
0
        if (objname)
5907
0
          *objname = list_make1(extname);
5908
0
        break;
5909
0
      }
5910
5911
0
    case EventTriggerRelationId:
5912
0
      {
5913
0
        HeapTuple tup;
5914
0
        Form_pg_event_trigger trigForm;
5915
0
        char     *evtname;
5916
5917
0
        tup = SearchSysCache1(EVENTTRIGGEROID,
5918
0
                    ObjectIdGetDatum(object->objectId));
5919
0
        if (!HeapTupleIsValid(tup))
5920
0
        {
5921
0
          if (!missing_ok)
5922
0
            elog(ERROR, "cache lookup failed for event trigger %u",
5923
0
               object->objectId);
5924
0
          break;
5925
0
        }
5926
0
        trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
5927
0
        evtname = pstrdup(NameStr(trigForm->evtname));
5928
0
        appendStringInfoString(&buffer, quote_identifier(evtname));
5929
0
        if (objname)
5930
0
          *objname = list_make1(evtname);
5931
0
        ReleaseSysCache(tup);
5932
0
        break;
5933
0
      }
5934
5935
0
    case ParameterAclRelationId:
5936
0
      {
5937
0
        HeapTuple tup;
5938
0
        Datum   nameDatum;
5939
0
        char     *parname;
5940
5941
0
        tup = SearchSysCache1(PARAMETERACLOID,
5942
0
                    ObjectIdGetDatum(object->objectId));
5943
0
        if (!HeapTupleIsValid(tup))
5944
0
        {
5945
0
          if (!missing_ok)
5946
0
            elog(ERROR, "cache lookup failed for parameter ACL %u",
5947
0
               object->objectId);
5948
0
          break;
5949
0
        }
5950
0
        nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tup,
5951
0
                           Anum_pg_parameter_acl_parname);
5952
0
        parname = TextDatumGetCString(nameDatum);
5953
0
        appendStringInfoString(&buffer, parname);
5954
0
        if (objname)
5955
0
          *objname = list_make1(parname);
5956
0
        ReleaseSysCache(tup);
5957
0
        break;
5958
0
      }
5959
5960
0
    case PolicyRelationId:
5961
0
      {
5962
0
        Relation  polDesc;
5963
0
        HeapTuple tup;
5964
0
        Form_pg_policy policy;
5965
5966
0
        polDesc = table_open(PolicyRelationId, AccessShareLock);
5967
5968
0
        tup = get_catalog_object_by_oid(polDesc, Anum_pg_policy_oid,
5969
0
                        object->objectId);
5970
5971
0
        if (!HeapTupleIsValid(tup))
5972
0
        {
5973
0
          if (!missing_ok)
5974
0
            elog(ERROR, "could not find tuple for policy %u",
5975
0
               object->objectId);
5976
5977
0
          table_close(polDesc, AccessShareLock);
5978
0
          break;
5979
0
        }
5980
5981
0
        policy = (Form_pg_policy) GETSTRUCT(tup);
5982
5983
0
        appendStringInfo(&buffer, "%s on ",
5984
0
                 quote_identifier(NameStr(policy->polname)));
5985
0
        getRelationIdentity(&buffer, policy->polrelid, objname, false);
5986
0
        if (objname)
5987
0
          *objname = lappend(*objname, pstrdup(NameStr(policy->polname)));
5988
5989
0
        table_close(polDesc, AccessShareLock);
5990
0
        break;
5991
0
      }
5992
5993
0
    case PublicationRelationId:
5994
0
      {
5995
0
        char     *pubname;
5996
5997
0
        pubname = get_publication_name(object->objectId, missing_ok);
5998
0
        if (pubname)
5999
0
        {
6000
0
          appendStringInfoString(&buffer,
6001
0
                       quote_identifier(pubname));
6002
0
          if (objname)
6003
0
            *objname = list_make1(pubname);
6004
0
        }
6005
0
        break;
6006
0
      }
6007
6008
0
    case PublicationNamespaceRelationId:
6009
0
      {
6010
0
        char     *pubname;
6011
0
        char     *nspname;
6012
6013
0
        if (!getPublicationSchemaInfo(object, missing_ok, &pubname,
6014
0
                        &nspname))
6015
0
          break;
6016
0
        appendStringInfo(&buffer, "%s in publication %s",
6017
0
                 nspname, pubname);
6018
6019
0
        if (objargs)
6020
0
          *objargs = list_make1(pubname);
6021
0
        else
6022
0
          pfree(pubname);
6023
6024
0
        if (objname)
6025
0
          *objname = list_make1(nspname);
6026
0
        else
6027
0
          pfree(nspname);
6028
6029
0
        break;
6030
0
      }
6031
6032
0
    case PublicationRelRelationId:
6033
0
      {
6034
0
        HeapTuple tup;
6035
0
        char     *pubname;
6036
0
        Form_pg_publication_rel prform;
6037
6038
0
        tup = SearchSysCache1(PUBLICATIONREL,
6039
0
                    ObjectIdGetDatum(object->objectId));
6040
0
        if (!HeapTupleIsValid(tup))
6041
0
        {
6042
0
          if (!missing_ok)
6043
0
            elog(ERROR, "cache lookup failed for publication table %u",
6044
0
               object->objectId);
6045
0
          break;
6046
0
        }
6047
6048
0
        prform = (Form_pg_publication_rel) GETSTRUCT(tup);
6049
0
        pubname = get_publication_name(prform->prpubid, false);
6050
6051
0
        getRelationIdentity(&buffer, prform->prrelid, objname, false);
6052
0
        if (prform->prexcept)
6053
0
          appendStringInfo(&buffer, " excluded from publication %s",
6054
0
                   pubname);
6055
0
        else
6056
0
          appendStringInfo(&buffer, " in publication %s", pubname);
6057
6058
0
        if (objargs)
6059
0
          *objargs = list_make1(pubname);
6060
6061
0
        ReleaseSysCache(tup);
6062
0
        break;
6063
0
      }
6064
6065
0
    case SubscriptionRelationId:
6066
0
      {
6067
0
        char     *subname;
6068
6069
0
        subname = get_subscription_name(object->objectId, missing_ok);
6070
0
        if (subname)
6071
0
        {
6072
0
          appendStringInfoString(&buffer,
6073
0
                       quote_identifier(subname));
6074
0
          if (objname)
6075
0
            *objname = list_make1(subname);
6076
0
        }
6077
0
        break;
6078
0
      }
6079
6080
0
    case TransformRelationId:
6081
0
      {
6082
0
        Relation  transformDesc;
6083
0
        HeapTuple tup;
6084
0
        Form_pg_transform transform;
6085
0
        char     *transformLang;
6086
0
        char     *transformType;
6087
6088
0
        transformDesc = table_open(TransformRelationId, AccessShareLock);
6089
6090
0
        tup = get_catalog_object_by_oid(transformDesc,
6091
0
                        Anum_pg_transform_oid,
6092
0
                        object->objectId);
6093
6094
0
        if (!HeapTupleIsValid(tup))
6095
0
        {
6096
0
          if (!missing_ok)
6097
0
            elog(ERROR, "could not find tuple for transform %u",
6098
0
               object->objectId);
6099
6100
0
          table_close(transformDesc, AccessShareLock);
6101
0
          break;
6102
0
        }
6103
6104
0
        transform = (Form_pg_transform) GETSTRUCT(tup);
6105
6106
0
        transformType = format_type_be_qualified(transform->trftype);
6107
0
        transformLang = get_language_name(transform->trflang, false);
6108
6109
0
        appendStringInfo(&buffer, "for %s language %s",
6110
0
                 transformType,
6111
0
                 transformLang);
6112
0
        if (objname)
6113
0
        {
6114
0
          *objname = list_make1(transformType);
6115
0
          *objargs = list_make1(pstrdup(transformLang));
6116
0
        }
6117
6118
0
        table_close(transformDesc, AccessShareLock);
6119
0
      }
6120
0
      break;
6121
6122
0
    default:
6123
0
      elog(ERROR, "unsupported object class: %u", object->classId);
6124
0
  }
6125
6126
0
  if (!missing_ok)
6127
0
  {
6128
    /*
6129
     * If a get_object_address() representation was requested, make sure
6130
     * we are providing one.  We don't check objargs, because many of the
6131
     * cases above leave it as NIL.
6132
     */
6133
0
    if (objname && *objname == NIL)
6134
0
      elog(ERROR, "requested object address for unsupported object class %u: text result \"%s\"",
6135
0
         object->classId, buffer.data);
6136
0
  }
6137
0
  else
6138
0
  {
6139
    /* an empty buffer is equivalent to no object found */
6140
0
    if (buffer.len == 0)
6141
0
    {
6142
0
      Assert((objname == NULL || *objname == NIL) &&
6143
0
           (objargs == NULL || *objargs == NIL));
6144
0
      return NULL;
6145
0
    }
6146
0
  }
6147
6148
0
  return buffer.data;
6149
0
}
6150
6151
static void
6152
getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
6153
          bool missing_ok)
6154
0
{
6155
0
  HeapTuple opfTup;
6156
0
  Form_pg_opfamily opfForm;
6157
0
  HeapTuple amTup;
6158
0
  Form_pg_am  amForm;
6159
0
  char     *schema;
6160
6161
0
  opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
6162
0
  if (!HeapTupleIsValid(opfTup))
6163
0
  {
6164
0
    if (!missing_ok)
6165
0
      elog(ERROR, "cache lookup failed for opfamily %u", opfid);
6166
0
    return;
6167
0
  }
6168
0
  opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
6169
6170
0
  amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
6171
0
  if (!HeapTupleIsValid(amTup))
6172
0
    elog(ERROR, "cache lookup failed for access method %u",
6173
0
       opfForm->opfmethod);
6174
0
  amForm = (Form_pg_am) GETSTRUCT(amTup);
6175
6176
0
  schema = get_namespace_name_or_temp(opfForm->opfnamespace);
6177
0
  appendStringInfo(buffer, "%s USING %s",
6178
0
           quote_qualified_identifier(schema,
6179
0
                        NameStr(opfForm->opfname)),
6180
0
           NameStr(amForm->amname));
6181
6182
0
  if (object)
6183
0
    *object = list_make3(pstrdup(NameStr(amForm->amname)),
6184
0
               pstrdup(schema),
6185
0
               pstrdup(NameStr(opfForm->opfname)));
6186
6187
0
  ReleaseSysCache(amTup);
6188
0
  ReleaseSysCache(opfTup);
6189
0
}
6190
6191
/*
6192
 * Append the relation identity (quoted qualified name) to the given
6193
 * StringInfo.
6194
 */
6195
static void
6196
getRelationIdentity(StringInfo buffer, Oid relid, List **object,
6197
          bool missing_ok)
6198
0
{
6199
0
  HeapTuple relTup;
6200
0
  Form_pg_class relForm;
6201
0
  char     *schema;
6202
6203
0
  relTup = SearchSysCache1(RELOID,
6204
0
               ObjectIdGetDatum(relid));
6205
0
  if (!HeapTupleIsValid(relTup))
6206
0
  {
6207
0
    if (!missing_ok)
6208
0
      elog(ERROR, "cache lookup failed for relation %u", relid);
6209
6210
0
    if (object)
6211
0
      *object = NIL;
6212
0
    return;
6213
0
  }
6214
0
  relForm = (Form_pg_class) GETSTRUCT(relTup);
6215
6216
0
  schema = get_namespace_name_or_temp(relForm->relnamespace);
6217
0
  appendStringInfoString(buffer,
6218
0
               quote_qualified_identifier(schema,
6219
0
                            NameStr(relForm->relname)));
6220
0
  if (object)
6221
0
    *object = list_make2(schema, pstrdup(NameStr(relForm->relname)));
6222
6223
0
  ReleaseSysCache(relTup);
6224
0
}
6225
6226
/*
6227
 * Auxiliary function to build a TEXT array out of a list of C-strings.
6228
 */
6229
ArrayType *
6230
strlist_to_textarray(List *list)
6231
0
{
6232
0
  ArrayType  *arr;
6233
0
  Datum    *datums;
6234
0
  bool     *nulls;
6235
0
  int     j = 0;
6236
0
  ListCell   *cell;
6237
0
  MemoryContext memcxt;
6238
0
  MemoryContext oldcxt;
6239
0
  int     lb[1];
6240
6241
  /* Work in a temp context; easier than individually pfree'ing the Datums */
6242
0
  memcxt = AllocSetContextCreate(CurrentMemoryContext,
6243
0
                   "strlist to array",
6244
0
                   ALLOCSET_DEFAULT_SIZES);
6245
0
  oldcxt = MemoryContextSwitchTo(memcxt);
6246
6247
0
  datums = palloc_array(Datum, list_length(list));
6248
0
  nulls = palloc_array(bool, list_length(list));
6249
6250
0
  foreach(cell, list)
6251
0
  {
6252
0
    char     *name = lfirst(cell);
6253
6254
0
    if (name)
6255
0
    {
6256
0
      nulls[j] = false;
6257
0
      datums[j++] = CStringGetTextDatum(name);
6258
0
    }
6259
0
    else
6260
0
      nulls[j] = true;
6261
0
  }
6262
6263
0
  MemoryContextSwitchTo(oldcxt);
6264
6265
0
  lb[0] = 1;
6266
0
  arr = construct_md_array(datums, nulls, 1, &j,
6267
0
               lb, TEXTOID, -1, false, TYPALIGN_INT);
6268
6269
0
  MemoryContextDelete(memcxt);
6270
6271
0
  return arr;
6272
0
}
6273
6274
/*
6275
 * get_relkind_objtype
6276
 *
6277
 * Return the object type for the relkind given by the caller.
6278
 *
6279
 * If an unexpected relkind is passed, we say OBJECT_TABLE rather than
6280
 * failing.  That's because this is mostly used for generating error messages
6281
 * for failed ACL checks on relations, and we'd rather produce a generic
6282
 * message saying "table" than fail entirely.
6283
 */
6284
ObjectType
6285
get_relkind_objtype(char relkind)
6286
0
{
6287
0
  switch (relkind)
6288
0
  {
6289
0
    case RELKIND_RELATION:
6290
0
    case RELKIND_PARTITIONED_TABLE:
6291
0
      return OBJECT_TABLE;
6292
0
    case RELKIND_INDEX:
6293
0
    case RELKIND_PARTITIONED_INDEX:
6294
0
      return OBJECT_INDEX;
6295
0
    case RELKIND_SEQUENCE:
6296
0
      return OBJECT_SEQUENCE;
6297
0
    case RELKIND_VIEW:
6298
0
      return OBJECT_VIEW;
6299
0
    case RELKIND_MATVIEW:
6300
0
      return OBJECT_MATVIEW;
6301
0
    case RELKIND_FOREIGN_TABLE:
6302
0
      return OBJECT_FOREIGN_TABLE;
6303
0
    case RELKIND_TOASTVALUE:
6304
0
      return OBJECT_TABLE;
6305
0
    default:
6306
      /* Per above, don't raise an error */
6307
0
      return OBJECT_TABLE;
6308
0
  }
6309
0
}