Header And Logo

PostgreSQL
| The world's most advanced open source database.

objectaddress.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * objectaddress.c
00004  *    functions for working with ObjectAddresses
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/catalog/objectaddress.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 
00016 #include "postgres.h"
00017 
00018 #include "access/htup_details.h"
00019 #include "access/sysattr.h"
00020 #include "catalog/catalog.h"
00021 #include "catalog/indexing.h"
00022 #include "catalog/objectaddress.h"
00023 #include "catalog/pg_amop.h"
00024 #include "catalog/pg_amproc.h"
00025 #include "catalog/pg_attrdef.h"
00026 #include "catalog/pg_authid.h"
00027 #include "catalog/pg_cast.h"
00028 #include "catalog/pg_default_acl.h"
00029 #include "catalog/pg_event_trigger.h"
00030 #include "catalog/pg_collation.h"
00031 #include "catalog/pg_constraint.h"
00032 #include "catalog/pg_conversion.h"
00033 #include "catalog/pg_database.h"
00034 #include "catalog/pg_extension.h"
00035 #include "catalog/pg_foreign_data_wrapper.h"
00036 #include "catalog/pg_foreign_server.h"
00037 #include "catalog/pg_language.h"
00038 #include "catalog/pg_largeobject.h"
00039 #include "catalog/pg_largeobject_metadata.h"
00040 #include "catalog/pg_namespace.h"
00041 #include "catalog/pg_opclass.h"
00042 #include "catalog/pg_opfamily.h"
00043 #include "catalog/pg_operator.h"
00044 #include "catalog/pg_proc.h"
00045 #include "catalog/pg_rewrite.h"
00046 #include "catalog/pg_tablespace.h"
00047 #include "catalog/pg_trigger.h"
00048 #include "catalog/pg_ts_config.h"
00049 #include "catalog/pg_ts_dict.h"
00050 #include "catalog/pg_ts_parser.h"
00051 #include "catalog/pg_ts_template.h"
00052 #include "catalog/pg_type.h"
00053 #include "catalog/pg_user_mapping.h"
00054 #include "commands/dbcommands.h"
00055 #include "commands/defrem.h"
00056 #include "commands/event_trigger.h"
00057 #include "commands/extension.h"
00058 #include "commands/proclang.h"
00059 #include "commands/tablespace.h"
00060 #include "commands/trigger.h"
00061 #include "foreign/foreign.h"
00062 #include "funcapi.h"
00063 #include "libpq/be-fsstubs.h"
00064 #include "miscadmin.h"
00065 #include "nodes/makefuncs.h"
00066 #include "parser/parse_func.h"
00067 #include "parser/parse_oper.h"
00068 #include "parser/parse_type.h"
00069 #include "rewrite/rewriteSupport.h"
00070 #include "storage/lmgr.h"
00071 #include "storage/sinval.h"
00072 #include "utils/builtins.h"
00073 #include "utils/fmgroids.h"
00074 #include "utils/lsyscache.h"
00075 #include "utils/syscache.h"
00076 #include "utils/tqual.h"
00077 
00078 /*
00079  * ObjectProperty
00080  *
00081  * This array provides a common part of system object structure; to help
00082  * consolidate routines to handle various kind of object classes.
00083  */
00084 typedef struct
00085 {
00086     Oid         class_oid;      /* oid of catalog */
00087     Oid         oid_index_oid;  /* oid of index on system oid column */
00088     int         oid_catcache_id;    /* id of catcache on system oid column  */
00089     int         name_catcache_id;       /* id of catcache on (name,namespace),
00090                                          * or (name) if the object does not
00091                                          * live in a namespace */
00092     AttrNumber  attnum_name;    /* attnum of name field */
00093     AttrNumber  attnum_namespace;       /* attnum of namespace field */
00094     AttrNumber  attnum_owner;   /* attnum of owner field */
00095     AttrNumber  attnum_acl;     /* attnum of acl field */
00096     AclObjectKind acl_kind;     /* ACL_KIND_* of this object type */
00097     bool        is_nsp_name_unique; /* can the nsp/name combination (or name
00098                                      * alone, if there's no namespace) be
00099                                      * considered an unique identifier for an
00100                                      * object of this class? */
00101 } ObjectPropertyType;
00102 
00103 static ObjectPropertyType ObjectProperty[] =
00104 {
00105     {
00106         CastRelationId,
00107         CastOidIndexId,
00108         -1,
00109         -1,
00110         InvalidAttrNumber,
00111         InvalidAttrNumber,
00112         InvalidAttrNumber,
00113         InvalidAttrNumber,
00114         -1,
00115         false
00116     },
00117     {
00118         CollationRelationId,
00119         CollationOidIndexId,
00120         COLLOID,
00121         -1,                     /* COLLNAMEENCNSP also takes encoding */
00122         Anum_pg_collation_collname,
00123         Anum_pg_collation_collnamespace,
00124         Anum_pg_collation_collowner,
00125         InvalidAttrNumber,
00126         ACL_KIND_COLLATION,
00127         true
00128     },
00129     {
00130         ConstraintRelationId,
00131         ConstraintOidIndexId,
00132         CONSTROID,
00133         -1,
00134         Anum_pg_constraint_conname,
00135         Anum_pg_constraint_connamespace,
00136         InvalidAttrNumber,
00137         InvalidAttrNumber,
00138         -1,
00139         false
00140     },
00141     {
00142         ConversionRelationId,
00143         ConversionOidIndexId,
00144         CONVOID,
00145         CONNAMENSP,
00146         Anum_pg_conversion_conname,
00147         Anum_pg_conversion_connamespace,
00148         Anum_pg_conversion_conowner,
00149         InvalidAttrNumber,
00150         ACL_KIND_CONVERSION,
00151         true
00152     },
00153     {
00154         DatabaseRelationId,
00155         DatabaseOidIndexId,
00156         DATABASEOID,
00157         -1,
00158         Anum_pg_database_datname,
00159         InvalidAttrNumber,
00160         Anum_pg_database_datdba,
00161         Anum_pg_database_datacl,
00162         ACL_KIND_DATABASE,
00163         true
00164     },
00165     {
00166         ExtensionRelationId,
00167         ExtensionOidIndexId,
00168         -1,
00169         -1,
00170         Anum_pg_extension_extname,
00171         InvalidAttrNumber,      /* extension doesn't belong to extnamespace */
00172         Anum_pg_extension_extowner,
00173         InvalidAttrNumber,
00174         ACL_KIND_EXTENSION,
00175         true
00176     },
00177     {
00178         ForeignDataWrapperRelationId,
00179         ForeignDataWrapperOidIndexId,
00180         FOREIGNDATAWRAPPEROID,
00181         FOREIGNDATAWRAPPERNAME,
00182         Anum_pg_foreign_data_wrapper_fdwname,
00183         InvalidAttrNumber,
00184         Anum_pg_foreign_data_wrapper_fdwowner,
00185         Anum_pg_foreign_data_wrapper_fdwacl,
00186         ACL_KIND_FDW,
00187         true
00188     },
00189     {
00190         ForeignServerRelationId,
00191         ForeignServerOidIndexId,
00192         FOREIGNSERVEROID,
00193         FOREIGNSERVERNAME,
00194         Anum_pg_foreign_server_srvname,
00195         InvalidAttrNumber,
00196         Anum_pg_foreign_server_srvowner,
00197         Anum_pg_foreign_server_srvacl,
00198         ACL_KIND_FOREIGN_SERVER,
00199         true
00200     },
00201     {
00202         ProcedureRelationId,
00203         ProcedureOidIndexId,
00204         PROCOID,
00205         -1,                     /* PROCNAMEARGSNSP also takes argument types */
00206         Anum_pg_proc_proname,
00207         Anum_pg_proc_pronamespace,
00208         Anum_pg_proc_proowner,
00209         Anum_pg_proc_proacl,
00210         ACL_KIND_PROC,
00211         false
00212     },
00213     {
00214         LanguageRelationId,
00215         LanguageOidIndexId,
00216         LANGOID,
00217         LANGNAME,
00218         Anum_pg_language_lanname,
00219         InvalidAttrNumber,
00220         Anum_pg_language_lanowner,
00221         Anum_pg_language_lanacl,
00222         ACL_KIND_LANGUAGE,
00223         true
00224     },
00225     {
00226         LargeObjectMetadataRelationId,
00227         LargeObjectMetadataOidIndexId,
00228         -1,
00229         -1,
00230         InvalidAttrNumber,
00231         InvalidAttrNumber,
00232         Anum_pg_largeobject_metadata_lomowner,
00233         Anum_pg_largeobject_metadata_lomacl,
00234         ACL_KIND_LARGEOBJECT,
00235         false
00236     },
00237     {
00238         OperatorClassRelationId,
00239         OpclassOidIndexId,
00240         CLAOID,
00241         -1,                     /* CLAAMNAMENSP also takes opcmethod */
00242         Anum_pg_opclass_opcname,
00243         Anum_pg_opclass_opcnamespace,
00244         Anum_pg_opclass_opcowner,
00245         InvalidAttrNumber,
00246         ACL_KIND_OPCLASS,
00247         true
00248     },
00249     {
00250         OperatorRelationId,
00251         OperatorOidIndexId,
00252         OPEROID,
00253         -1,                     /* OPERNAMENSP also takes left and right type */
00254         Anum_pg_operator_oprname,
00255         Anum_pg_operator_oprnamespace,
00256         Anum_pg_operator_oprowner,
00257         InvalidAttrNumber,
00258         ACL_KIND_OPER,
00259         false
00260     },
00261     {
00262         OperatorFamilyRelationId,
00263         OpfamilyOidIndexId,
00264         OPFAMILYOID,
00265         -1,                     /* OPFAMILYAMNAMENSP also takes opfmethod */
00266         Anum_pg_opfamily_opfname,
00267         Anum_pg_opfamily_opfnamespace,
00268         Anum_pg_opfamily_opfowner,
00269         InvalidAttrNumber,
00270         ACL_KIND_OPFAMILY,
00271         true
00272     },
00273     {
00274         AuthIdRelationId,
00275         AuthIdOidIndexId,
00276         AUTHOID,
00277         AUTHNAME,
00278         Anum_pg_authid_rolname,
00279         InvalidAttrNumber,
00280         InvalidAttrNumber,
00281         InvalidAttrNumber,
00282         -1,
00283         true
00284     },
00285     {
00286         RewriteRelationId,
00287         RewriteOidIndexId,
00288         -1,
00289         -1,
00290         Anum_pg_rewrite_rulename,
00291         InvalidAttrNumber,
00292         InvalidAttrNumber,
00293         InvalidAttrNumber,
00294         -1,
00295         false
00296     },
00297     {
00298         NamespaceRelationId,
00299         NamespaceOidIndexId,
00300         NAMESPACEOID,
00301         NAMESPACENAME,
00302         Anum_pg_namespace_nspname,
00303         InvalidAttrNumber,
00304         Anum_pg_namespace_nspowner,
00305         Anum_pg_namespace_nspacl,
00306         ACL_KIND_NAMESPACE,
00307         true
00308     },
00309     {
00310         RelationRelationId,
00311         ClassOidIndexId,
00312         RELOID,
00313         RELNAMENSP,
00314         Anum_pg_class_relname,
00315         Anum_pg_class_relnamespace,
00316         Anum_pg_class_relowner,
00317         Anum_pg_class_relacl,
00318         ACL_KIND_CLASS,
00319         true
00320     },
00321     {
00322         TableSpaceRelationId,
00323         TablespaceOidIndexId,
00324         TABLESPACEOID,
00325         -1,
00326         Anum_pg_tablespace_spcname,
00327         InvalidAttrNumber,
00328         Anum_pg_tablespace_spcowner,
00329         Anum_pg_tablespace_spcacl,
00330         ACL_KIND_TABLESPACE,
00331         true
00332     },
00333     {
00334         TriggerRelationId,
00335         TriggerOidIndexId,
00336         -1,
00337         -1,
00338         Anum_pg_trigger_tgname,
00339         InvalidAttrNumber,
00340         InvalidAttrNumber,
00341         InvalidAttrNumber,
00342         -1,
00343         false
00344     },
00345     {
00346         EventTriggerRelationId,
00347         EventTriggerOidIndexId,
00348         EVENTTRIGGEROID,
00349         EVENTTRIGGERNAME,
00350         Anum_pg_event_trigger_evtname,
00351         InvalidAttrNumber,
00352         Anum_pg_event_trigger_evtowner,
00353         InvalidAttrNumber,
00354         ACL_KIND_EVENT_TRIGGER,
00355         true
00356     },
00357     {
00358         TSConfigRelationId,
00359         TSConfigOidIndexId,
00360         TSCONFIGOID,
00361         TSCONFIGNAMENSP,
00362         Anum_pg_ts_config_cfgname,
00363         Anum_pg_ts_config_cfgnamespace,
00364         Anum_pg_ts_config_cfgowner,
00365         InvalidAttrNumber,
00366         ACL_KIND_TSCONFIGURATION,
00367         true
00368     },
00369     {
00370         TSDictionaryRelationId,
00371         TSDictionaryOidIndexId,
00372         TSDICTOID,
00373         TSDICTNAMENSP,
00374         Anum_pg_ts_dict_dictname,
00375         Anum_pg_ts_dict_dictnamespace,
00376         Anum_pg_ts_dict_dictowner,
00377         InvalidAttrNumber,
00378         ACL_KIND_TSDICTIONARY,
00379         true
00380     },
00381     {
00382         TSParserRelationId,
00383         TSParserOidIndexId,
00384         TSPARSEROID,
00385         TSPARSERNAMENSP,
00386         Anum_pg_ts_parser_prsname,
00387         Anum_pg_ts_parser_prsnamespace,
00388         InvalidAttrNumber,
00389         InvalidAttrNumber,
00390         -1,
00391         true
00392     },
00393     {
00394         TSTemplateRelationId,
00395         TSTemplateOidIndexId,
00396         TSTEMPLATEOID,
00397         TSTEMPLATENAMENSP,
00398         Anum_pg_ts_template_tmplname,
00399         Anum_pg_ts_template_tmplnamespace,
00400         InvalidAttrNumber,
00401         InvalidAttrNumber,
00402         -1,
00403         true,
00404     },
00405     {
00406         TypeRelationId,
00407         TypeOidIndexId,
00408         TYPEOID,
00409         TYPENAMENSP,
00410         Anum_pg_type_typname,
00411         Anum_pg_type_typnamespace,
00412         Anum_pg_type_typowner,
00413         Anum_pg_type_typacl,
00414         ACL_KIND_TYPE,
00415         true
00416     }
00417 };
00418 
00419 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
00420                                List *qualname, bool missing_ok);
00421 static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
00422                                List *objname, Relation *relp,
00423                                LOCKMODE lockmode, bool missing_ok);
00424 static ObjectAddress get_object_address_relobject(ObjectType objtype,
00425                              List *objname, Relation *relp, bool missing_ok);
00426 static ObjectAddress get_object_address_attribute(ObjectType objtype,
00427                              List *objname, Relation *relp,
00428                              LOCKMODE lockmode, bool missing_ok);
00429 static ObjectAddress get_object_address_type(ObjectType objtype,
00430                         List *objname, bool missing_ok);
00431 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
00432                         List *objargs, bool missing_ok);
00433 static ObjectPropertyType *get_object_property_data(Oid class_id);
00434 
00435 static void getRelationDescription(StringInfo buffer, Oid relid);
00436 static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
00437 static void getRelationTypeDescription(StringInfo buffer, Oid relid,
00438                            int32 objectSubId);
00439 static void getProcedureTypeDescription(StringInfo buffer, Oid procid);
00440 static void getConstraintTypeDescription(StringInfo buffer, Oid constroid);
00441 static void getOpFamilyIdentity(StringInfo buffer, Oid opfid);
00442 static void getRelationIdentity(StringInfo buffer, Oid relid);
00443 
00444 /*
00445  * Translate an object name and arguments (as passed by the parser) to an
00446  * ObjectAddress.
00447  *
00448  * The returned object will be locked using the specified lockmode.  If a
00449  * sub-object is looked up, the parent object will be locked instead.
00450  *
00451  * If the object is a relation or a child object of a relation (e.g. an
00452  * attribute or contraint), the relation is also opened and *relp receives
00453  * the open relcache entry pointer; otherwise, *relp is set to NULL.  This
00454  * is a bit grotty but it makes life simpler, since the caller will
00455  * typically need the relcache entry too.  Caller must close the relcache
00456  * entry when done with it.  The relation is locked with the specified lockmode
00457  * if the target object is the relation itself or an attribute, but for other
00458  * child objects, only AccessShareLock is acquired on the relation.
00459  *
00460  * We don't currently provide a function to release the locks acquired here;
00461  * typically, the lock must be held until commit to guard against a concurrent
00462  * drop operation.
00463  */
00464 ObjectAddress
00465 get_object_address(ObjectType objtype, List *objname, List *objargs,
00466                    Relation *relp, LOCKMODE lockmode, bool missing_ok)
00467 {
00468     ObjectAddress address;
00469     ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
00470     Relation    relation = NULL;
00471     uint64      inval_count;
00472 
00473     /* Some kind of lock must be taken. */
00474     Assert(lockmode != NoLock);
00475 
00476     for (;;)
00477     {
00478         /*
00479          * Remember this value, so that, after looking up the object name and
00480          * locking it, we can check whether any invalidation messages have
00481          * been processed that might require a do-over.
00482          */
00483         inval_count = SharedInvalidMessageCounter;
00484 
00485         /* Look up object address. */
00486         switch (objtype)
00487         {
00488             case OBJECT_INDEX:
00489             case OBJECT_SEQUENCE:
00490             case OBJECT_TABLE:
00491             case OBJECT_VIEW:
00492             case OBJECT_MATVIEW:
00493             case OBJECT_FOREIGN_TABLE:
00494                 address =
00495                     get_relation_by_qualified_name(objtype, objname,
00496                                                    &relation, lockmode,
00497                                                    missing_ok);
00498                 break;
00499             case OBJECT_COLUMN:
00500                 address =
00501                     get_object_address_attribute(objtype, objname,
00502                                                  &relation, lockmode,
00503                                                  missing_ok);
00504                 break;
00505             case OBJECT_RULE:
00506             case OBJECT_TRIGGER:
00507             case OBJECT_CONSTRAINT:
00508                 address = get_object_address_relobject(objtype, objname,
00509                                                        &relation, missing_ok);
00510                 break;
00511             case OBJECT_DATABASE:
00512             case OBJECT_EXTENSION:
00513             case OBJECT_TABLESPACE:
00514             case OBJECT_ROLE:
00515             case OBJECT_SCHEMA:
00516             case OBJECT_LANGUAGE:
00517             case OBJECT_FDW:
00518             case OBJECT_FOREIGN_SERVER:
00519             case OBJECT_EVENT_TRIGGER:
00520                 address = get_object_address_unqualified(objtype,
00521                                                          objname, missing_ok);
00522                 break;
00523             case OBJECT_TYPE:
00524             case OBJECT_DOMAIN:
00525                 address = get_object_address_type(objtype, objname, missing_ok);
00526                 break;
00527             case OBJECT_AGGREGATE:
00528                 address.classId = ProcedureRelationId;
00529                 address.objectId =
00530                     LookupAggNameTypeNames(objname, objargs, missing_ok);
00531                 address.objectSubId = 0;
00532                 break;
00533             case OBJECT_FUNCTION:
00534                 address.classId = ProcedureRelationId;
00535                 address.objectId =
00536                     LookupFuncNameTypeNames(objname, objargs, missing_ok);
00537                 address.objectSubId = 0;
00538                 break;
00539             case OBJECT_OPERATOR:
00540                 Assert(list_length(objargs) == 2);
00541                 address.classId = OperatorRelationId;
00542                 address.objectId =
00543                     LookupOperNameTypeNames(NULL, objname,
00544                                             (TypeName *) linitial(objargs),
00545                                             (TypeName *) lsecond(objargs),
00546                                             missing_ok, -1);
00547                 address.objectSubId = 0;
00548                 break;
00549             case OBJECT_COLLATION:
00550                 address.classId = CollationRelationId;
00551                 address.objectId = get_collation_oid(objname, missing_ok);
00552                 address.objectSubId = 0;
00553                 break;
00554             case OBJECT_CONVERSION:
00555                 address.classId = ConversionRelationId;
00556                 address.objectId = get_conversion_oid(objname, missing_ok);
00557                 address.objectSubId = 0;
00558                 break;
00559             case OBJECT_OPCLASS:
00560             case OBJECT_OPFAMILY:
00561                 address = get_object_address_opcf(objtype,
00562                                                objname, objargs, missing_ok);
00563                 break;
00564             case OBJECT_LARGEOBJECT:
00565                 Assert(list_length(objname) == 1);
00566                 address.classId = LargeObjectRelationId;
00567                 address.objectId = oidparse(linitial(objname));
00568                 address.objectSubId = 0;
00569                 if (!LargeObjectExists(address.objectId))
00570                 {
00571                     if (!missing_ok)
00572                         ereport(ERROR,
00573                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00574                                  errmsg("large object %u does not exist",
00575                                         address.objectId)));
00576                 }
00577                 break;
00578             case OBJECT_CAST:
00579                 {
00580                     TypeName   *sourcetype = (TypeName *) linitial(objname);
00581                     TypeName   *targettype = (TypeName *) linitial(objargs);
00582                     Oid         sourcetypeid = typenameTypeId(NULL, sourcetype);
00583                     Oid         targettypeid = typenameTypeId(NULL, targettype);
00584 
00585                     address.classId = CastRelationId;
00586                     address.objectId =
00587                         get_cast_oid(sourcetypeid, targettypeid, missing_ok);
00588                     address.objectSubId = 0;
00589                 }
00590                 break;
00591             case OBJECT_TSPARSER:
00592                 address.classId = TSParserRelationId;
00593                 address.objectId = get_ts_parser_oid(objname, missing_ok);
00594                 address.objectSubId = 0;
00595                 break;
00596             case OBJECT_TSDICTIONARY:
00597                 address.classId = TSDictionaryRelationId;
00598                 address.objectId = get_ts_dict_oid(objname, missing_ok);
00599                 address.objectSubId = 0;
00600                 break;
00601             case OBJECT_TSTEMPLATE:
00602                 address.classId = TSTemplateRelationId;
00603                 address.objectId = get_ts_template_oid(objname, missing_ok);
00604                 address.objectSubId = 0;
00605                 break;
00606             case OBJECT_TSCONFIGURATION:
00607                 address.classId = TSConfigRelationId;
00608                 address.objectId = get_ts_config_oid(objname, missing_ok);
00609                 address.objectSubId = 0;
00610                 break;
00611             default:
00612                 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
00613                 /* placate compiler, in case it thinks elog might return */
00614                 address.classId = InvalidOid;
00615                 address.objectId = InvalidOid;
00616                 address.objectSubId = 0;
00617         }
00618 
00619         /*
00620          * If we could not find the supplied object, return without locking.
00621          */
00622         if (!OidIsValid(address.objectId))
00623         {
00624             Assert(missing_ok);
00625             return address;
00626         }
00627 
00628         /*
00629          * If we're retrying, see if we got the same answer as last time.  If
00630          * so, we're done; if not, we locked the wrong thing, so give up our
00631          * lock.
00632          */
00633         if (OidIsValid(old_address.classId))
00634         {
00635             if (old_address.classId == address.classId
00636                 && old_address.objectId == address.objectId
00637                 && old_address.objectSubId == address.objectSubId)
00638                 break;
00639             if (old_address.classId != RelationRelationId)
00640             {
00641                 if (IsSharedRelation(old_address.classId))
00642                     UnlockSharedObject(old_address.classId,
00643                                        old_address.objectId,
00644                                        0, lockmode);
00645                 else
00646                     UnlockDatabaseObject(old_address.classId,
00647                                          old_address.objectId,
00648                                          0, lockmode);
00649             }
00650         }
00651 
00652         /*
00653          * If we're dealing with a relation or attribute, then the relation is
00654          * already locked.  Otherwise, we lock it now.
00655          */
00656         if (address.classId != RelationRelationId)
00657         {
00658             if (IsSharedRelation(address.classId))
00659                 LockSharedObject(address.classId, address.objectId, 0,
00660                                  lockmode);
00661             else
00662                 LockDatabaseObject(address.classId, address.objectId, 0,
00663                                    lockmode);
00664         }
00665 
00666         /*
00667          * At this point, we've resolved the name to an OID and locked the
00668          * corresponding database object.  However, it's possible that by the
00669          * time we acquire the lock on the object, concurrent DDL has modified
00670          * the database in such a way that the name we originally looked up no
00671          * longer resolves to that OID.
00672          *
00673          * We can be certain that this isn't an issue if (a) no shared
00674          * invalidation messages have been processed or (b) we've locked a
00675          * relation somewhere along the line.  All the relation name lookups
00676          * in this module ultimately use RangeVarGetRelid() to acquire a
00677          * relation lock, and that function protects against the same kinds of
00678          * races we're worried about here.  Even when operating on a
00679          * constraint, rule, or trigger, we still acquire AccessShareLock on
00680          * the relation, which is enough to freeze out any concurrent DDL.
00681          *
00682          * In all other cases, however, it's possible that the name we looked
00683          * up no longer refers to the object we locked, so we retry the lookup
00684          * and see whether we get the same answer.
00685          */
00686         if (inval_count == SharedInvalidMessageCounter || relation != NULL)
00687             break;
00688         old_address = address;
00689     }
00690 
00691     /* Return the object address and the relation. */
00692     *relp = relation;
00693     return address;
00694 }
00695 
00696 /*
00697  * Find an ObjectAddress for a type of object that is identified by an
00698  * unqualified name.
00699  */
00700 static ObjectAddress
00701 get_object_address_unqualified(ObjectType objtype,
00702                                List *qualname, bool missing_ok)
00703 {
00704     const char *name;
00705     ObjectAddress address;
00706 
00707     /*
00708      * The types of names handled by this function are not permitted to be
00709      * schema-qualified or catalog-qualified.
00710      */
00711     if (list_length(qualname) != 1)
00712     {
00713         const char *msg;
00714 
00715         switch (objtype)
00716         {
00717             case OBJECT_DATABASE:
00718                 msg = gettext_noop("database name cannot be qualified");
00719                 break;
00720             case OBJECT_EXTENSION:
00721                 msg = gettext_noop("extension name cannot be qualified");
00722                 break;
00723             case OBJECT_TABLESPACE:
00724                 msg = gettext_noop("tablespace name cannot be qualified");
00725                 break;
00726             case OBJECT_ROLE:
00727                 msg = gettext_noop("role name cannot be qualified");
00728                 break;
00729             case OBJECT_SCHEMA:
00730                 msg = gettext_noop("schema name cannot be qualified");
00731                 break;
00732             case OBJECT_LANGUAGE:
00733                 msg = gettext_noop("language name cannot be qualified");
00734                 break;
00735             case OBJECT_FDW:
00736                 msg = gettext_noop("foreign-data wrapper name cannot be qualified");
00737                 break;
00738             case OBJECT_FOREIGN_SERVER:
00739                 msg = gettext_noop("server name cannot be qualified");
00740                 break;
00741             case OBJECT_EVENT_TRIGGER:
00742                 msg = gettext_noop("event trigger name cannot be qualified");
00743                 break;
00744             default:
00745                 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
00746                 msg = NULL;     /* placate compiler */
00747         }
00748         ereport(ERROR,
00749                 (errcode(ERRCODE_SYNTAX_ERROR),
00750                  errmsg("%s", _(msg))));
00751     }
00752 
00753     /* Format is valid, extract the actual name. */
00754     name = strVal(linitial(qualname));
00755 
00756     /* Translate name to OID. */
00757     switch (objtype)
00758     {
00759         case OBJECT_DATABASE:
00760             address.classId = DatabaseRelationId;
00761             address.objectId = get_database_oid(name, missing_ok);
00762             address.objectSubId = 0;
00763             break;
00764         case OBJECT_EXTENSION:
00765             address.classId = ExtensionRelationId;
00766             address.objectId = get_extension_oid(name, missing_ok);
00767             address.objectSubId = 0;
00768             break;
00769         case OBJECT_TABLESPACE:
00770             address.classId = TableSpaceRelationId;
00771             address.objectId = get_tablespace_oid(name, missing_ok);
00772             address.objectSubId = 0;
00773             break;
00774         case OBJECT_ROLE:
00775             address.classId = AuthIdRelationId;
00776             address.objectId = get_role_oid(name, missing_ok);
00777             address.objectSubId = 0;
00778             break;
00779         case OBJECT_SCHEMA:
00780             address.classId = NamespaceRelationId;
00781             address.objectId = get_namespace_oid(name, missing_ok);
00782             address.objectSubId = 0;
00783             break;
00784         case OBJECT_LANGUAGE:
00785             address.classId = LanguageRelationId;
00786             address.objectId = get_language_oid(name, missing_ok);
00787             address.objectSubId = 0;
00788             break;
00789         case OBJECT_FDW:
00790             address.classId = ForeignDataWrapperRelationId;
00791             address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
00792             address.objectSubId = 0;
00793             break;
00794         case OBJECT_FOREIGN_SERVER:
00795             address.classId = ForeignServerRelationId;
00796             address.objectId = get_foreign_server_oid(name, missing_ok);
00797             address.objectSubId = 0;
00798             break;
00799         case OBJECT_EVENT_TRIGGER:
00800             address.classId = EventTriggerRelationId;
00801             address.objectId = get_event_trigger_oid(name, missing_ok);
00802             address.objectSubId = 0;
00803             break;
00804         default:
00805             elog(ERROR, "unrecognized objtype: %d", (int) objtype);
00806             /* placate compiler, which doesn't know elog won't return */
00807             address.classId = InvalidOid;
00808             address.objectId = InvalidOid;
00809             address.objectSubId = 0;
00810     }
00811 
00812     return address;
00813 }
00814 
00815 /*
00816  * Locate a relation by qualified name.
00817  */
00818 static ObjectAddress
00819 get_relation_by_qualified_name(ObjectType objtype, List *objname,
00820                                Relation *relp, LOCKMODE lockmode,
00821                                bool missing_ok)
00822 {
00823     Relation    relation;
00824     ObjectAddress address;
00825 
00826     address.classId = RelationRelationId;
00827     address.objectId = InvalidOid;
00828     address.objectSubId = 0;
00829 
00830     relation = relation_openrv_extended(makeRangeVarFromNameList(objname),
00831                                         lockmode, missing_ok);
00832     if (!relation)
00833         return address;
00834 
00835     switch (objtype)
00836     {
00837         case OBJECT_INDEX:
00838             if (relation->rd_rel->relkind != RELKIND_INDEX)
00839                 ereport(ERROR,
00840                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00841                          errmsg("\"%s\" is not an index",
00842                                 RelationGetRelationName(relation))));
00843             break;
00844         case OBJECT_SEQUENCE:
00845             if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
00846                 ereport(ERROR,
00847                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00848                          errmsg("\"%s\" is not a sequence",
00849                                 RelationGetRelationName(relation))));
00850             break;
00851         case OBJECT_TABLE:
00852             if (relation->rd_rel->relkind != RELKIND_RELATION)
00853                 ereport(ERROR,
00854                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00855                          errmsg("\"%s\" is not a table",
00856                                 RelationGetRelationName(relation))));
00857             break;
00858         case OBJECT_VIEW:
00859             if (relation->rd_rel->relkind != RELKIND_VIEW)
00860                 ereport(ERROR,
00861                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00862                          errmsg("\"%s\" is not a view",
00863                                 RelationGetRelationName(relation))));
00864             break;
00865         case OBJECT_MATVIEW:
00866             if (relation->rd_rel->relkind != RELKIND_MATVIEW)
00867                 ereport(ERROR,
00868                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00869                          errmsg("\"%s\" is not a materialized view",
00870                                 RelationGetRelationName(relation))));
00871             break;
00872         case OBJECT_FOREIGN_TABLE:
00873             if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
00874                 ereport(ERROR,
00875                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00876                          errmsg("\"%s\" is not a foreign table",
00877                                 RelationGetRelationName(relation))));
00878             break;
00879         default:
00880             elog(ERROR, "unrecognized objtype: %d", (int) objtype);
00881             break;
00882     }
00883 
00884     /* Done. */
00885     address.objectId = RelationGetRelid(relation);
00886     *relp = relation;
00887 
00888     return address;
00889 }
00890 
00891 /*
00892  * Find object address for an object that is attached to a relation.
00893  *
00894  * Note that we take only an AccessShareLock on the relation.  We need not
00895  * pass down the LOCKMODE from get_object_address(), because that is the lock
00896  * mode for the object itself, not the relation to which it is attached.
00897  */
00898 static ObjectAddress
00899 get_object_address_relobject(ObjectType objtype, List *objname,
00900                              Relation *relp, bool missing_ok)
00901 {
00902     ObjectAddress address;
00903     Relation    relation = NULL;
00904     int         nnames;
00905     const char *depname;
00906 
00907     /* Extract name of dependent object. */
00908     depname = strVal(lfirst(list_tail(objname)));
00909 
00910     /* Separate relation name from dependent object name. */
00911     nnames = list_length(objname);
00912     if (nnames < 2)
00913     {
00914         Oid         reloid;
00915 
00916         /*
00917          * For compatibility with very old releases, we sometimes allow users
00918          * to attempt to specify a rule without mentioning the relation name.
00919          * If there's only rule by that name in the entire database, this will
00920          * work.  But objects other than rules don't get this special
00921          * treatment.
00922          */
00923         if (objtype != OBJECT_RULE)
00924             elog(ERROR, "must specify relation and object name");
00925         address.classId = RewriteRelationId;
00926         address.objectId =
00927             get_rewrite_oid_without_relid(depname, &reloid, missing_ok);
00928         address.objectSubId = 0;
00929 
00930         /*
00931          * Caller is expecting to get back the relation, even though we didn't
00932          * end up using it to find the rule.
00933          */
00934         if (OidIsValid(address.objectId))
00935             relation = heap_open(reloid, AccessShareLock);
00936     }
00937     else
00938     {
00939         List       *relname;
00940         Oid         reloid;
00941 
00942         /* Extract relation name and open relation. */
00943         relname = list_truncate(list_copy(objname), nnames - 1);
00944         relation = heap_openrv(makeRangeVarFromNameList(relname),
00945                                AccessShareLock);
00946         reloid = RelationGetRelid(relation);
00947 
00948         switch (objtype)
00949         {
00950             case OBJECT_RULE:
00951                 address.classId = RewriteRelationId;
00952                 address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
00953                 address.objectSubId = 0;
00954                 break;
00955             case OBJECT_TRIGGER:
00956                 address.classId = TriggerRelationId;
00957                 address.objectId = get_trigger_oid(reloid, depname, missing_ok);
00958                 address.objectSubId = 0;
00959                 break;
00960             case OBJECT_CONSTRAINT:
00961                 address.classId = ConstraintRelationId;
00962                 address.objectId =
00963                     get_relation_constraint_oid(reloid, depname, missing_ok);
00964                 address.objectSubId = 0;
00965                 break;
00966             default:
00967                 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
00968                 /* placate compiler, which doesn't know elog won't return */
00969                 address.classId = InvalidOid;
00970                 address.objectId = InvalidOid;
00971                 address.objectSubId = 0;
00972         }
00973 
00974         /* Avoid relcache leak when object not found. */
00975         if (!OidIsValid(address.objectId))
00976         {
00977             heap_close(relation, AccessShareLock);
00978             relation = NULL;    /* department of accident prevention */
00979             return address;
00980         }
00981     }
00982 
00983     /* Done. */
00984     *relp = relation;
00985     return address;
00986 }
00987 
00988 /*
00989  * Find the ObjectAddress for an attribute.
00990  */
00991 static ObjectAddress
00992 get_object_address_attribute(ObjectType objtype, List *objname,
00993                              Relation *relp, LOCKMODE lockmode,
00994                              bool missing_ok)
00995 {
00996     ObjectAddress address;
00997     List       *relname;
00998     Oid         reloid;
00999     Relation    relation;
01000     const char *attname;
01001     AttrNumber  attnum;
01002 
01003     /* Extract relation name and open relation. */
01004     if (list_length(objname) < 2)
01005         ereport(ERROR,
01006                 (errcode(ERRCODE_SYNTAX_ERROR),
01007                  errmsg("column name must be qualified")));
01008     attname = strVal(lfirst(list_tail(objname)));
01009     relname = list_truncate(list_copy(objname), list_length(objname) - 1);
01010     relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
01011     reloid = RelationGetRelid(relation);
01012 
01013     /* Look up attribute and construct return value. */
01014     attnum = get_attnum(reloid, attname);
01015     if (attnum == InvalidAttrNumber)
01016     {
01017         if (!missing_ok)
01018             ereport(ERROR,
01019                     (errcode(ERRCODE_UNDEFINED_COLUMN),
01020                      errmsg("column \"%s\" of relation \"%s\" does not exist",
01021                             attname, NameListToString(relname))));
01022 
01023         address.classId = RelationRelationId;
01024         address.objectId = InvalidOid;
01025         address.objectSubId = InvalidAttrNumber;
01026         return address;
01027     }
01028 
01029     address.classId = RelationRelationId;
01030     address.objectId = reloid;
01031     address.objectSubId = attnum;
01032 
01033     *relp = relation;
01034     return address;
01035 }
01036 
01037 /*
01038  * Find the ObjectAddress for a type or domain
01039  */
01040 static ObjectAddress
01041 get_object_address_type(ObjectType objtype,
01042                         List *objname, bool missing_ok)
01043 {
01044     ObjectAddress address;
01045     TypeName   *typename;
01046     Type        tup;
01047 
01048     typename = makeTypeNameFromNameList(objname);
01049 
01050     address.classId = TypeRelationId;
01051     address.objectId = InvalidOid;
01052     address.objectSubId = 0;
01053 
01054     tup = LookupTypeName(NULL, typename, NULL);
01055     if (!HeapTupleIsValid(tup))
01056     {
01057         if (!missing_ok)
01058             ereport(ERROR,
01059                     (errcode(ERRCODE_UNDEFINED_OBJECT),
01060                      errmsg("type \"%s\" does not exist",
01061                             TypeNameToString(typename))));
01062         return address;
01063     }
01064     address.objectId = typeTypeId(tup);
01065 
01066     if (objtype == OBJECT_DOMAIN)
01067     {
01068         if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
01069             ereport(ERROR,
01070                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01071                      errmsg("\"%s\" is not a domain",
01072                             TypeNameToString(typename))));
01073     }
01074 
01075     ReleaseSysCache(tup);
01076 
01077     return address;
01078 }
01079 
01080 /*
01081  * Find the ObjectAddress for an opclass or opfamily.
01082  */
01083 static ObjectAddress
01084 get_object_address_opcf(ObjectType objtype,
01085                         List *objname, List *objargs, bool missing_ok)
01086 {
01087     Oid         amoid;
01088     ObjectAddress address;
01089 
01090     Assert(list_length(objargs) == 1);
01091     amoid = get_am_oid(strVal(linitial(objargs)), false);
01092 
01093     switch (objtype)
01094     {
01095         case OBJECT_OPCLASS:
01096             address.classId = OperatorClassRelationId;
01097             address.objectId = get_opclass_oid(amoid, objname, missing_ok);
01098             address.objectSubId = 0;
01099             break;
01100         case OBJECT_OPFAMILY:
01101             address.classId = OperatorFamilyRelationId;
01102             address.objectId = get_opfamily_oid(amoid, objname, missing_ok);
01103             address.objectSubId = 0;
01104             break;
01105         default:
01106             elog(ERROR, "unrecognized objtype: %d", (int) objtype);
01107             /* placate compiler, which doesn't know elog won't return */
01108             address.classId = InvalidOid;
01109             address.objectId = InvalidOid;
01110             address.objectSubId = 0;
01111     }
01112 
01113     return address;
01114 }
01115 
01116 /*
01117  * Check ownership of an object previously identified by get_object_address.
01118  */
01119 void
01120 check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
01121                        List *objname, List *objargs, Relation relation)
01122 {
01123     switch (objtype)
01124     {
01125         case OBJECT_INDEX:
01126         case OBJECT_SEQUENCE:
01127         case OBJECT_TABLE:
01128         case OBJECT_VIEW:
01129         case OBJECT_MATVIEW:
01130         case OBJECT_FOREIGN_TABLE:
01131         case OBJECT_COLUMN:
01132         case OBJECT_RULE:
01133         case OBJECT_TRIGGER:
01134         case OBJECT_CONSTRAINT:
01135             if (!pg_class_ownercheck(RelationGetRelid(relation), roleid))
01136                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
01137                                RelationGetRelationName(relation));
01138             break;
01139         case OBJECT_DATABASE:
01140             if (!pg_database_ownercheck(address.objectId, roleid))
01141                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
01142                                NameListToString(objname));
01143             break;
01144         case OBJECT_TYPE:
01145         case OBJECT_DOMAIN:
01146         case OBJECT_ATTRIBUTE:
01147             if (!pg_type_ownercheck(address.objectId, roleid))
01148                 aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId);
01149             break;
01150         case OBJECT_AGGREGATE:
01151         case OBJECT_FUNCTION:
01152             if (!pg_proc_ownercheck(address.objectId, roleid))
01153                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
01154                                NameListToString(objname));
01155             break;
01156         case OBJECT_OPERATOR:
01157             if (!pg_oper_ownercheck(address.objectId, roleid))
01158                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
01159                                NameListToString(objname));
01160             break;
01161         case OBJECT_SCHEMA:
01162             if (!pg_namespace_ownercheck(address.objectId, roleid))
01163                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
01164                                NameListToString(objname));
01165             break;
01166         case OBJECT_COLLATION:
01167             if (!pg_collation_ownercheck(address.objectId, roleid))
01168                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION,
01169                                NameListToString(objname));
01170             break;
01171         case OBJECT_CONVERSION:
01172             if (!pg_conversion_ownercheck(address.objectId, roleid))
01173                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
01174                                NameListToString(objname));
01175             break;
01176         case OBJECT_EXTENSION:
01177             if (!pg_extension_ownercheck(address.objectId, roleid))
01178                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
01179                                NameListToString(objname));
01180             break;
01181         case OBJECT_FDW:
01182             if (!pg_foreign_data_wrapper_ownercheck(address.objectId, roleid))
01183                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FDW,
01184                                NameListToString(objname));
01185             break;
01186         case OBJECT_FOREIGN_SERVER:
01187             if (!pg_foreign_server_ownercheck(address.objectId, roleid))
01188                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
01189                                NameListToString(objname));
01190             break;
01191         case OBJECT_EVENT_TRIGGER:
01192             if (!pg_event_trigger_ownercheck(address.objectId, roleid))
01193                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
01194                                NameListToString(objname));
01195             break;
01196         case OBJECT_LANGUAGE:
01197             if (!pg_language_ownercheck(address.objectId, roleid))
01198                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
01199                                NameListToString(objname));
01200             break;
01201         case OBJECT_OPCLASS:
01202             if (!pg_opclass_ownercheck(address.objectId, roleid))
01203                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
01204                                NameListToString(objname));
01205             break;
01206         case OBJECT_OPFAMILY:
01207             if (!pg_opfamily_ownercheck(address.objectId, roleid))
01208                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
01209                                NameListToString(objname));
01210             break;
01211         case OBJECT_LARGEOBJECT:
01212             if (!lo_compat_privileges &&
01213                 !pg_largeobject_ownercheck(address.objectId, roleid))
01214                 ereport(ERROR,
01215                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01216                          errmsg("must be owner of large object %u",
01217                                 address.objectId)));
01218             break;
01219         case OBJECT_CAST:
01220             {
01221                 /* We can only check permissions on the source/target types */
01222                 TypeName   *sourcetype = (TypeName *) linitial(objname);
01223                 TypeName   *targettype = (TypeName *) linitial(objargs);
01224                 Oid         sourcetypeid = typenameTypeId(NULL, sourcetype);
01225                 Oid         targettypeid = typenameTypeId(NULL, targettype);
01226 
01227                 if (!pg_type_ownercheck(sourcetypeid, roleid)
01228                     && !pg_type_ownercheck(targettypeid, roleid))
01229                     ereport(ERROR,
01230                             (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01231                              errmsg("must be owner of type %s or type %s",
01232                                     format_type_be(sourcetypeid),
01233                                     format_type_be(targettypeid))));
01234             }
01235             break;
01236         case OBJECT_TABLESPACE:
01237             if (!pg_tablespace_ownercheck(address.objectId, roleid))
01238                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
01239                                NameListToString(objname));
01240             break;
01241         case OBJECT_TSDICTIONARY:
01242             if (!pg_ts_dict_ownercheck(address.objectId, roleid))
01243                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
01244                                NameListToString(objname));
01245             break;
01246         case OBJECT_TSCONFIGURATION:
01247             if (!pg_ts_config_ownercheck(address.objectId, roleid))
01248                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
01249                                NameListToString(objname));
01250             break;
01251         case OBJECT_ROLE:
01252 
01253             /*
01254              * We treat roles as being "owned" by those with CREATEROLE priv,
01255              * except that superusers are only owned by superusers.
01256              */
01257             if (superuser_arg(address.objectId))
01258             {
01259                 if (!superuser_arg(roleid))
01260                     ereport(ERROR,
01261                             (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01262                              errmsg("must be superuser")));
01263             }
01264             else
01265             {
01266                 if (!has_createrole_privilege(roleid))
01267                     ereport(ERROR,
01268                             (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01269                              errmsg("must have CREATEROLE privilege")));
01270             }
01271             break;
01272         case OBJECT_TSPARSER:
01273         case OBJECT_TSTEMPLATE:
01274             /* We treat these object types as being owned by superusers */
01275             if (!superuser_arg(roleid))
01276                 ereport(ERROR,
01277                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01278                          errmsg("must be superuser")));
01279             break;
01280         default:
01281             elog(ERROR, "unrecognized object type: %d",
01282                  (int) objtype);
01283     }
01284 }
01285 
01286 /*
01287  * get_object_namespace
01288  *
01289  * Find the schema containing the specified object.  For non-schema objects,
01290  * this function returns InvalidOid.
01291  */
01292 Oid
01293 get_object_namespace(const ObjectAddress *address)
01294 {
01295     int         cache;
01296     HeapTuple   tuple;
01297     bool        isnull;
01298     Oid         oid;
01299     ObjectPropertyType *property;
01300 
01301     /* If not owned by a namespace, just return InvalidOid. */
01302     property = get_object_property_data(address->classId);
01303     if (property->attnum_namespace == InvalidAttrNumber)
01304         return InvalidOid;
01305 
01306     /* Currently, we can only handle object types with system caches. */
01307     cache = property->oid_catcache_id;
01308     Assert(cache != -1);
01309 
01310     /* Fetch tuple from syscache and extract namespace attribute. */
01311     tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
01312     if (!HeapTupleIsValid(tuple))
01313         elog(ERROR, "cache lookup failed for cache %d oid %u",
01314              cache, address->objectId);
01315     oid = DatumGetObjectId(SysCacheGetAttr(cache,
01316                                            tuple,
01317                                            property->attnum_namespace,
01318                                            &isnull));
01319     Assert(!isnull);
01320     ReleaseSysCache(tuple);
01321 
01322     return oid;
01323 }
01324 
01325 /*
01326  * Interfaces to reference fields of ObjectPropertyType
01327  */
01328 Oid
01329 get_object_oid_index(Oid class_id)
01330 {
01331     ObjectPropertyType *prop = get_object_property_data(class_id);
01332 
01333     return prop->oid_index_oid;
01334 }
01335 
01336 int
01337 get_object_catcache_oid(Oid class_id)
01338 {
01339     ObjectPropertyType *prop = get_object_property_data(class_id);
01340 
01341     return prop->oid_catcache_id;
01342 }
01343 
01344 int
01345 get_object_catcache_name(Oid class_id)
01346 {
01347     ObjectPropertyType *prop = get_object_property_data(class_id);
01348 
01349     return prop->name_catcache_id;
01350 }
01351 
01352 AttrNumber
01353 get_object_attnum_name(Oid class_id)
01354 {
01355     ObjectPropertyType *prop = get_object_property_data(class_id);
01356 
01357     return prop->attnum_name;
01358 }
01359 
01360 AttrNumber
01361 get_object_attnum_namespace(Oid class_id)
01362 {
01363     ObjectPropertyType *prop = get_object_property_data(class_id);
01364 
01365     return prop->attnum_namespace;
01366 }
01367 
01368 AttrNumber
01369 get_object_attnum_owner(Oid class_id)
01370 {
01371     ObjectPropertyType *prop = get_object_property_data(class_id);
01372 
01373     return prop->attnum_owner;
01374 }
01375 
01376 AttrNumber
01377 get_object_attnum_acl(Oid class_id)
01378 {
01379     ObjectPropertyType *prop = get_object_property_data(class_id);
01380 
01381     return prop->attnum_acl;
01382 }
01383 
01384 AclObjectKind
01385 get_object_aclkind(Oid class_id)
01386 {
01387     ObjectPropertyType *prop = get_object_property_data(class_id);
01388 
01389     return prop->acl_kind;
01390 }
01391 
01392 bool
01393 get_object_namensp_unique(Oid class_id)
01394 {
01395     ObjectPropertyType *prop = get_object_property_data(class_id);
01396 
01397     return prop->is_nsp_name_unique;
01398 }
01399 
01400 /*
01401  * Return whether we have useful data for the given object class in the
01402  * ObjectProperty table.
01403  */
01404 bool
01405 is_objectclass_supported(Oid class_id)
01406 {
01407     int         index;
01408 
01409     for (index = 0; index < lengthof(ObjectProperty); index++)
01410     {
01411         if (ObjectProperty[index].class_oid == class_id)
01412             return true;
01413     }
01414 
01415     return false;
01416 }
01417 
01418 /*
01419  * Find ObjectProperty structure by class_id.
01420  */
01421 static ObjectPropertyType *
01422 get_object_property_data(Oid class_id)
01423 {
01424     static ObjectPropertyType *prop_last = NULL;
01425     int         index;
01426 
01427     /*
01428      * A shortcut to speed up multiple consecutive lookups of a particular
01429      * object class.
01430      */
01431     if (prop_last && prop_last->class_oid == class_id)
01432         return prop_last;
01433 
01434     for (index = 0; index < lengthof(ObjectProperty); index++)
01435     {
01436         if (ObjectProperty[index].class_oid == class_id)
01437         {
01438             prop_last = &ObjectProperty[index];
01439             return &ObjectProperty[index];
01440         }
01441     }
01442 
01443     ereport(ERROR,
01444             (errmsg_internal("unrecognized class id: %u", class_id)));
01445 
01446     return NULL; /* keep MSC compiler happy */
01447 }
01448 
01449 /*
01450  * Return a copy of the tuple for the object with the given object OID, from
01451  * the given catalog (which must have been opened by the caller and suitably
01452  * locked).  NULL is returned if the OID is not found.
01453  *
01454  * We try a syscache first, if available.
01455  */
01456 HeapTuple
01457 get_catalog_object_by_oid(Relation catalog, Oid objectId)
01458 {
01459     HeapTuple   tuple;
01460     Oid         classId = RelationGetRelid(catalog);
01461     int         oidCacheId = get_object_catcache_oid(classId);
01462 
01463     if (oidCacheId > 0)
01464     {
01465         tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
01466         if (!HeapTupleIsValid(tuple))  /* should not happen */
01467             return NULL;
01468     }
01469     else
01470     {
01471         Oid         oidIndexId = get_object_oid_index(classId);
01472         SysScanDesc scan;
01473         ScanKeyData skey;
01474 
01475         Assert(OidIsValid(oidIndexId));
01476 
01477         ScanKeyInit(&skey,
01478                     ObjectIdAttributeNumber,
01479                     BTEqualStrategyNumber, F_OIDEQ,
01480                     ObjectIdGetDatum(objectId));
01481 
01482         scan = systable_beginscan(catalog, oidIndexId, true,
01483                                   SnapshotNow, 1, &skey);
01484         tuple = systable_getnext(scan);
01485         if (!HeapTupleIsValid(tuple))
01486         {
01487             systable_endscan(scan);
01488             return NULL;
01489         }
01490         tuple = heap_copytuple(tuple);
01491 
01492         systable_endscan(scan);
01493     }
01494 
01495     return tuple;
01496 }
01497 
01498 /*
01499  * getObjectDescription: build an object description for messages
01500  *
01501  * The result is a palloc'd string.
01502  */
01503 char *
01504 getObjectDescription(const ObjectAddress *object)
01505 {
01506     StringInfoData buffer;
01507 
01508     initStringInfo(&buffer);
01509 
01510     switch (getObjectClass(object))
01511     {
01512         case OCLASS_CLASS:
01513             getRelationDescription(&buffer, object->objectId);
01514             if (object->objectSubId != 0)
01515                 appendStringInfo(&buffer, _(" column %s"),
01516                                  get_relid_attribute_name(object->objectId,
01517                                                        object->objectSubId));
01518             break;
01519 
01520         case OCLASS_PROC:
01521             appendStringInfo(&buffer, _("function %s"),
01522                              format_procedure(object->objectId));
01523             break;
01524 
01525         case OCLASS_TYPE:
01526             appendStringInfo(&buffer, _("type %s"),
01527                              format_type_be(object->objectId));
01528             break;
01529 
01530         case OCLASS_CAST:
01531             {
01532                 Relation    castDesc;
01533                 ScanKeyData skey[1];
01534                 SysScanDesc rcscan;
01535                 HeapTuple   tup;
01536                 Form_pg_cast castForm;
01537 
01538                 castDesc = heap_open(CastRelationId, AccessShareLock);
01539 
01540                 ScanKeyInit(&skey[0],
01541                             ObjectIdAttributeNumber,
01542                             BTEqualStrategyNumber, F_OIDEQ,
01543                             ObjectIdGetDatum(object->objectId));
01544 
01545                 rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
01546                                             SnapshotNow, 1, skey);
01547 
01548                 tup = systable_getnext(rcscan);
01549 
01550                 if (!HeapTupleIsValid(tup))
01551                     elog(ERROR, "could not find tuple for cast %u",
01552                          object->objectId);
01553 
01554                 castForm = (Form_pg_cast) GETSTRUCT(tup);
01555 
01556                 appendStringInfo(&buffer, _("cast from %s to %s"),
01557                                  format_type_be(castForm->castsource),
01558                                  format_type_be(castForm->casttarget));
01559 
01560                 systable_endscan(rcscan);
01561                 heap_close(castDesc, AccessShareLock);
01562                 break;
01563             }
01564 
01565         case OCLASS_COLLATION:
01566             {
01567                 HeapTuple   collTup;
01568                 Form_pg_collation coll;
01569 
01570                 collTup = SearchSysCache1(COLLOID,
01571                                           ObjectIdGetDatum(object->objectId));
01572                 if (!HeapTupleIsValid(collTup))
01573                     elog(ERROR, "cache lookup failed for collation %u",
01574                          object->objectId);
01575                 coll = (Form_pg_collation) GETSTRUCT(collTup);
01576                 appendStringInfo(&buffer, _("collation %s"),
01577                                  NameStr(coll->collname));
01578                 ReleaseSysCache(collTup);
01579                 break;
01580             }
01581 
01582         case OCLASS_CONSTRAINT:
01583             {
01584                 HeapTuple   conTup;
01585                 Form_pg_constraint con;
01586 
01587                 conTup = SearchSysCache1(CONSTROID,
01588                                          ObjectIdGetDatum(object->objectId));
01589                 if (!HeapTupleIsValid(conTup))
01590                     elog(ERROR, "cache lookup failed for constraint %u",
01591                          object->objectId);
01592                 con = (Form_pg_constraint) GETSTRUCT(conTup);
01593 
01594                 if (OidIsValid(con->conrelid))
01595                 {
01596                     StringInfoData rel;
01597 
01598                     initStringInfo(&rel);
01599                     getRelationDescription(&rel, con->conrelid);
01600                     appendStringInfo(&buffer, _("constraint %s on %s"),
01601                                      NameStr(con->conname), rel.data);
01602                     pfree(rel.data);
01603                 }
01604                 else
01605                 {
01606                     appendStringInfo(&buffer, _("constraint %s"),
01607                                      NameStr(con->conname));
01608                 }
01609 
01610                 ReleaseSysCache(conTup);
01611                 break;
01612             }
01613 
01614         case OCLASS_CONVERSION:
01615             {
01616                 HeapTuple   conTup;
01617 
01618                 conTup = SearchSysCache1(CONVOID,
01619                                          ObjectIdGetDatum(object->objectId));
01620                 if (!HeapTupleIsValid(conTup))
01621                     elog(ERROR, "cache lookup failed for conversion %u",
01622                          object->objectId);
01623                 appendStringInfo(&buffer, _("conversion %s"),
01624                  NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
01625                 ReleaseSysCache(conTup);
01626                 break;
01627             }
01628 
01629         case OCLASS_DEFAULT:
01630             {
01631                 Relation    attrdefDesc;
01632                 ScanKeyData skey[1];
01633                 SysScanDesc adscan;
01634                 HeapTuple   tup;
01635                 Form_pg_attrdef attrdef;
01636                 ObjectAddress colobject;
01637 
01638                 attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
01639 
01640                 ScanKeyInit(&skey[0],
01641                             ObjectIdAttributeNumber,
01642                             BTEqualStrategyNumber, F_OIDEQ,
01643                             ObjectIdGetDatum(object->objectId));
01644 
01645                 adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
01646                                             true, SnapshotNow, 1, skey);
01647 
01648                 tup = systable_getnext(adscan);
01649 
01650                 if (!HeapTupleIsValid(tup))
01651                     elog(ERROR, "could not find tuple for attrdef %u",
01652                          object->objectId);
01653 
01654                 attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
01655 
01656                 colobject.classId = RelationRelationId;
01657                 colobject.objectId = attrdef->adrelid;
01658                 colobject.objectSubId = attrdef->adnum;
01659 
01660                 appendStringInfo(&buffer, _("default for %s"),
01661                                  getObjectDescription(&colobject));
01662 
01663                 systable_endscan(adscan);
01664                 heap_close(attrdefDesc, AccessShareLock);
01665                 break;
01666             }
01667 
01668         case OCLASS_LANGUAGE:
01669             {
01670                 HeapTuple   langTup;
01671 
01672                 langTup = SearchSysCache1(LANGOID,
01673                                           ObjectIdGetDatum(object->objectId));
01674                 if (!HeapTupleIsValid(langTup))
01675                     elog(ERROR, "cache lookup failed for language %u",
01676                          object->objectId);
01677                 appendStringInfo(&buffer, _("language %s"),
01678                   NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
01679                 ReleaseSysCache(langTup);
01680                 break;
01681             }
01682         case OCLASS_LARGEOBJECT:
01683             appendStringInfo(&buffer, _("large object %u"),
01684                              object->objectId);
01685             break;
01686 
01687         case OCLASS_OPERATOR:
01688             appendStringInfo(&buffer, _("operator %s"),
01689                              format_operator(object->objectId));
01690             break;
01691 
01692         case OCLASS_OPCLASS:
01693             {
01694                 HeapTuple   opcTup;
01695                 Form_pg_opclass opcForm;
01696                 HeapTuple   amTup;
01697                 Form_pg_am  amForm;
01698                 char       *nspname;
01699 
01700                 opcTup = SearchSysCache1(CLAOID,
01701                                          ObjectIdGetDatum(object->objectId));
01702                 if (!HeapTupleIsValid(opcTup))
01703                     elog(ERROR, "cache lookup failed for opclass %u",
01704                          object->objectId);
01705                 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
01706 
01707                 amTup = SearchSysCache1(AMOID,
01708                                         ObjectIdGetDatum(opcForm->opcmethod));
01709                 if (!HeapTupleIsValid(amTup))
01710                     elog(ERROR, "cache lookup failed for access method %u",
01711                          opcForm->opcmethod);
01712                 amForm = (Form_pg_am) GETSTRUCT(amTup);
01713 
01714                 /* Qualify the name if not visible in search path */
01715                 if (OpclassIsVisible(object->objectId))
01716                     nspname = NULL;
01717                 else
01718                     nspname = get_namespace_name(opcForm->opcnamespace);
01719 
01720                 appendStringInfo(&buffer, _("operator class %s for access method %s"),
01721                                  quote_qualified_identifier(nspname,
01722                                                   NameStr(opcForm->opcname)),
01723                                  NameStr(amForm->amname));
01724 
01725                 ReleaseSysCache(amTup);
01726                 ReleaseSysCache(opcTup);
01727                 break;
01728             }
01729 
01730         case OCLASS_OPFAMILY:
01731             getOpFamilyDescription(&buffer, object->objectId);
01732             break;
01733 
01734         case OCLASS_AMOP:
01735             {
01736                 Relation    amopDesc;
01737                 HeapTuple   tup;
01738                 ScanKeyData skey[1];
01739                 SysScanDesc amscan;
01740                 Form_pg_amop amopForm;
01741                 StringInfoData opfam;
01742 
01743                 amopDesc = heap_open(AccessMethodOperatorRelationId,
01744                                      AccessShareLock);
01745 
01746                 ScanKeyInit(&skey[0],
01747                             ObjectIdAttributeNumber,
01748                             BTEqualStrategyNumber, F_OIDEQ,
01749                             ObjectIdGetDatum(object->objectId));
01750 
01751                 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
01752                                             SnapshotNow, 1, skey);
01753 
01754                 tup = systable_getnext(amscan);
01755 
01756                 if (!HeapTupleIsValid(tup))
01757                     elog(ERROR, "could not find tuple for amop entry %u",
01758                          object->objectId);
01759 
01760                 amopForm = (Form_pg_amop) GETSTRUCT(tup);
01761 
01762                 initStringInfo(&opfam);
01763                 getOpFamilyDescription(&opfam, amopForm->amopfamily);
01764 
01765                 /*------
01766                    translator: %d is the operator strategy (a number), the
01767                    first two %s's are data type names, the third %s is the
01768                    description of the operator family, and the last %s is the
01769                    textual form of the operator with arguments.  */
01770                 appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
01771                                  amopForm->amopstrategy,
01772                                  format_type_be(amopForm->amoplefttype),
01773                                  format_type_be(amopForm->amoprighttype),
01774                                  opfam.data,
01775                                  format_operator(amopForm->amopopr));
01776 
01777                 pfree(opfam.data);
01778 
01779                 systable_endscan(amscan);
01780                 heap_close(amopDesc, AccessShareLock);
01781                 break;
01782             }
01783 
01784         case OCLASS_AMPROC:
01785             {
01786                 Relation    amprocDesc;
01787                 ScanKeyData skey[1];
01788                 SysScanDesc amscan;
01789                 HeapTuple   tup;
01790                 Form_pg_amproc amprocForm;
01791                 StringInfoData opfam;
01792 
01793                 amprocDesc = heap_open(AccessMethodProcedureRelationId,
01794                                        AccessShareLock);
01795 
01796                 ScanKeyInit(&skey[0],
01797                             ObjectIdAttributeNumber,
01798                             BTEqualStrategyNumber, F_OIDEQ,
01799                             ObjectIdGetDatum(object->objectId));
01800 
01801                 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
01802                                             SnapshotNow, 1, skey);
01803 
01804                 tup = systable_getnext(amscan);
01805 
01806                 if (!HeapTupleIsValid(tup))
01807                     elog(ERROR, "could not find tuple for amproc entry %u",
01808                          object->objectId);
01809 
01810                 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
01811 
01812                 initStringInfo(&opfam);
01813                 getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
01814 
01815                 /*------
01816                    translator: %d is the function number, the first two %s's
01817                    are data type names, the third %s is the description of the
01818                    operator family, and the last %s is the textual form of the
01819                    function with arguments.  */
01820                 appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
01821                                  amprocForm->amprocnum,
01822                                  format_type_be(amprocForm->amproclefttype),
01823                                  format_type_be(amprocForm->amprocrighttype),
01824                                  opfam.data,
01825                                  format_procedure(amprocForm->amproc));
01826 
01827                 pfree(opfam.data);
01828 
01829                 systable_endscan(amscan);
01830                 heap_close(amprocDesc, AccessShareLock);
01831                 break;
01832             }
01833 
01834         case OCLASS_REWRITE:
01835             {
01836                 Relation    ruleDesc;
01837                 ScanKeyData skey[1];
01838                 SysScanDesc rcscan;
01839                 HeapTuple   tup;
01840                 Form_pg_rewrite rule;
01841 
01842                 ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
01843 
01844                 ScanKeyInit(&skey[0],
01845                             ObjectIdAttributeNumber,
01846                             BTEqualStrategyNumber, F_OIDEQ,
01847                             ObjectIdGetDatum(object->objectId));
01848 
01849                 rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
01850                                             SnapshotNow, 1, skey);
01851 
01852                 tup = systable_getnext(rcscan);
01853 
01854                 if (!HeapTupleIsValid(tup))
01855                     elog(ERROR, "could not find tuple for rule %u",
01856                          object->objectId);
01857 
01858                 rule = (Form_pg_rewrite) GETSTRUCT(tup);
01859 
01860                 appendStringInfo(&buffer, _("rule %s on "),
01861                                  NameStr(rule->rulename));
01862                 getRelationDescription(&buffer, rule->ev_class);
01863 
01864                 systable_endscan(rcscan);
01865                 heap_close(ruleDesc, AccessShareLock);
01866                 break;
01867             }
01868 
01869         case OCLASS_TRIGGER:
01870             {
01871                 Relation    trigDesc;
01872                 ScanKeyData skey[1];
01873                 SysScanDesc tgscan;
01874                 HeapTuple   tup;
01875                 Form_pg_trigger trig;
01876 
01877                 trigDesc = heap_open(TriggerRelationId, AccessShareLock);
01878 
01879                 ScanKeyInit(&skey[0],
01880                             ObjectIdAttributeNumber,
01881                             BTEqualStrategyNumber, F_OIDEQ,
01882                             ObjectIdGetDatum(object->objectId));
01883 
01884                 tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
01885                                             SnapshotNow, 1, skey);
01886 
01887                 tup = systable_getnext(tgscan);
01888 
01889                 if (!HeapTupleIsValid(tup))
01890                     elog(ERROR, "could not find tuple for trigger %u",
01891                          object->objectId);
01892 
01893                 trig = (Form_pg_trigger) GETSTRUCT(tup);
01894 
01895                 appendStringInfo(&buffer, _("trigger %s on "),
01896                                  NameStr(trig->tgname));
01897                 getRelationDescription(&buffer, trig->tgrelid);
01898 
01899                 systable_endscan(tgscan);
01900                 heap_close(trigDesc, AccessShareLock);
01901                 break;
01902             }
01903 
01904         case OCLASS_SCHEMA:
01905             {
01906                 char       *nspname;
01907 
01908                 nspname = get_namespace_name(object->objectId);
01909                 if (!nspname)
01910                     elog(ERROR, "cache lookup failed for namespace %u",
01911                          object->objectId);
01912                 appendStringInfo(&buffer, _("schema %s"), nspname);
01913                 break;
01914             }
01915 
01916         case OCLASS_TSPARSER:
01917             {
01918                 HeapTuple   tup;
01919 
01920                 tup = SearchSysCache1(TSPARSEROID,
01921                                       ObjectIdGetDatum(object->objectId));
01922                 if (!HeapTupleIsValid(tup))
01923                     elog(ERROR, "cache lookup failed for text search parser %u",
01924                          object->objectId);
01925                 appendStringInfo(&buffer, _("text search parser %s"),
01926                      NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
01927                 ReleaseSysCache(tup);
01928                 break;
01929             }
01930 
01931         case OCLASS_TSDICT:
01932             {
01933                 HeapTuple   tup;
01934 
01935                 tup = SearchSysCache1(TSDICTOID,
01936                                       ObjectIdGetDatum(object->objectId));
01937                 if (!HeapTupleIsValid(tup))
01938                     elog(ERROR, "cache lookup failed for text search dictionary %u",
01939                          object->objectId);
01940                 appendStringInfo(&buffer, _("text search dictionary %s"),
01941                       NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
01942                 ReleaseSysCache(tup);
01943                 break;
01944             }
01945 
01946         case OCLASS_TSTEMPLATE:
01947             {
01948                 HeapTuple   tup;
01949 
01950                 tup = SearchSysCache1(TSTEMPLATEOID,
01951                                       ObjectIdGetDatum(object->objectId));
01952                 if (!HeapTupleIsValid(tup))
01953                     elog(ERROR, "cache lookup failed for text search template %u",
01954                          object->objectId);
01955                 appendStringInfo(&buffer, _("text search template %s"),
01956                   NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
01957                 ReleaseSysCache(tup);
01958                 break;
01959             }
01960 
01961         case OCLASS_TSCONFIG:
01962             {
01963                 HeapTuple   tup;
01964 
01965                 tup = SearchSysCache1(TSCONFIGOID,
01966                                       ObjectIdGetDatum(object->objectId));
01967                 if (!HeapTupleIsValid(tup))
01968                     elog(ERROR, "cache lookup failed for text search configuration %u",
01969                          object->objectId);
01970                 appendStringInfo(&buffer, _("text search configuration %s"),
01971                      NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
01972                 ReleaseSysCache(tup);
01973                 break;
01974             }
01975 
01976         case OCLASS_ROLE:
01977             {
01978                 appendStringInfo(&buffer, _("role %s"),
01979                                  GetUserNameFromId(object->objectId));
01980                 break;
01981             }
01982 
01983         case OCLASS_DATABASE:
01984             {
01985                 char       *datname;
01986 
01987                 datname = get_database_name(object->objectId);
01988                 if (!datname)
01989                     elog(ERROR, "cache lookup failed for database %u",
01990                          object->objectId);
01991                 appendStringInfo(&buffer, _("database %s"), datname);
01992                 break;
01993             }
01994 
01995         case OCLASS_TBLSPACE:
01996             {
01997                 char       *tblspace;
01998 
01999                 tblspace = get_tablespace_name(object->objectId);
02000                 if (!tblspace)
02001                     elog(ERROR, "cache lookup failed for tablespace %u",
02002                          object->objectId);
02003                 appendStringInfo(&buffer, _("tablespace %s"), tblspace);
02004                 break;
02005             }
02006 
02007         case OCLASS_FDW:
02008             {
02009                 ForeignDataWrapper *fdw;
02010 
02011                 fdw = GetForeignDataWrapper(object->objectId);
02012                 appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
02013                 break;
02014             }
02015 
02016         case OCLASS_FOREIGN_SERVER:
02017             {
02018                 ForeignServer *srv;
02019 
02020                 srv = GetForeignServer(object->objectId);
02021                 appendStringInfo(&buffer, _("server %s"), srv->servername);
02022                 break;
02023             }
02024 
02025         case OCLASS_USER_MAPPING:
02026             {
02027                 HeapTuple   tup;
02028                 Oid         useid;
02029                 char       *usename;
02030 
02031                 tup = SearchSysCache1(USERMAPPINGOID,
02032                                       ObjectIdGetDatum(object->objectId));
02033                 if (!HeapTupleIsValid(tup))
02034                     elog(ERROR, "cache lookup failed for user mapping %u",
02035                          object->objectId);
02036 
02037                 useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
02038 
02039                 ReleaseSysCache(tup);
02040 
02041                 if (OidIsValid(useid))
02042                     usename = GetUserNameFromId(useid);
02043                 else
02044                     usename = "public";
02045 
02046                 appendStringInfo(&buffer, _("user mapping for %s"), usename);
02047                 break;
02048             }
02049 
02050         case OCLASS_DEFACL:
02051             {
02052                 Relation    defaclrel;
02053                 ScanKeyData skey[1];
02054                 SysScanDesc rcscan;
02055                 HeapTuple   tup;
02056                 Form_pg_default_acl defacl;
02057 
02058                 defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
02059 
02060                 ScanKeyInit(&skey[0],
02061                             ObjectIdAttributeNumber,
02062                             BTEqualStrategyNumber, F_OIDEQ,
02063                             ObjectIdGetDatum(object->objectId));
02064 
02065                 rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
02066                                             true, SnapshotNow, 1, skey);
02067 
02068                 tup = systable_getnext(rcscan);
02069 
02070                 if (!HeapTupleIsValid(tup))
02071                     elog(ERROR, "could not find tuple for default ACL %u",
02072                          object->objectId);
02073 
02074                 defacl = (Form_pg_default_acl) GETSTRUCT(tup);
02075 
02076                 switch (defacl->defaclobjtype)
02077                 {
02078                     case DEFACLOBJ_RELATION:
02079                         appendStringInfo(&buffer,
02080                                          _("default privileges on new relations belonging to role %s"),
02081                                       GetUserNameFromId(defacl->defaclrole));
02082                         break;
02083                     case DEFACLOBJ_SEQUENCE:
02084                         appendStringInfo(&buffer,
02085                                          _("default privileges on new sequences belonging to role %s"),
02086                                       GetUserNameFromId(defacl->defaclrole));
02087                         break;
02088                     case DEFACLOBJ_FUNCTION:
02089                         appendStringInfo(&buffer,
02090                                          _("default privileges on new functions belonging to role %s"),
02091                                       GetUserNameFromId(defacl->defaclrole));
02092                         break;
02093                     case DEFACLOBJ_TYPE:
02094                         appendStringInfo(&buffer,
02095                                          _("default privileges on new types belonging to role %s"),
02096                                       GetUserNameFromId(defacl->defaclrole));
02097                         break;
02098                     default:
02099                         /* shouldn't get here */
02100                         appendStringInfo(&buffer,
02101                                 _("default privileges belonging to role %s"),
02102                                       GetUserNameFromId(defacl->defaclrole));
02103                         break;
02104                 }
02105 
02106                 if (OidIsValid(defacl->defaclnamespace))
02107                 {
02108                     appendStringInfo(&buffer,
02109                                      _(" in schema %s"),
02110                                 get_namespace_name(defacl->defaclnamespace));
02111                 }
02112 
02113                 systable_endscan(rcscan);
02114                 heap_close(defaclrel, AccessShareLock);
02115                 break;
02116             }
02117 
02118         case OCLASS_EXTENSION:
02119             {
02120                 char       *extname;
02121 
02122                 extname = get_extension_name(object->objectId);
02123                 if (!extname)
02124                     elog(ERROR, "cache lookup failed for extension %u",
02125                          object->objectId);
02126                 appendStringInfo(&buffer, _("extension %s"), extname);
02127                 break;
02128             }
02129 
02130         case OCLASS_EVENT_TRIGGER:
02131             {
02132                 HeapTuple   tup;
02133 
02134                 tup = SearchSysCache1(EVENTTRIGGEROID,
02135                                       ObjectIdGetDatum(object->objectId));
02136                 if (!HeapTupleIsValid(tup))
02137                     elog(ERROR, "cache lookup failed for event trigger %u",
02138                          object->objectId);
02139                 appendStringInfo(&buffer, _("event trigger %s"),
02140                      NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
02141                 ReleaseSysCache(tup);
02142                 break;
02143             }
02144 
02145         default:
02146             appendStringInfo(&buffer, "unrecognized object %u %u %d",
02147                              object->classId,
02148                              object->objectId,
02149                              object->objectSubId);
02150             break;
02151     }
02152 
02153     return buffer.data;
02154 }
02155 
02156 /*
02157  * getObjectDescriptionOids: as above, except the object is specified by Oids
02158  */
02159 char *
02160 getObjectDescriptionOids(Oid classid, Oid objid)
02161 {
02162     ObjectAddress address;
02163 
02164     address.classId = classid;
02165     address.objectId = objid;
02166     address.objectSubId = 0;
02167 
02168     return getObjectDescription(&address);
02169 }
02170 
02171 /*
02172  * subroutine for getObjectDescription: describe a relation
02173  */
02174 static void
02175 getRelationDescription(StringInfo buffer, Oid relid)
02176 {
02177     HeapTuple   relTup;
02178     Form_pg_class relForm;
02179     char       *nspname;
02180     char       *relname;
02181 
02182     relTup = SearchSysCache1(RELOID,
02183                              ObjectIdGetDatum(relid));
02184     if (!HeapTupleIsValid(relTup))
02185         elog(ERROR, "cache lookup failed for relation %u", relid);
02186     relForm = (Form_pg_class) GETSTRUCT(relTup);
02187 
02188     /* Qualify the name if not visible in search path */
02189     if (RelationIsVisible(relid))
02190         nspname = NULL;
02191     else
02192         nspname = get_namespace_name(relForm->relnamespace);
02193 
02194     relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
02195 
02196     switch (relForm->relkind)
02197     {
02198         case RELKIND_RELATION:
02199             appendStringInfo(buffer, _("table %s"),
02200                              relname);
02201             break;
02202         case RELKIND_INDEX:
02203             appendStringInfo(buffer, _("index %s"),
02204                              relname);
02205             break;
02206         case RELKIND_SEQUENCE:
02207             appendStringInfo(buffer, _("sequence %s"),
02208                              relname);
02209             break;
02210         case RELKIND_TOASTVALUE:
02211             appendStringInfo(buffer, _("toast table %s"),
02212                              relname);
02213             break;
02214         case RELKIND_VIEW:
02215             appendStringInfo(buffer, _("view %s"),
02216                              relname);
02217             break;
02218         case RELKIND_MATVIEW:
02219             appendStringInfo(buffer, _("materialized view %s"),
02220                              relname);
02221             break;
02222         case RELKIND_COMPOSITE_TYPE:
02223             appendStringInfo(buffer, _("composite type %s"),
02224                              relname);
02225             break;
02226         case RELKIND_FOREIGN_TABLE:
02227             appendStringInfo(buffer, _("foreign table %s"),
02228                              relname);
02229             break;
02230         default:
02231             /* shouldn't get here */
02232             appendStringInfo(buffer, _("relation %s"),
02233                              relname);
02234             break;
02235     }
02236 
02237     ReleaseSysCache(relTup);
02238 }
02239 
02240 /*
02241  * subroutine for getObjectDescription: describe an operator family
02242  */
02243 static void
02244 getOpFamilyDescription(StringInfo buffer, Oid opfid)
02245 {
02246     HeapTuple   opfTup;
02247     Form_pg_opfamily opfForm;
02248     HeapTuple   amTup;
02249     Form_pg_am  amForm;
02250     char       *nspname;
02251 
02252     opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
02253     if (!HeapTupleIsValid(opfTup))
02254         elog(ERROR, "cache lookup failed for opfamily %u", opfid);
02255     opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
02256 
02257     amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
02258     if (!HeapTupleIsValid(amTup))
02259         elog(ERROR, "cache lookup failed for access method %u",
02260              opfForm->opfmethod);
02261     amForm = (Form_pg_am) GETSTRUCT(amTup);
02262 
02263     /* Qualify the name if not visible in search path */
02264     if (OpfamilyIsVisible(opfid))
02265         nspname = NULL;
02266     else
02267         nspname = get_namespace_name(opfForm->opfnamespace);
02268 
02269     appendStringInfo(buffer, _("operator family %s for access method %s"),
02270                      quote_qualified_identifier(nspname,
02271                                                 NameStr(opfForm->opfname)),
02272                      NameStr(amForm->amname));
02273 
02274     ReleaseSysCache(amTup);
02275     ReleaseSysCache(opfTup);
02276 }
02277 
02278 /*
02279  * SQL-level callable version of getObjectDescription
02280  */
02281 Datum
02282 pg_describe_object(PG_FUNCTION_ARGS)
02283 {
02284     Oid         classid = PG_GETARG_OID(0);
02285     Oid         objid = PG_GETARG_OID(1);
02286     int32       subobjid = PG_GETARG_INT32(2);
02287     char       *description;
02288     ObjectAddress address;
02289 
02290     /* for "pinned" items in pg_depend, return null */
02291     if (!OidIsValid(classid) && !OidIsValid(objid))
02292         PG_RETURN_NULL();
02293 
02294     address.classId = classid;
02295     address.objectId = objid;
02296     address.objectSubId = subobjid;
02297 
02298     description = getObjectDescription(&address);
02299     PG_RETURN_TEXT_P(cstring_to_text(description));
02300 }
02301 
02302 /*
02303  * SQL-level callable function to obtain object type + identity
02304  */
02305 Datum
02306 pg_identify_object(PG_FUNCTION_ARGS)
02307 {
02308     Oid         classid = PG_GETARG_OID(0);
02309     Oid         objid = PG_GETARG_OID(1);
02310     int32       subobjid = PG_GETARG_INT32(2);
02311     Oid         schema_oid = InvalidOid;
02312     const char *objname = NULL;
02313     ObjectAddress address;
02314     Datum       values[4];
02315     bool        nulls[4];
02316     TupleDesc   tupdesc;
02317     HeapTuple   htup;
02318 
02319     address.classId = classid;
02320     address.objectId = objid;
02321     address.objectSubId = subobjid;
02322 
02323     /*
02324      * Construct a tuple descriptor for the result row.  This must match this
02325      * function's pg_proc entry!
02326      */
02327     tupdesc = CreateTemplateTupleDesc(4, false);
02328     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
02329                        TEXTOID, -1, 0);
02330     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
02331                        TEXTOID, -1, 0);
02332     TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
02333                        TEXTOID, -1, 0);
02334     TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
02335                        TEXTOID, -1, 0);
02336 
02337     tupdesc = BlessTupleDesc(tupdesc);
02338 
02339     if (is_objectclass_supported(address.classId))
02340     {
02341         HeapTuple   objtup;
02342         Relation    catalog = heap_open(address.classId, AccessShareLock);
02343 
02344         objtup = get_catalog_object_by_oid(catalog, address.objectId);
02345         if (objtup != NULL)
02346         {
02347             bool        isnull;
02348             AttrNumber  nspAttnum;
02349             AttrNumber  nameAttnum;
02350 
02351             nspAttnum = get_object_attnum_namespace(address.classId);
02352             if (nspAttnum != InvalidAttrNumber)
02353             {
02354                 schema_oid = heap_getattr(objtup, nspAttnum,
02355                                           RelationGetDescr(catalog), &isnull);
02356                 if (isnull)
02357                     elog(ERROR, "invalid null namespace in object %u/%u/%d",
02358                          address.classId, address.objectId, address.objectSubId);
02359             }
02360 
02361             /*
02362              * We only return the object name if it can be used (together
02363              * with the schema name, if any) as an unique identifier.
02364              */
02365             if (get_object_namensp_unique(address.classId))
02366             {
02367                 nameAttnum = get_object_attnum_name(address.classId);
02368                 if (nameAttnum != InvalidAttrNumber)
02369                 {
02370                     Datum   nameDatum;
02371 
02372                     nameDatum = heap_getattr(objtup, nameAttnum,
02373                                              RelationGetDescr(catalog), &isnull);
02374                     if (isnull)
02375                         elog(ERROR, "invalid null name in object %u/%u/%d",
02376                              address.classId, address.objectId, address.objectSubId);
02377                     objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
02378                 }
02379             }
02380         }
02381 
02382         heap_close(catalog, AccessShareLock);
02383     }
02384 
02385     /* object type */
02386     values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
02387     nulls[0] = false;
02388 
02389     /* schema name */
02390     if (OidIsValid(schema_oid))
02391     {
02392         const char  *schema = quote_identifier(get_namespace_name(schema_oid));
02393 
02394         values[1] = CStringGetTextDatum(schema);
02395         nulls[1] = false;
02396     }
02397     else
02398         nulls[1] = true;
02399 
02400     /* object name */
02401     if (objname)
02402     {
02403         values[2] = CStringGetTextDatum(objname);
02404         nulls[2] = false;
02405     }
02406     else
02407         nulls[2] = true;
02408 
02409     /* object identity */
02410     values[3] = CStringGetTextDatum(getObjectIdentity(&address));
02411     nulls[3] = false;
02412 
02413     htup = heap_form_tuple(tupdesc, values, nulls);
02414 
02415     PG_RETURN_DATUM(HeapTupleGetDatum(htup));
02416 }
02417 
02418 /*
02419  * Return a palloc'ed string that describes the type of object that the
02420  * passed address is for.
02421  */
02422 char *
02423 getObjectTypeDescription(const ObjectAddress *object)
02424 {
02425     StringInfoData buffer;
02426 
02427     initStringInfo(&buffer);
02428 
02429     switch (getObjectClass(object))
02430     {
02431         case OCLASS_CLASS:
02432             getRelationTypeDescription(&buffer, object->objectId,
02433                                        object->objectSubId);
02434             break;
02435 
02436         case OCLASS_PROC:
02437             getProcedureTypeDescription(&buffer, object->objectId);
02438             break;
02439 
02440         case OCLASS_TYPE:
02441             appendStringInfo(&buffer, "type");
02442             break;
02443 
02444         case OCLASS_CAST:
02445             appendStringInfo(&buffer, "cast");
02446             break;
02447 
02448         case OCLASS_COLLATION:
02449             appendStringInfo(&buffer, "collation");
02450             break;
02451 
02452         case OCLASS_CONSTRAINT:
02453             getConstraintTypeDescription(&buffer, object->objectId);
02454             break;
02455 
02456         case OCLASS_CONVERSION:
02457             appendStringInfo(&buffer, "conversion");
02458             break;
02459 
02460         case OCLASS_DEFAULT:
02461             appendStringInfo(&buffer, "default value");
02462             break;
02463 
02464         case OCLASS_LANGUAGE:
02465             appendStringInfo(&buffer, "language");
02466             break;
02467 
02468         case OCLASS_LARGEOBJECT:
02469             appendStringInfo(&buffer, "large object");
02470             break;
02471 
02472         case OCLASS_OPERATOR:
02473             appendStringInfo(&buffer, "operator");
02474             break;
02475 
02476         case OCLASS_OPCLASS:
02477             appendStringInfo(&buffer, "operator class");
02478             break;
02479 
02480         case OCLASS_OPFAMILY:
02481             appendStringInfo(&buffer, "operator family");
02482             break;
02483 
02484         case OCLASS_AMOP:
02485             appendStringInfo(&buffer, "operator of access method");
02486             break;
02487 
02488         case OCLASS_AMPROC:
02489             appendStringInfo(&buffer, "function of access method");
02490             break;
02491 
02492         case OCLASS_REWRITE:
02493             appendStringInfo(&buffer, "rule");
02494             break;
02495 
02496         case OCLASS_TRIGGER:
02497             appendStringInfo(&buffer, "trigger");
02498             break;
02499 
02500         case OCLASS_SCHEMA:
02501             appendStringInfo(&buffer, "schema");
02502             break;
02503 
02504         case OCLASS_TSPARSER:
02505             appendStringInfo(&buffer, "text search parser");
02506             break;
02507 
02508         case OCLASS_TSDICT:
02509             appendStringInfo(&buffer, "text search dictionary");
02510             break;
02511 
02512         case OCLASS_TSTEMPLATE:
02513             appendStringInfo(&buffer, "text search template");
02514             break;
02515 
02516         case OCLASS_TSCONFIG:
02517             appendStringInfo(&buffer, "text search configuration");
02518             break;
02519 
02520         case OCLASS_ROLE:
02521             appendStringInfo(&buffer, "role");
02522             break;
02523 
02524         case OCLASS_DATABASE:
02525             appendStringInfo(&buffer, "database");
02526             break;
02527 
02528         case OCLASS_TBLSPACE:
02529             appendStringInfo(&buffer, "tablespace");
02530             break;
02531 
02532         case OCLASS_FDW:
02533             appendStringInfo(&buffer, "foreign-data wrapper");
02534             break;
02535 
02536         case OCLASS_FOREIGN_SERVER:
02537             appendStringInfo(&buffer, "server");
02538             break;
02539 
02540         case OCLASS_USER_MAPPING:
02541             appendStringInfo(&buffer, "user mapping");
02542             break;
02543 
02544         case OCLASS_DEFACL:
02545             appendStringInfo(&buffer, "default acl");
02546             break;
02547 
02548         case OCLASS_EXTENSION:
02549             appendStringInfo(&buffer, "extension");
02550             break;
02551 
02552         case OCLASS_EVENT_TRIGGER:
02553             appendStringInfo(&buffer, "event trigger");
02554             break;
02555 
02556         default:
02557             appendStringInfo(&buffer, "unrecognized %u", object->classId);
02558             break;
02559     }
02560 
02561     return buffer.data;
02562 }
02563 
02564 /*
02565  * subroutine for getObjectTypeDescription: describe a relation type
02566  */
02567 static void
02568 getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
02569 {
02570     HeapTuple   relTup;
02571     Form_pg_class relForm;
02572 
02573     relTup = SearchSysCache1(RELOID,
02574                              ObjectIdGetDatum(relid));
02575     if (!HeapTupleIsValid(relTup))
02576         elog(ERROR, "cache lookup failed for relation %u", relid);
02577     relForm = (Form_pg_class) GETSTRUCT(relTup);
02578 
02579     switch (relForm->relkind)
02580     {
02581         case RELKIND_RELATION:
02582             appendStringInfo(buffer, "table");
02583             break;
02584         case RELKIND_INDEX:
02585             appendStringInfo(buffer, "index");
02586             break;
02587         case RELKIND_SEQUENCE:
02588             appendStringInfo(buffer, "sequence");
02589             break;
02590         case RELKIND_TOASTVALUE:
02591             appendStringInfo(buffer, "toast table");
02592             break;
02593         case RELKIND_VIEW:
02594             appendStringInfo(buffer, "view");
02595             break;
02596         case RELKIND_MATVIEW:
02597             appendStringInfo(buffer, "materialized view");
02598             break;
02599         case RELKIND_COMPOSITE_TYPE:
02600             appendStringInfo(buffer, "composite type");
02601             break;
02602         case RELKIND_FOREIGN_TABLE:
02603             appendStringInfo(buffer, "foreign table");
02604             break;
02605         default:
02606             /* shouldn't get here */
02607             appendStringInfo(buffer, "relation");
02608             break;
02609     }
02610 
02611     if (objectSubId != 0)
02612         appendStringInfo(buffer, " column");
02613 
02614     ReleaseSysCache(relTup);
02615 }
02616 
02617 /*
02618  * subroutine for getObjectTypeDescription: describe a constraint type
02619  */
02620 static void
02621 getConstraintTypeDescription(StringInfo buffer, Oid constroid)
02622 {
02623     Relation    constrRel;
02624     HeapTuple   constrTup;
02625     Form_pg_constraint  constrForm;
02626 
02627     constrRel = heap_open(ConstraintRelationId, AccessShareLock);
02628     constrTup = get_catalog_object_by_oid(constrRel, constroid);
02629     if (!HeapTupleIsValid(constrTup))
02630         elog(ERROR, "cache lookup failed for constraint %u", constroid);
02631 
02632     constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
02633 
02634     if (OidIsValid(constrForm->conrelid))
02635         appendStringInfoString(buffer, "table constraint");
02636     else if (OidIsValid(constrForm->contypid))
02637         appendStringInfoString(buffer, "domain constraint");
02638     else
02639         elog(ERROR, "invalid constraint %u", HeapTupleGetOid(constrTup));
02640 
02641     heap_close(constrRel, AccessShareLock);
02642 }
02643 
02644 /*
02645  * subroutine for getObjectTypeDescription: describe a procedure type
02646  */
02647 static void
02648 getProcedureTypeDescription(StringInfo buffer, Oid procid)
02649 {
02650     HeapTuple   procTup;
02651     Form_pg_proc procForm;
02652 
02653     procTup = SearchSysCache1(PROCOID,
02654                              ObjectIdGetDatum(procid));
02655     if (!HeapTupleIsValid(procTup))
02656         elog(ERROR, "cache lookup failed for procedure %u", procid);
02657     procForm = (Form_pg_proc) GETSTRUCT(procTup);
02658 
02659     if (procForm->proisagg)
02660         appendStringInfo(buffer, "aggregate");
02661     else
02662         appendStringInfo(buffer, "function");
02663 
02664     ReleaseSysCache(procTup);
02665 }
02666 
02667 /*
02668  * Return a palloc'ed string that identifies an object.
02669  *
02670  * This is for machine consumption, so it's not translated.  All elements are
02671  * schema-qualified when appropriate.
02672  */
02673 char *
02674 getObjectIdentity(const ObjectAddress *object)
02675 {
02676     StringInfoData buffer;
02677 
02678     initStringInfo(&buffer);
02679 
02680     switch (getObjectClass(object))
02681     {
02682         case OCLASS_CLASS:
02683             getRelationIdentity(&buffer, object->objectId);
02684             if (object->objectSubId != 0)
02685             {
02686                 char   *attr;
02687 
02688                 attr = get_relid_attribute_name(object->objectId,
02689                                                 object->objectSubId);
02690                 appendStringInfo(&buffer, ".%s", quote_identifier(attr));
02691             }
02692             break;
02693 
02694         case OCLASS_PROC:
02695             appendStringInfo(&buffer, "%s",
02696                              format_procedure_qualified(object->objectId));
02697             break;
02698 
02699         case OCLASS_TYPE:
02700             appendStringInfo(&buffer, "%s",
02701                              format_type_be_qualified(object->objectId));
02702             break;
02703 
02704         case OCLASS_CAST:
02705             {
02706                 Relation    castRel;
02707                 HeapTuple   tup;
02708                 Form_pg_cast castForm;
02709 
02710                 castRel = heap_open(CastRelationId, AccessShareLock);
02711 
02712                 tup = get_catalog_object_by_oid(castRel, object->objectId);
02713 
02714                 if (!HeapTupleIsValid(tup))
02715                     elog(ERROR, "could not find tuple for cast %u",
02716                          object->objectId);
02717 
02718                 castForm = (Form_pg_cast) GETSTRUCT(tup);
02719 
02720                 appendStringInfo(&buffer, "(%s AS %s)",
02721                                  format_type_be_qualified(castForm->castsource),
02722                                  format_type_be_qualified(castForm->casttarget));
02723 
02724                 heap_close(castRel, AccessShareLock);
02725                 break;
02726             }
02727 
02728         case OCLASS_COLLATION:
02729             {
02730                 HeapTuple   collTup;
02731                 Form_pg_collation coll;
02732                 char   *schema;
02733 
02734                 collTup = SearchSysCache1(COLLOID,
02735                                           ObjectIdGetDatum(object->objectId));
02736                 if (!HeapTupleIsValid(collTup))
02737                     elog(ERROR, "cache lookup failed for collation %u",
02738                          object->objectId);
02739                 coll = (Form_pg_collation) GETSTRUCT(collTup);
02740                 schema = get_namespace_name(coll->collnamespace);
02741                 appendStringInfoString(&buffer,
02742                                        quote_qualified_identifier(schema,
02743                                                                   NameStr(coll->collname)));
02744                 ReleaseSysCache(collTup);
02745                 break;
02746             }
02747 
02748         case OCLASS_CONSTRAINT:
02749             {
02750                 HeapTuple   conTup;
02751                 Form_pg_constraint con;
02752 
02753                 conTup = SearchSysCache1(CONSTROID,
02754                                          ObjectIdGetDatum(object->objectId));
02755                 if (!HeapTupleIsValid(conTup))
02756                     elog(ERROR, "cache lookup failed for constraint %u",
02757                          object->objectId);
02758                 con = (Form_pg_constraint) GETSTRUCT(conTup);
02759 
02760                 if (OidIsValid(con->conrelid))
02761                 {
02762                     appendStringInfo(&buffer, "%s on ",
02763                                      quote_identifier(NameStr(con->conname)));
02764                     getRelationIdentity(&buffer, con->conrelid);
02765                 }
02766                 else
02767                 {
02768                     ObjectAddress   domain;
02769 
02770                     domain.classId = TypeRelationId;
02771                     domain.objectId = con->contypid;
02772                     domain.objectSubId = 0;
02773 
02774                     appendStringInfo(&buffer, "%s on %s",
02775                                      quote_identifier(NameStr(con->conname)),
02776                                      getObjectIdentity(&domain));
02777                 }
02778 
02779                 ReleaseSysCache(conTup);
02780                 break;
02781             }
02782 
02783         case OCLASS_CONVERSION:
02784             {
02785                 HeapTuple   conTup;
02786                 Form_pg_conversion conForm;
02787 
02788                 conTup = SearchSysCache1(CONVOID,
02789                                          ObjectIdGetDatum(object->objectId));
02790                 if (!HeapTupleIsValid(conTup))
02791                     elog(ERROR, "cache lookup failed for conversion %u",
02792                          object->objectId);
02793                 conForm = (Form_pg_conversion) GETSTRUCT(conTup);
02794                 appendStringInfo(&buffer, "%s",
02795                                  quote_identifier(NameStr(conForm->conname)));
02796                 ReleaseSysCache(conTup);
02797                 break;
02798             }
02799 
02800         case OCLASS_DEFAULT:
02801             {
02802                 Relation    attrdefDesc;
02803                 ScanKeyData skey[1];
02804                 SysScanDesc adscan;
02805 
02806                 HeapTuple   tup;
02807                 Form_pg_attrdef attrdef;
02808                 ObjectAddress colobject;
02809 
02810                 attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
02811 
02812                 ScanKeyInit(&skey[0],
02813                             ObjectIdAttributeNumber,
02814                             BTEqualStrategyNumber, F_OIDEQ,
02815                             ObjectIdGetDatum(object->objectId));
02816 
02817                 adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
02818                                             true, SnapshotNow, 1, skey);
02819 
02820                 tup = systable_getnext(adscan);
02821 
02822                 if (!HeapTupleIsValid(tup))
02823                     elog(ERROR, "could not find tuple for attrdef %u",
02824                          object->objectId);
02825 
02826                 attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
02827 
02828                 colobject.classId = RelationRelationId;
02829                 colobject.objectId = attrdef->adrelid;
02830                 colobject.objectSubId = attrdef->adnum;
02831 
02832                 appendStringInfo(&buffer, "for %s",
02833                                  getObjectIdentity(&colobject));
02834 
02835                 systable_endscan(adscan);
02836                 heap_close(attrdefDesc, AccessShareLock);
02837                 break;
02838             }
02839 
02840         case OCLASS_LANGUAGE:
02841             {
02842                 HeapTuple   langTup;
02843                 Form_pg_language langForm;
02844 
02845                 langTup = SearchSysCache1(LANGOID,
02846                                           ObjectIdGetDatum(object->objectId));
02847                 if (!HeapTupleIsValid(langTup))
02848                     elog(ERROR, "cache lookup failed for language %u",
02849                          object->objectId);
02850                 langForm = (Form_pg_language) GETSTRUCT(langTup);
02851                 appendStringInfo(&buffer, "%s",
02852                                  quote_identifier(NameStr(langForm->lanname)));
02853                 ReleaseSysCache(langTup);
02854                 break;
02855             }
02856         case OCLASS_LARGEOBJECT:
02857             appendStringInfo(&buffer, "%u",
02858                              object->objectId);
02859             break;
02860 
02861         case OCLASS_OPERATOR:
02862             appendStringInfo(&buffer, "%s",
02863                              format_operator_qualified(object->objectId));
02864             break;
02865 
02866         case OCLASS_OPCLASS:
02867             {
02868                 HeapTuple   opcTup;
02869                 Form_pg_opclass opcForm;
02870                 HeapTuple   amTup;
02871                 Form_pg_am  amForm;
02872                 char       *schema;
02873 
02874                 opcTup = SearchSysCache1(CLAOID,
02875                                          ObjectIdGetDatum(object->objectId));
02876                 if (!HeapTupleIsValid(opcTup))
02877                     elog(ERROR, "cache lookup failed for opclass %u",
02878                          object->objectId);
02879                 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
02880                 schema = get_namespace_name(opcForm->opcnamespace);
02881 
02882                 amTup = SearchSysCache1(AMOID,
02883                                         ObjectIdGetDatum(opcForm->opcmethod));
02884                 if (!HeapTupleIsValid(amTup))
02885                     elog(ERROR, "cache lookup failed for access method %u",
02886                          opcForm->opcmethod);
02887                 amForm = (Form_pg_am) GETSTRUCT(amTup);
02888 
02889                 appendStringInfo(&buffer,
02890                                  "%s",
02891                                  quote_qualified_identifier(schema,
02892                                                             NameStr(opcForm->opcname)));
02893                 appendStringInfo(&buffer, " for %s",
02894                                  quote_identifier(NameStr(amForm->amname)));
02895 
02896                 ReleaseSysCache(amTup);
02897                 ReleaseSysCache(opcTup);
02898                 break;
02899             }
02900 
02901         case OCLASS_OPFAMILY:
02902             getOpFamilyIdentity(&buffer, object->objectId);
02903             break;
02904 
02905         case OCLASS_AMOP:
02906             {
02907                 Relation    amopDesc;
02908                 HeapTuple   tup;
02909                 ScanKeyData skey[1];
02910                 SysScanDesc amscan;
02911                 Form_pg_amop amopForm;
02912                 StringInfoData opfam;
02913 
02914                 amopDesc = heap_open(AccessMethodOperatorRelationId,
02915                                      AccessShareLock);
02916 
02917                 ScanKeyInit(&skey[0],
02918                             ObjectIdAttributeNumber,
02919                             BTEqualStrategyNumber, F_OIDEQ,
02920                             ObjectIdGetDatum(object->objectId));
02921 
02922                 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
02923                                             SnapshotNow, 1, skey);
02924 
02925                 tup = systable_getnext(amscan);
02926 
02927                 if (!HeapTupleIsValid(tup))
02928                     elog(ERROR, "could not find tuple for amop entry %u",
02929                          object->objectId);
02930 
02931                 amopForm = (Form_pg_amop) GETSTRUCT(tup);
02932 
02933                 initStringInfo(&opfam);
02934                 getOpFamilyIdentity(&opfam, amopForm->amopfamily);
02935 
02936                 appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
02937                                  amopForm->amopstrategy,
02938                                  format_type_be_qualified(amopForm->amoplefttype),
02939                                  format_type_be_qualified(amopForm->amoprighttype),
02940                                  opfam.data);
02941 
02942                 pfree(opfam.data);
02943 
02944                 systable_endscan(amscan);
02945                 heap_close(amopDesc, AccessShareLock);
02946                 break;
02947             }
02948 
02949         case OCLASS_AMPROC:
02950             {
02951                 Relation    amprocDesc;
02952                 ScanKeyData skey[1];
02953                 SysScanDesc amscan;
02954                 HeapTuple   tup;
02955                 Form_pg_amproc amprocForm;
02956                 StringInfoData opfam;
02957 
02958                 amprocDesc = heap_open(AccessMethodProcedureRelationId,
02959                                        AccessShareLock);
02960 
02961                 ScanKeyInit(&skey[0],
02962                             ObjectIdAttributeNumber,
02963                             BTEqualStrategyNumber, F_OIDEQ,
02964                             ObjectIdGetDatum(object->objectId));
02965 
02966                 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
02967                                             SnapshotNow, 1, skey);
02968 
02969                 tup = systable_getnext(amscan);
02970 
02971                 if (!HeapTupleIsValid(tup))
02972                     elog(ERROR, "could not find tuple for amproc entry %u",
02973                          object->objectId);
02974 
02975                 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
02976 
02977                 initStringInfo(&opfam);
02978                 getOpFamilyIdentity(&opfam, amprocForm->amprocfamily);
02979 
02980                 appendStringInfo(&buffer, "function %d (%s, %s) of %s",
02981                                  amprocForm->amprocnum,
02982                                  format_type_be_qualified(amprocForm->amproclefttype),
02983                                  format_type_be_qualified(amprocForm->amprocrighttype),
02984                                  opfam.data);
02985 
02986                 pfree(opfam.data);
02987 
02988                 systable_endscan(amscan);
02989                 heap_close(amprocDesc, AccessShareLock);
02990                 break;
02991             }
02992 
02993         case OCLASS_REWRITE:
02994             {
02995                 Relation    ruleDesc;
02996                 HeapTuple   tup;
02997                 Form_pg_rewrite rule;
02998 
02999                 ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
03000 
03001                 tup = get_catalog_object_by_oid(ruleDesc, object->objectId);
03002 
03003                 if (!HeapTupleIsValid(tup))
03004                     elog(ERROR, "could not find tuple for rule %u",
03005                          object->objectId);
03006 
03007                 rule = (Form_pg_rewrite) GETSTRUCT(tup);
03008 
03009                 appendStringInfo(&buffer, "%s on ",
03010                                  quote_identifier(NameStr(rule->rulename)));
03011                 getRelationIdentity(&buffer, rule->ev_class);
03012 
03013                 heap_close(ruleDesc, AccessShareLock);
03014                 break;
03015             }
03016 
03017         case OCLASS_TRIGGER:
03018             {
03019                 Relation    trigDesc;
03020                 HeapTuple   tup;
03021                 Form_pg_trigger trig;
03022 
03023                 trigDesc = heap_open(TriggerRelationId, AccessShareLock);
03024 
03025                 tup = get_catalog_object_by_oid(trigDesc, object->objectId);
03026 
03027                 if (!HeapTupleIsValid(tup))
03028                     elog(ERROR, "could not find tuple for trigger %u",
03029                          object->objectId);
03030 
03031                 trig = (Form_pg_trigger) GETSTRUCT(tup);
03032 
03033                 appendStringInfo(&buffer, "%s on ",
03034                                  quote_identifier(NameStr(trig->tgname)));
03035                 getRelationIdentity(&buffer, trig->tgrelid);
03036 
03037                 heap_close(trigDesc, AccessShareLock);
03038                 break;
03039             }
03040 
03041         case OCLASS_SCHEMA:
03042             {
03043                 char       *nspname;
03044 
03045                 nspname = get_namespace_name(object->objectId);
03046                 if (!nspname)
03047                     elog(ERROR, "cache lookup failed for namespace %u",
03048                          object->objectId);
03049                 appendStringInfo(&buffer, "%s",
03050                                  quote_identifier(nspname));
03051                 break;
03052             }
03053 
03054         case OCLASS_TSPARSER:
03055             {
03056                 HeapTuple   tup;
03057                 Form_pg_ts_parser   formParser;
03058 
03059                 tup = SearchSysCache1(TSPARSEROID,
03060                                       ObjectIdGetDatum(object->objectId));
03061                 if (!HeapTupleIsValid(tup))
03062                     elog(ERROR, "cache lookup failed for text search parser %u",
03063                          object->objectId);
03064                 formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
03065                 appendStringInfo(&buffer, "%s",
03066                                  quote_identifier(NameStr(formParser->prsname)));
03067                 ReleaseSysCache(tup);
03068                 break;
03069             }
03070 
03071         case OCLASS_TSDICT:
03072             {
03073                 HeapTuple   tup;
03074                 Form_pg_ts_dict     formDict;
03075 
03076                 tup = SearchSysCache1(TSDICTOID,
03077                                       ObjectIdGetDatum(object->objectId));
03078                 if (!HeapTupleIsValid(tup))
03079                     elog(ERROR, "cache lookup failed for text search dictionary %u",
03080                          object->objectId);
03081                 formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
03082                 appendStringInfo(&buffer, "%s",
03083                                  quote_identifier(NameStr(formDict->dictname)));
03084                 ReleaseSysCache(tup);
03085                 break;
03086             }
03087 
03088         case OCLASS_TSTEMPLATE:
03089             {
03090                 HeapTuple   tup;
03091                 Form_pg_ts_template formTmpl;
03092 
03093                 tup = SearchSysCache1(TSTEMPLATEOID,
03094                                       ObjectIdGetDatum(object->objectId));
03095                 if (!HeapTupleIsValid(tup))
03096                     elog(ERROR, "cache lookup failed for text search template %u",
03097                          object->objectId);
03098                 formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
03099                 appendStringInfo(&buffer, "%s",
03100                                  quote_identifier(NameStr(formTmpl->tmplname)));
03101                 ReleaseSysCache(tup);
03102                 break;
03103             }
03104 
03105         case OCLASS_TSCONFIG:
03106             {
03107                 HeapTuple   tup;
03108                 Form_pg_ts_config formCfg;
03109 
03110                 tup = SearchSysCache1(TSCONFIGOID,
03111                                       ObjectIdGetDatum(object->objectId));
03112                 if (!HeapTupleIsValid(tup))
03113                     elog(ERROR, "cache lookup failed for text search configuration %u",
03114                          object->objectId);
03115                 formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
03116                 appendStringInfo(&buffer, "%s",
03117                                  quote_identifier(NameStr(formCfg->cfgname)));
03118                 ReleaseSysCache(tup);
03119                 break;
03120             }
03121 
03122         case OCLASS_ROLE:
03123             {
03124                 char   *username;
03125 
03126                 username = GetUserNameFromId(object->objectId);
03127                 appendStringInfo(&buffer, "%s",
03128                                  quote_identifier(username));
03129                 break;
03130             }
03131 
03132         case OCLASS_DATABASE:
03133             {
03134                 char       *datname;
03135 
03136                 datname = get_database_name(object->objectId);
03137                 if (!datname)
03138                     elog(ERROR, "cache lookup failed for database %u",
03139                          object->objectId);
03140                 appendStringInfo(&buffer, "%s",
03141                                  quote_identifier(datname));
03142                 break;
03143             }
03144 
03145         case OCLASS_TBLSPACE:
03146             {
03147                 char       *tblspace;
03148 
03149                 tblspace = get_tablespace_name(object->objectId);
03150                 if (!tblspace)
03151                     elog(ERROR, "cache lookup failed for tablespace %u",
03152                          object->objectId);
03153                 appendStringInfo(&buffer, "%s",
03154                                  quote_identifier(tblspace));
03155                 break;
03156             }
03157 
03158         case OCLASS_FDW:
03159             {
03160                 ForeignDataWrapper *fdw;
03161 
03162                 fdw = GetForeignDataWrapper(object->objectId);
03163                 appendStringInfo(&buffer, "%s",
03164                                  quote_identifier(fdw->fdwname));
03165                 break;
03166             }
03167 
03168         case OCLASS_FOREIGN_SERVER:
03169             {
03170                 ForeignServer *srv;
03171 
03172                 srv = GetForeignServer(object->objectId);
03173                 appendStringInfo(&buffer, "%s",
03174                                  quote_identifier(srv->servername));
03175                 break;
03176             }
03177 
03178         case OCLASS_USER_MAPPING:
03179             {
03180                 HeapTuple   tup;
03181                 Oid         useid;
03182                 const char *usename;
03183 
03184                 tup = SearchSysCache1(USERMAPPINGOID,
03185                                       ObjectIdGetDatum(object->objectId));
03186                 if (!HeapTupleIsValid(tup))
03187                     elog(ERROR, "cache lookup failed for user mapping %u",
03188                          object->objectId);
03189 
03190                 useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
03191 
03192                 ReleaseSysCache(tup);
03193 
03194                 if (OidIsValid(useid))
03195                     usename = quote_identifier(GetUserNameFromId(useid));
03196                 else
03197                     usename = "public";
03198 
03199                 appendStringInfo(&buffer, "%s", usename);
03200                 break;
03201             }
03202 
03203         case OCLASS_DEFACL:
03204             {
03205                 Relation    defaclrel;
03206                 ScanKeyData skey[1];
03207                 SysScanDesc rcscan;
03208 
03209                 HeapTuple   tup;
03210                 Form_pg_default_acl defacl;
03211 
03212                 defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
03213 
03214                 ScanKeyInit(&skey[0],
03215                             ObjectIdAttributeNumber,
03216                             BTEqualStrategyNumber, F_OIDEQ,
03217                             ObjectIdGetDatum(object->objectId));
03218 
03219                 rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
03220                                             true, SnapshotNow, 1, skey);
03221 
03222                 tup = systable_getnext(rcscan);
03223 
03224                 if (!HeapTupleIsValid(tup))
03225                     elog(ERROR, "could not find tuple for default ACL %u",
03226                          object->objectId);
03227 
03228                 defacl = (Form_pg_default_acl) GETSTRUCT(tup);
03229 
03230                 appendStringInfo(&buffer,
03231                                  "for role %s",
03232                                  quote_identifier(GetUserNameFromId(defacl->defaclrole)));
03233 
03234                 if (OidIsValid(defacl->defaclnamespace))
03235                 {
03236                     char   *schema;
03237 
03238                     schema = get_namespace_name(defacl->defaclnamespace);
03239                     appendStringInfo(&buffer,
03240                                      " in schema %s",
03241                                      quote_identifier(schema));
03242                 }
03243 
03244                 switch (defacl->defaclobjtype)
03245                 {
03246                     case DEFACLOBJ_RELATION:
03247                         appendStringInfoString(&buffer,
03248                                                " on tables");
03249                         break;
03250                     case DEFACLOBJ_SEQUENCE:
03251                         appendStringInfoString(&buffer,
03252                                                " on sequences");
03253                         break;
03254                     case DEFACLOBJ_FUNCTION:
03255                         appendStringInfoString(&buffer,
03256                                                " on functions");
03257                         break;
03258                     case DEFACLOBJ_TYPE:
03259                         appendStringInfoString(&buffer,
03260                                                " on types");
03261                         break;
03262                 }
03263 
03264                 systable_endscan(rcscan);
03265                 heap_close(defaclrel, AccessShareLock);
03266                 break;
03267             }
03268 
03269         case OCLASS_EXTENSION:
03270             {
03271                 char       *extname;
03272 
03273                 extname = get_extension_name(object->objectId);
03274                 if (!extname)
03275                     elog(ERROR, "cache lookup failed for extension %u",
03276                          object->objectId);
03277                 appendStringInfo(&buffer, "%s",
03278                                  quote_identifier(extname));
03279                 break;
03280             }
03281 
03282         case OCLASS_EVENT_TRIGGER:
03283             {
03284                 HeapTuple   tup;
03285                 Form_pg_event_trigger trigForm;
03286 
03287                 tup = SearchSysCache1(EVENTTRIGGEROID,
03288                                       ObjectIdGetDatum(object->objectId));
03289                 if (!HeapTupleIsValid(tup))
03290                     elog(ERROR, "cache lookup failed for event trigger %u",
03291                          object->objectId);
03292                 trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
03293                 appendStringInfo(&buffer, "%s",
03294                                  quote_identifier(NameStr(trigForm->evtname)));
03295                 ReleaseSysCache(tup);
03296                 break;
03297             }
03298 
03299         default:
03300             appendStringInfo(&buffer, "unrecognized object %u %u %d",
03301                              object->classId,
03302                              object->objectId,
03303                              object->objectSubId);
03304             break;
03305     }
03306 
03307     return buffer.data;
03308 }
03309 
03310 static void
03311 getOpFamilyIdentity(StringInfo buffer, Oid opfid)
03312 {
03313     HeapTuple   opfTup;
03314     Form_pg_opfamily opfForm;
03315     HeapTuple   amTup;
03316     Form_pg_am  amForm;
03317     char       *schema;
03318 
03319     opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
03320     if (!HeapTupleIsValid(opfTup))
03321         elog(ERROR, "cache lookup failed for opfamily %u", opfid);
03322     opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
03323 
03324     amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
03325     if (!HeapTupleIsValid(amTup))
03326         elog(ERROR, "cache lookup failed for access method %u",
03327              opfForm->opfmethod);
03328     amForm = (Form_pg_am) GETSTRUCT(amTup);
03329 
03330     schema = get_namespace_name(opfForm->opfnamespace);
03331     appendStringInfo(buffer, "%s for %s",
03332                      quote_qualified_identifier(schema,
03333                                                 NameStr(opfForm->opfname)),
03334                      NameStr(amForm->amname));
03335 
03336     ReleaseSysCache(amTup);
03337     ReleaseSysCache(opfTup);
03338 }
03339 
03340 /*
03341  * Append the relation identity (quoted qualified name) to the given
03342  * StringInfo.
03343  */
03344 static void
03345 getRelationIdentity(StringInfo buffer, Oid relid)
03346 {
03347     HeapTuple   relTup;
03348     Form_pg_class relForm;
03349     char       *schema;
03350 
03351     relTup = SearchSysCache1(RELOID,
03352                              ObjectIdGetDatum(relid));
03353     if (!HeapTupleIsValid(relTup))
03354         elog(ERROR, "cache lookup failed for relation %u", relid);
03355     relForm = (Form_pg_class) GETSTRUCT(relTup);
03356 
03357     schema = get_namespace_name(relForm->relnamespace);
03358     appendStringInfo(buffer, "%s",
03359                      quote_qualified_identifier(schema,
03360                                                 NameStr(relForm->relname)));
03361 
03362     ReleaseSysCache(relTup);
03363 }