LCOV - code coverage report
Current view: top level - src/backend/catalog - objectaddress.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 2085 2343 89.0 %
Date: 2023-12-02 15:10:53 Functions: 49 51 96.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14