Coverage Report

Created: 2025-06-13 06:06

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