]> granicus.if.org Git - postgresql/commitdiff
Allow extracting machine-readable object identity
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 20 Mar 2013 21:19:19 +0000 (18:19 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 20 Mar 2013 21:19:19 +0000 (18:19 -0300)
Introduce pg_identify_object(oid,oid,int4), which is similar in spirit
to pg_describe_object but instead produces a row of machine-readable
information to uniquely identify the given object, without resorting to
OIDs or other internal representation.  This is intended to be used in
the event trigger implementation, to report objects being operated on;
but it has usefulness of its own.

Catalog version bumped because of the new function.

12 files changed:
doc/src/sgml/func.sgml
src/backend/catalog/dependency.c
src/backend/catalog/objectaddress.c
src/backend/commands/alter.c
src/backend/parser/gram.y
src/backend/utils/adt/format_type.c
src/backend/utils/adt/regproc.c
src/include/catalog/catversion.h
src/include/catalog/dependency.h
src/include/catalog/objectaddress.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h

index 51df17248a5ebad7d7fb144a396753bfdcad3d3e..490d7106435510f3c87771d53c62ee9bbfd54719 100644 (file)
@@ -13930,6 +13930,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
     <primary>pg_describe_object</primary>
    </indexterm>
 
+   <indexterm>
+    <primary>pg_identify_object</primary>
+   </indexterm>
+
    <indexterm>
     <primary>pg_get_constraintdef</primary>
    </indexterm>
@@ -14029,6 +14033,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
        <entry><type>text</type></entry>
        <entry>get description of a database object</entry>
       </row>
+      <row>
+       <entry><literal><function>pg_identify_object(<parameter>catalog_id</parameter> <type>oid</>, <parameter>object_id</parameter> <type>oid</>, <parameter>object_sub_id</parameter> <type>integer</>)</function></literal></entry>
+       <entry><parameter>type</> <type>text</>, <parameter>schema</> <type>text</>, <parameter>name</> <type>text</>, <parameter>identity</> <type>text</></entry>
+       <entry>get identity of a database object</entry>
+      </row>
       <row>
        <entry><literal><function>pg_get_constraintdef(<parameter>constraint_oid</parameter>)</function></literal></entry>
        <entry><type>text</type></entry>
@@ -14273,12 +14282,30 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
   </para>
 
   <para>
-   <function>pg_describe_object</function> returns a description of a database
+   <function>pg_describe_object</function> returns a textual description of a database
    object specified by catalog OID, object OID and a (possibly zero) sub-object ID.
+   This description is intended to be human-readable, and might be translated,
+   depending on server configuration.
    This is useful to determine the identity of an object as stored in the
    <structname>pg_depend</structname> catalog.
   </para>
 
+  <para>
+   <function>pg_identify_object</function> returns a row containing enough information
+   to uniquely identify the database object specified by catalog OID, object OID and a
+   (possibly zero) sub-object ID.  This information is intended to be machine-readable,
+   and is never translated.
+   <parameter>type</> identifies the type of database object;
+   <parameter>schema</> is the schema name that the object belongs in, or
+   <literal>NULL</> for object types that do not belong to schemas;
+   <parameter>name</> is the name of the object, quoted if necessary, only
+   present if it can be used (alongside schema name, if pertinent) as an unique
+   identifier of the object, otherwise <literal>NULL</>;
+   <parameter>identity</> is the complete object identity, with the precise format
+   depending on object type, and each part within the format being
+   schema-qualified and quoted as necessary.
+  </para>
+
   <para>
    <function>pg_typeof</function> returns the OID of the data type of the
    value that is passed to it.  This can be helpful for troubleshooting or
index 7b8e0246339d4053074d34edb13ea250f1a8d5e1..ddf199049ef48032beff595b57dc7ba98c072a12 100644 (file)
 #include "postgres.h"
 
 #include "access/htup_details.h"
-#include "access/sysattr.h"
 #include "access/xact.h"
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
-#include "catalog/namespace.h"
 #include "catalog/objectaccess.h"
 #include "catalog/pg_amop.h"
 #include "catalog/pg_amproc.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
 #include "commands/comment.h"
-#include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/event_trigger.h"
 #include "commands/extension.h"
 #include "commands/proclang.h"
 #include "commands/schemacmds.h"
 #include "commands/seclabel.h"
-#include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "commands/typecmds.h"
-#include "foreign/foreign.h"
-#include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteRemove.h"
 #include "storage/lmgr.h"
-#include "utils/acl.h"
-#include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
@@ -196,8 +188,6 @@ static bool object_address_present_add_flags(const ObjectAddress *object,
 static bool stack_address_present_add_flags(const ObjectAddress *object,
                                                                int flags,
                                                                ObjectAddressStack *stack);
-static void getRelationDescription(StringInfo buffer, Oid relid);
-static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
 
 
 /*
@@ -2193,7 +2183,7 @@ getObjectClass(const ObjectAddress *object)
        /* only pg_class entries can have nonzero objectSubId */
        if (object->classId != RelationRelationId &&
                object->objectSubId != 0)
-               elog(ERROR, "invalid objectSubId 0 for object class %u",
+               elog(ERROR, "invalid non-zero objectSubId for object class %u",
                         object->classId);
 
        switch (object->classId)
@@ -2297,807 +2287,3 @@ getObjectClass(const ObjectAddress *object)
        elog(ERROR, "unrecognized object class: %u", object->classId);
        return OCLASS_CLASS;            /* keep compiler quiet */
 }
-
-/*
- * getObjectDescription: build an object description for messages
- *
- * The result is a palloc'd string.
- */
-char *
-getObjectDescription(const ObjectAddress *object)
-{
-       StringInfoData buffer;
-
-       initStringInfo(&buffer);
-
-       switch (getObjectClass(object))
-       {
-               case OCLASS_CLASS:
-                       getRelationDescription(&buffer, object->objectId);
-                       if (object->objectSubId != 0)
-                               appendStringInfo(&buffer, _(" column %s"),
-                                                                get_relid_attribute_name(object->objectId,
-                                                                                                          object->objectSubId));
-                       break;
-
-               case OCLASS_PROC:
-                       appendStringInfo(&buffer, _("function %s"),
-                                                        format_procedure(object->objectId));
-                       break;
-
-               case OCLASS_TYPE:
-                       appendStringInfo(&buffer, _("type %s"),
-                                                        format_type_be(object->objectId));
-                       break;
-
-               case OCLASS_CAST:
-                       {
-                               Relation        castDesc;
-                               ScanKeyData skey[1];
-                               SysScanDesc rcscan;
-                               HeapTuple       tup;
-                               Form_pg_cast castForm;
-
-                               castDesc = heap_open(CastRelationId, AccessShareLock);
-
-                               ScanKeyInit(&skey[0],
-                                                       ObjectIdAttributeNumber,
-                                                       BTEqualStrategyNumber, F_OIDEQ,
-                                                       ObjectIdGetDatum(object->objectId));
-
-                               rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
-                                                                                       SnapshotNow, 1, skey);
-
-                               tup = systable_getnext(rcscan);
-
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "could not find tuple for cast %u",
-                                                object->objectId);
-
-                               castForm = (Form_pg_cast) GETSTRUCT(tup);
-
-                               appendStringInfo(&buffer, _("cast from %s to %s"),
-                                                                format_type_be(castForm->castsource),
-                                                                format_type_be(castForm->casttarget));
-
-                               systable_endscan(rcscan);
-                               heap_close(castDesc, AccessShareLock);
-                               break;
-                       }
-
-               case OCLASS_COLLATION:
-                       {
-                               HeapTuple       collTup;
-                               Form_pg_collation coll;
-
-                               collTup = SearchSysCache1(COLLOID,
-                                                                                 ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(collTup))
-                                       elog(ERROR, "cache lookup failed for collation %u",
-                                                object->objectId);
-                               coll = (Form_pg_collation) GETSTRUCT(collTup);
-                               appendStringInfo(&buffer, _("collation %s"),
-                                                                NameStr(coll->collname));
-                               ReleaseSysCache(collTup);
-                               break;
-                       }
-
-               case OCLASS_CONSTRAINT:
-                       {
-                               HeapTuple       conTup;
-                               Form_pg_constraint con;
-
-                               conTup = SearchSysCache1(CONSTROID,
-                                                                                ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(conTup))
-                                       elog(ERROR, "cache lookup failed for constraint %u",
-                                                object->objectId);
-                               con = (Form_pg_constraint) GETSTRUCT(conTup);
-
-                               if (OidIsValid(con->conrelid))
-                               {
-                                       StringInfoData rel;
-
-                                       initStringInfo(&rel);
-                                       getRelationDescription(&rel, con->conrelid);
-                                       appendStringInfo(&buffer, _("constraint %s on %s"),
-                                                                        NameStr(con->conname), rel.data);
-                                       pfree(rel.data);
-                               }
-                               else
-                               {
-                                       appendStringInfo(&buffer, _("constraint %s"),
-                                                                        NameStr(con->conname));
-                               }
-
-                               ReleaseSysCache(conTup);
-                               break;
-                       }
-
-               case OCLASS_CONVERSION:
-                       {
-                               HeapTuple       conTup;
-
-                               conTup = SearchSysCache1(CONVOID,
-                                                                                ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(conTup))
-                                       elog(ERROR, "cache lookup failed for conversion %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("conversion %s"),
-                                NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
-                               ReleaseSysCache(conTup);
-                               break;
-                       }
-
-               case OCLASS_DEFAULT:
-                       {
-                               Relation        attrdefDesc;
-                               ScanKeyData skey[1];
-                               SysScanDesc adscan;
-                               HeapTuple       tup;
-                               Form_pg_attrdef attrdef;
-                               ObjectAddress colobject;
-
-                               attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
-
-                               ScanKeyInit(&skey[0],
-                                                       ObjectIdAttributeNumber,
-                                                       BTEqualStrategyNumber, F_OIDEQ,
-                                                       ObjectIdGetDatum(object->objectId));
-
-                               adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
-                                                                                       true, SnapshotNow, 1, skey);
-
-                               tup = systable_getnext(adscan);
-
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "could not find tuple for attrdef %u",
-                                                object->objectId);
-
-                               attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
-
-                               colobject.classId = RelationRelationId;
-                               colobject.objectId = attrdef->adrelid;
-                               colobject.objectSubId = attrdef->adnum;
-
-                               appendStringInfo(&buffer, _("default for %s"),
-                                                                getObjectDescription(&colobject));
-
-                               systable_endscan(adscan);
-                               heap_close(attrdefDesc, AccessShareLock);
-                               break;
-                       }
-
-               case OCLASS_LANGUAGE:
-                       {
-                               HeapTuple       langTup;
-
-                               langTup = SearchSysCache1(LANGOID,
-                                                                                 ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(langTup))
-                                       elog(ERROR, "cache lookup failed for language %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("language %s"),
-                                 NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
-                               ReleaseSysCache(langTup);
-                               break;
-                       }
-               case OCLASS_LARGEOBJECT:
-                       appendStringInfo(&buffer, _("large object %u"),
-                                                        object->objectId);
-                       break;
-
-               case OCLASS_OPERATOR:
-                       appendStringInfo(&buffer, _("operator %s"),
-                                                        format_operator(object->objectId));
-                       break;
-
-               case OCLASS_OPCLASS:
-                       {
-                               HeapTuple       opcTup;
-                               Form_pg_opclass opcForm;
-                               HeapTuple       amTup;
-                               Form_pg_am      amForm;
-                               char       *nspname;
-
-                               opcTup = SearchSysCache1(CLAOID,
-                                                                                ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(opcTup))
-                                       elog(ERROR, "cache lookup failed for opclass %u",
-                                                object->objectId);
-                               opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
-
-                               amTup = SearchSysCache1(AMOID,
-                                                                               ObjectIdGetDatum(opcForm->opcmethod));
-                               if (!HeapTupleIsValid(amTup))
-                                       elog(ERROR, "cache lookup failed for access method %u",
-                                                opcForm->opcmethod);
-                               amForm = (Form_pg_am) GETSTRUCT(amTup);
-
-                               /* Qualify the name if not visible in search path */
-                               if (OpclassIsVisible(object->objectId))
-                                       nspname = NULL;
-                               else
-                                       nspname = get_namespace_name(opcForm->opcnamespace);
-
-                               appendStringInfo(&buffer, _("operator class %s for access method %s"),
-                                                                quote_qualified_identifier(nspname,
-                                                                                                 NameStr(opcForm->opcname)),
-                                                                NameStr(amForm->amname));
-
-                               ReleaseSysCache(amTup);
-                               ReleaseSysCache(opcTup);
-                               break;
-                       }
-
-               case OCLASS_OPFAMILY:
-                       getOpFamilyDescription(&buffer, object->objectId);
-                       break;
-
-               case OCLASS_AMOP:
-                       {
-                               Relation        amopDesc;
-                               ScanKeyData skey[1];
-                               SysScanDesc amscan;
-                               HeapTuple       tup;
-                               Form_pg_amop amopForm;
-                               StringInfoData opfam;
-
-                               amopDesc = heap_open(AccessMethodOperatorRelationId,
-                                                                        AccessShareLock);
-
-                               ScanKeyInit(&skey[0],
-                                                       ObjectIdAttributeNumber,
-                                                       BTEqualStrategyNumber, F_OIDEQ,
-                                                       ObjectIdGetDatum(object->objectId));
-
-                               amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
-                                                                                       SnapshotNow, 1, skey);
-
-                               tup = systable_getnext(amscan);
-
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "could not find tuple for amop entry %u",
-                                                object->objectId);
-
-                               amopForm = (Form_pg_amop) GETSTRUCT(tup);
-
-                               initStringInfo(&opfam);
-                               getOpFamilyDescription(&opfam, amopForm->amopfamily);
-
-                               /*------
-                                  translator: %d is the operator strategy (a number), the
-                                  first two %s's are data type names, the third %s is the
-                                  description of the operator family, and the last %s is the
-                                  textual form of the operator with arguments.  */
-                               appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
-                                                                amopForm->amopstrategy,
-                                                                format_type_be(amopForm->amoplefttype),
-                                                                format_type_be(amopForm->amoprighttype),
-                                                                opfam.data,
-                                                                format_operator(amopForm->amopopr));
-
-                               pfree(opfam.data);
-
-                               systable_endscan(amscan);
-                               heap_close(amopDesc, AccessShareLock);
-                               break;
-                       }
-
-               case OCLASS_AMPROC:
-                       {
-                               Relation        amprocDesc;
-                               ScanKeyData skey[1];
-                               SysScanDesc amscan;
-                               HeapTuple       tup;
-                               Form_pg_amproc amprocForm;
-                               StringInfoData opfam;
-
-                               amprocDesc = heap_open(AccessMethodProcedureRelationId,
-                                                                          AccessShareLock);
-
-                               ScanKeyInit(&skey[0],
-                                                       ObjectIdAttributeNumber,
-                                                       BTEqualStrategyNumber, F_OIDEQ,
-                                                       ObjectIdGetDatum(object->objectId));
-
-                               amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
-                                                                                       SnapshotNow, 1, skey);
-
-                               tup = systable_getnext(amscan);
-
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "could not find tuple for amproc entry %u",
-                                                object->objectId);
-
-                               amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
-
-                               initStringInfo(&opfam);
-                               getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
-
-                               /*------
-                                  translator: %d is the function number, the first two %s's
-                                  are data type names, the third %s is the description of the
-                                  operator family, and the last %s is the textual form of the
-                                  function with arguments.  */
-                               appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
-                                                                amprocForm->amprocnum,
-                                                                format_type_be(amprocForm->amproclefttype),
-                                                                format_type_be(amprocForm->amprocrighttype),
-                                                                opfam.data,
-                                                                format_procedure(amprocForm->amproc));
-
-                               pfree(opfam.data);
-
-                               systable_endscan(amscan);
-                               heap_close(amprocDesc, AccessShareLock);
-                               break;
-                       }
-
-               case OCLASS_REWRITE:
-                       {
-                               Relation        ruleDesc;
-                               ScanKeyData skey[1];
-                               SysScanDesc rcscan;
-                               HeapTuple       tup;
-                               Form_pg_rewrite rule;
-
-                               ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
-
-                               ScanKeyInit(&skey[0],
-                                                       ObjectIdAttributeNumber,
-                                                       BTEqualStrategyNumber, F_OIDEQ,
-                                                       ObjectIdGetDatum(object->objectId));
-
-                               rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
-                                                                                       SnapshotNow, 1, skey);
-
-                               tup = systable_getnext(rcscan);
-
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "could not find tuple for rule %u",
-                                                object->objectId);
-
-                               rule = (Form_pg_rewrite) GETSTRUCT(tup);
-
-                               appendStringInfo(&buffer, _("rule %s on "),
-                                                                NameStr(rule->rulename));
-                               getRelationDescription(&buffer, rule->ev_class);
-
-                               systable_endscan(rcscan);
-                               heap_close(ruleDesc, AccessShareLock);
-                               break;
-                       }
-
-               case OCLASS_TRIGGER:
-                       {
-                               Relation        trigDesc;
-                               ScanKeyData skey[1];
-                               SysScanDesc tgscan;
-                               HeapTuple       tup;
-                               Form_pg_trigger trig;
-
-                               trigDesc = heap_open(TriggerRelationId, AccessShareLock);
-
-                               ScanKeyInit(&skey[0],
-                                                       ObjectIdAttributeNumber,
-                                                       BTEqualStrategyNumber, F_OIDEQ,
-                                                       ObjectIdGetDatum(object->objectId));
-
-                               tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
-                                                                                       SnapshotNow, 1, skey);
-
-                               tup = systable_getnext(tgscan);
-
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "could not find tuple for trigger %u",
-                                                object->objectId);
-
-                               trig = (Form_pg_trigger) GETSTRUCT(tup);
-
-                               appendStringInfo(&buffer, _("trigger %s on "),
-                                                                NameStr(trig->tgname));
-                               getRelationDescription(&buffer, trig->tgrelid);
-
-                               systable_endscan(tgscan);
-                               heap_close(trigDesc, AccessShareLock);
-                               break;
-                       }
-
-               case OCLASS_SCHEMA:
-                       {
-                               char       *nspname;
-
-                               nspname = get_namespace_name(object->objectId);
-                               if (!nspname)
-                                       elog(ERROR, "cache lookup failed for namespace %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("schema %s"), nspname);
-                               break;
-                       }
-
-               case OCLASS_TSPARSER:
-                       {
-                               HeapTuple       tup;
-
-                               tup = SearchSysCache1(TSPARSEROID,
-                                                                         ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "cache lookup failed for text search parser %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("text search parser %s"),
-                                        NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
-                               ReleaseSysCache(tup);
-                               break;
-                       }
-
-               case OCLASS_TSDICT:
-                       {
-                               HeapTuple       tup;
-
-                               tup = SearchSysCache1(TSDICTOID,
-                                                                         ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "cache lookup failed for text search dictionary %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("text search dictionary %s"),
-                                         NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
-                               ReleaseSysCache(tup);
-                               break;
-                       }
-
-               case OCLASS_TSTEMPLATE:
-                       {
-                               HeapTuple       tup;
-
-                               tup = SearchSysCache1(TSTEMPLATEOID,
-                                                                         ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "cache lookup failed for text search template %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("text search template %s"),
-                                 NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
-                               ReleaseSysCache(tup);
-                               break;
-                       }
-
-               case OCLASS_TSCONFIG:
-                       {
-                               HeapTuple       tup;
-
-                               tup = SearchSysCache1(TSCONFIGOID,
-                                                                         ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "cache lookup failed for text search configuration %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("text search configuration %s"),
-                                        NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
-                               ReleaseSysCache(tup);
-                               break;
-                       }
-
-               case OCLASS_ROLE:
-                       {
-                               appendStringInfo(&buffer, _("role %s"),
-                                                                GetUserNameFromId(object->objectId));
-                               break;
-                       }
-
-               case OCLASS_DATABASE:
-                       {
-                               char       *datname;
-
-                               datname = get_database_name(object->objectId);
-                               if (!datname)
-                                       elog(ERROR, "cache lookup failed for database %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("database %s"), datname);
-                               break;
-                       }
-
-               case OCLASS_TBLSPACE:
-                       {
-                               char       *tblspace;
-
-                               tblspace = get_tablespace_name(object->objectId);
-                               if (!tblspace)
-                                       elog(ERROR, "cache lookup failed for tablespace %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("tablespace %s"), tblspace);
-                               break;
-                       }
-
-               case OCLASS_FDW:
-                       {
-                               ForeignDataWrapper *fdw;
-
-                               fdw = GetForeignDataWrapper(object->objectId);
-                               appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
-                               break;
-                       }
-
-               case OCLASS_FOREIGN_SERVER:
-                       {
-                               ForeignServer *srv;
-
-                               srv = GetForeignServer(object->objectId);
-                               appendStringInfo(&buffer, _("server %s"), srv->servername);
-                               break;
-                       }
-
-               case OCLASS_USER_MAPPING:
-                       {
-                               HeapTuple       tup;
-                               Oid                     useid;
-                               char       *usename;
-
-                               tup = SearchSysCache1(USERMAPPINGOID,
-                                                                         ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "cache lookup failed for user mapping %u",
-                                                object->objectId);
-
-                               useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
-
-                               ReleaseSysCache(tup);
-
-                               if (OidIsValid(useid))
-                                       usename = GetUserNameFromId(useid);
-                               else
-                                       usename = "public";
-
-                               appendStringInfo(&buffer, _("user mapping for %s"), usename);
-                               break;
-                       }
-
-               case OCLASS_DEFACL:
-                       {
-                               Relation        defaclrel;
-                               ScanKeyData skey[1];
-                               SysScanDesc rcscan;
-                               HeapTuple       tup;
-                               Form_pg_default_acl defacl;
-
-                               defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
-
-                               ScanKeyInit(&skey[0],
-                                                       ObjectIdAttributeNumber,
-                                                       BTEqualStrategyNumber, F_OIDEQ,
-                                                       ObjectIdGetDatum(object->objectId));
-
-                               rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
-                                                                                       true, SnapshotNow, 1, skey);
-
-                               tup = systable_getnext(rcscan);
-
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "could not find tuple for default ACL %u",
-                                                object->objectId);
-
-                               defacl = (Form_pg_default_acl) GETSTRUCT(tup);
-
-                               switch (defacl->defaclobjtype)
-                               {
-                                       case DEFACLOBJ_RELATION:
-                                               appendStringInfo(&buffer,
-                                                                                _("default privileges on new relations belonging to role %s"),
-                                                                         GetUserNameFromId(defacl->defaclrole));
-                                               break;
-                                       case DEFACLOBJ_SEQUENCE:
-                                               appendStringInfo(&buffer,
-                                                                                _("default privileges on new sequences belonging to role %s"),
-                                                                         GetUserNameFromId(defacl->defaclrole));
-                                               break;
-                                       case DEFACLOBJ_FUNCTION:
-                                               appendStringInfo(&buffer,
-                                                                                _("default privileges on new functions belonging to role %s"),
-                                                                         GetUserNameFromId(defacl->defaclrole));
-                                               break;
-                                       case DEFACLOBJ_TYPE:
-                                               appendStringInfo(&buffer,
-                                                                                _("default privileges on new types belonging to role %s"),
-                                                                         GetUserNameFromId(defacl->defaclrole));
-                                               break;
-                                       default:
-                                               /* shouldn't get here */
-                                               appendStringInfo(&buffer,
-                                                               _("default privileges belonging to role %s"),
-                                                                         GetUserNameFromId(defacl->defaclrole));
-                                               break;
-                               }
-
-                               if (OidIsValid(defacl->defaclnamespace))
-                               {
-                                       appendStringInfo(&buffer,
-                                                                        _(" in schema %s"),
-                                                               get_namespace_name(defacl->defaclnamespace));
-                               }
-
-                               systable_endscan(rcscan);
-                               heap_close(defaclrel, AccessShareLock);
-                               break;
-                       }
-
-               case OCLASS_EXTENSION:
-                       {
-                               char       *extname;
-
-                               extname = get_extension_name(object->objectId);
-                               if (!extname)
-                                       elog(ERROR, "cache lookup failed for extension %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("extension %s"), extname);
-                               break;
-                       }
-
-        case OCLASS_EVENT_TRIGGER:
-                       {
-                               HeapTuple       tup;
-
-                               tup = SearchSysCache1(EVENTTRIGGEROID,
-                                                                         ObjectIdGetDatum(object->objectId));
-                               if (!HeapTupleIsValid(tup))
-                                       elog(ERROR, "cache lookup failed for event trigger %u",
-                                                object->objectId);
-                               appendStringInfo(&buffer, _("event trigger %s"),
-                                        NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
-                               ReleaseSysCache(tup);
-                               break;
-                       }
-
-               default:
-                       appendStringInfo(&buffer, "unrecognized object %u %u %d",
-                                                        object->classId,
-                                                        object->objectId,
-                                                        object->objectSubId);
-                       break;
-       }
-
-       return buffer.data;
-}
-
-/*
- * getObjectDescriptionOids: as above, except the object is specified by Oids
- */
-char *
-getObjectDescriptionOids(Oid classid, Oid objid)
-{
-       ObjectAddress address;
-
-       address.classId = classid;
-       address.objectId = objid;
-       address.objectSubId = 0;
-
-       return getObjectDescription(&address);
-}
-
-/*
- * subroutine for getObjectDescription: describe a relation
- */
-static void
-getRelationDescription(StringInfo buffer, Oid relid)
-{
-       HeapTuple       relTup;
-       Form_pg_class relForm;
-       char       *nspname;
-       char       *relname;
-
-       relTup = SearchSysCache1(RELOID,
-                                                        ObjectIdGetDatum(relid));
-       if (!HeapTupleIsValid(relTup))
-               elog(ERROR, "cache lookup failed for relation %u", relid);
-       relForm = (Form_pg_class) GETSTRUCT(relTup);
-
-       /* Qualify the name if not visible in search path */
-       if (RelationIsVisible(relid))
-               nspname = NULL;
-       else
-               nspname = get_namespace_name(relForm->relnamespace);
-
-       relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
-
-       switch (relForm->relkind)
-       {
-               case RELKIND_RELATION:
-                       appendStringInfo(buffer, _("table %s"),
-                                                        relname);
-                       break;
-               case RELKIND_INDEX:
-                       appendStringInfo(buffer, _("index %s"),
-                                                        relname);
-                       break;
-               case RELKIND_SEQUENCE:
-                       appendStringInfo(buffer, _("sequence %s"),
-                                                        relname);
-                       break;
-               case RELKIND_TOASTVALUE:
-                       appendStringInfo(buffer, _("toast table %s"),
-                                                        relname);
-                       break;
-               case RELKIND_VIEW:
-                       appendStringInfo(buffer, _("view %s"),
-                                                        relname);
-                       break;
-               case RELKIND_MATVIEW:
-                       appendStringInfo(buffer, _("materialized view %s"),
-                                                        relname);
-                       break;
-               case RELKIND_COMPOSITE_TYPE:
-                       appendStringInfo(buffer, _("composite type %s"),
-                                                        relname);
-                       break;
-               case RELKIND_FOREIGN_TABLE:
-                       appendStringInfo(buffer, _("foreign table %s"),
-                                                        relname);
-                       break;
-               default:
-                       /* shouldn't get here */
-                       appendStringInfo(buffer, _("relation %s"),
-                                                        relname);
-                       break;
-       }
-
-       ReleaseSysCache(relTup);
-}
-
-/*
- * subroutine for getObjectDescription: describe an operator family
- */
-static void
-getOpFamilyDescription(StringInfo buffer, Oid opfid)
-{
-       HeapTuple       opfTup;
-       Form_pg_opfamily opfForm;
-       HeapTuple       amTup;
-       Form_pg_am      amForm;
-       char       *nspname;
-
-       opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
-       if (!HeapTupleIsValid(opfTup))
-               elog(ERROR, "cache lookup failed for opfamily %u", opfid);
-       opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
-
-       amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
-       if (!HeapTupleIsValid(amTup))
-               elog(ERROR, "cache lookup failed for access method %u",
-                        opfForm->opfmethod);
-       amForm = (Form_pg_am) GETSTRUCT(amTup);
-
-       /* Qualify the name if not visible in search path */
-       if (OpfamilyIsVisible(opfid))
-               nspname = NULL;
-       else
-               nspname = get_namespace_name(opfForm->opfnamespace);
-
-       appendStringInfo(buffer, _("operator family %s for access method %s"),
-                                        quote_qualified_identifier(nspname,
-                                                                                               NameStr(opfForm->opfname)),
-                                        NameStr(amForm->amname));
-
-       ReleaseSysCache(amTup);
-       ReleaseSysCache(opfTup);
-}
-
-/*
- * SQL-level callable version of getObjectDescription
- */
-Datum
-pg_describe_object(PG_FUNCTION_ARGS)
-{
-       Oid                     classid = PG_GETARG_OID(0);
-       Oid                     objid = PG_GETARG_OID(1);
-       int32           subobjid = PG_GETARG_INT32(2);
-       char       *description = NULL;
-       ObjectAddress address;
-
-       /* for "pinned" items in pg_depend, return null */
-       if (!OidIsValid(classid) && !OidIsValid(objid))
-               PG_RETURN_NULL();
-
-       address.classId = classid;
-       address.objectId = objid;
-       address.objectSubId = subobjid;
-
-       description = getObjectDescription(&address);
-       PG_RETURN_TEXT_P(cstring_to_text(description));
-}
index 6f60d7cad1ae14f7e098a5d9c475072e1747539f..48ef6bf0a490530f1bcbe5670129f5bce4d6aa89 100644 (file)
 #include "catalog/catalog.h"
 #include "catalog/indexing.h"
 #include "catalog/objectaddress.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
+#include "catalog/pg_attrdef.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_cast.h"
+#include "catalog/pg_default_acl.h"
 #include "catalog/pg_event_trigger.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
@@ -46,6 +50,7 @@
 #include "catalog/pg_ts_parser.h"
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
 #include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/event_trigger.h"
@@ -54,6 +59,7 @@
 #include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "foreign/foreign.h"
+#include "funcapi.h"
 #include "libpq/be-fsstubs.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
@@ -88,6 +94,10 @@ typedef struct
        AttrNumber      attnum_owner;   /* attnum of owner field */
        AttrNumber      attnum_acl;             /* attnum of acl field */
        AclObjectKind acl_kind;         /* ACL_KIND_* of this object type */
+       bool            is_nsp_name_unique;     /* can the nsp/name combination (or name
+                                                                        * alone, if there's no namespace) be
+                                                                        * considered an unique identifier for an
+                                                                        * object of this class? */
 } ObjectPropertyType;
 
 static ObjectPropertyType ObjectProperty[] =
@@ -101,7 +111,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                InvalidAttrNumber,
                InvalidAttrNumber,
-               -1
+               -1,
+               false
        },
        {
                CollationRelationId,
@@ -112,7 +123,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_collation_collnamespace,
                Anum_pg_collation_collowner,
                InvalidAttrNumber,
-               ACL_KIND_COLLATION
+               ACL_KIND_COLLATION,
+               true
        },
        {
                ConstraintRelationId,
@@ -123,7 +135,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_constraint_connamespace,
                InvalidAttrNumber,
                InvalidAttrNumber,
-               -1
+               -1,
+               false
        },
        {
                ConversionRelationId,
@@ -134,7 +147,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_conversion_connamespace,
                Anum_pg_conversion_conowner,
                InvalidAttrNumber,
-               ACL_KIND_CONVERSION
+               ACL_KIND_CONVERSION,
+               true
        },
        {
                DatabaseRelationId,
@@ -145,7 +159,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                Anum_pg_database_datdba,
                Anum_pg_database_datacl,
-               ACL_KIND_DATABASE
+               ACL_KIND_DATABASE,
+               true
        },
        {
                ExtensionRelationId,
@@ -156,7 +171,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,              /* extension doesn't belong to extnamespace */
                Anum_pg_extension_extowner,
                InvalidAttrNumber,
-               ACL_KIND_EXTENSION
+               ACL_KIND_EXTENSION,
+               true
        },
        {
                ForeignDataWrapperRelationId,
@@ -167,7 +183,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                Anum_pg_foreign_data_wrapper_fdwowner,
                Anum_pg_foreign_data_wrapper_fdwacl,
-               ACL_KIND_FDW
+               ACL_KIND_FDW,
+               true
        },
        {
                ForeignServerRelationId,
@@ -178,7 +195,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                Anum_pg_foreign_server_srvowner,
                Anum_pg_foreign_server_srvacl,
-               ACL_KIND_FOREIGN_SERVER
+               ACL_KIND_FOREIGN_SERVER,
+               true
        },
        {
                ProcedureRelationId,
@@ -189,7 +207,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_proc_pronamespace,
                Anum_pg_proc_proowner,
                Anum_pg_proc_proacl,
-               ACL_KIND_PROC
+               ACL_KIND_PROC,
+               false
        },
        {
                LanguageRelationId,
@@ -200,7 +219,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                Anum_pg_language_lanowner,
                Anum_pg_language_lanacl,
-               ACL_KIND_LANGUAGE
+               ACL_KIND_LANGUAGE,
+               true
        },
        {
                LargeObjectMetadataRelationId,
@@ -211,7 +231,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                Anum_pg_largeobject_metadata_lomowner,
                Anum_pg_largeobject_metadata_lomacl,
-               ACL_KIND_LARGEOBJECT
+               ACL_KIND_LARGEOBJECT,
+               false
        },
        {
                OperatorClassRelationId,
@@ -222,7 +243,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_opclass_opcnamespace,
                Anum_pg_opclass_opcowner,
                InvalidAttrNumber,
-               ACL_KIND_OPCLASS
+               ACL_KIND_OPCLASS,
+               true
        },
        {
                OperatorRelationId,
@@ -233,7 +255,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_operator_oprnamespace,
                Anum_pg_operator_oprowner,
                InvalidAttrNumber,
-               ACL_KIND_OPER
+               ACL_KIND_OPER,
+               false
        },
        {
                OperatorFamilyRelationId,
@@ -244,7 +267,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_opfamily_opfnamespace,
                Anum_pg_opfamily_opfowner,
                InvalidAttrNumber,
-               ACL_KIND_OPFAMILY
+               ACL_KIND_OPFAMILY,
+               true
        },
        {
                AuthIdRelationId,
@@ -255,7 +279,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                InvalidAttrNumber,
                InvalidAttrNumber,
-               -1
+               -1,
+               true
        },
        {
                RewriteRelationId,
@@ -266,7 +291,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                InvalidAttrNumber,
                InvalidAttrNumber,
-               -1
+               -1,
+               false
        },
        {
                NamespaceRelationId,
@@ -277,7 +303,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                Anum_pg_namespace_nspowner,
                Anum_pg_namespace_nspacl,
-               ACL_KIND_NAMESPACE
+               ACL_KIND_NAMESPACE,
+               true
        },
        {
                RelationRelationId,
@@ -288,7 +315,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_class_relnamespace,
                Anum_pg_class_relowner,
                Anum_pg_class_relacl,
-               ACL_KIND_CLASS
+               ACL_KIND_CLASS,
+               true
        },
        {
                TableSpaceRelationId,
@@ -299,7 +327,8 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                Anum_pg_tablespace_spcowner,
                Anum_pg_tablespace_spcacl,
-               ACL_KIND_TABLESPACE
+               ACL_KIND_TABLESPACE,
+               true
        },
        {
                TriggerRelationId,
@@ -311,6 +340,7 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                InvalidAttrNumber,
                -1,
+               false
        },
        {
                EventTriggerRelationId,
@@ -322,6 +352,7 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_event_trigger_evtowner,
                InvalidAttrNumber,
                ACL_KIND_EVENT_TRIGGER,
+               true
        },
        {
                TSConfigRelationId,
@@ -332,7 +363,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_ts_config_cfgnamespace,
                Anum_pg_ts_config_cfgowner,
                InvalidAttrNumber,
-               ACL_KIND_TSCONFIGURATION
+               ACL_KIND_TSCONFIGURATION,
+               true
        },
        {
                TSDictionaryRelationId,
@@ -343,7 +375,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_ts_dict_dictnamespace,
                Anum_pg_ts_dict_dictowner,
                InvalidAttrNumber,
-               ACL_KIND_TSDICTIONARY
+               ACL_KIND_TSDICTIONARY,
+               true
        },
        {
                TSParserRelationId,
@@ -355,6 +388,7 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                InvalidAttrNumber,
                -1,
+               true
        },
        {
                TSTemplateRelationId,
@@ -366,6 +400,7 @@ static ObjectPropertyType ObjectProperty[] =
                InvalidAttrNumber,
                InvalidAttrNumber,
                -1,
+               true,
        },
        {
                TypeRelationId,
@@ -376,7 +411,8 @@ static ObjectPropertyType ObjectProperty[] =
                Anum_pg_type_typnamespace,
                Anum_pg_type_typowner,
                Anum_pg_type_typacl,
-               ACL_KIND_TYPE
+               ACL_KIND_TYPE,
+               true
        }
 };
 
@@ -396,6 +432,15 @@ static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
                                                List *objargs, bool missing_ok);
 static ObjectPropertyType *get_object_property_data(Oid class_id);
 
+static void getRelationDescription(StringInfo buffer, Oid relid);
+static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
+static void getRelationTypeDescription(StringInfo buffer, Oid relid,
+                                                  int32 objectSubId);
+static void getProcedureTypeDescription(StringInfo buffer, Oid procid);
+static void getConstraintTypeDescription(StringInfo buffer, Oid constroid);
+static void getOpFamilyIdentity(StringInfo buffer, Oid opfid);
+static void getRelationIdentity(StringInfo buffer, Oid relid);
+
 /*
  * Translate an object name and arguments (as passed by the parser) to an
  * ObjectAddress.
@@ -1344,6 +1389,32 @@ get_object_aclkind(Oid class_id)
        return prop->acl_kind;
 }
 
+bool
+get_object_namensp_unique(Oid class_id)
+{
+       ObjectPropertyType *prop = get_object_property_data(class_id);
+
+       return prop->is_nsp_name_unique;
+}
+
+/*
+ * Return whether we have useful data for the given object class in the
+ * ObjectProperty table.
+ */
+bool
+is_objectclass_supported(Oid class_id)
+{
+       int                     index;
+
+       for (index = 0; index < lengthof(ObjectProperty); index++)
+       {
+               if (ObjectProperty[index].class_oid == class_id)
+                       return true;
+       }
+
+       return false;
+}
+
 /*
  * Find ObjectProperty structure by class_id.
  */
@@ -1374,3 +1445,1919 @@ get_object_property_data(Oid class_id)
 
        return NULL; /* keep MSC compiler happy */
 }
+
+/*
+ * Return a copy of the tuple for the object with the given object OID, from
+ * the given catalog (which must have been opened by the caller and suitably
+ * locked).  NULL is returned if the OID is not found.
+ *
+ * We try a syscache first, if available.
+ */
+HeapTuple
+get_catalog_object_by_oid(Relation catalog, Oid objectId)
+{
+       HeapTuple       tuple;
+       Oid                     classId = RelationGetRelid(catalog);
+       int                     oidCacheId = get_object_catcache_oid(classId);
+
+       if (oidCacheId > 0)
+       {
+               tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
+               if (!HeapTupleIsValid(tuple))  /* should not happen */
+                       return NULL;
+       }
+       else
+       {
+               Oid                     oidIndexId = get_object_oid_index(classId);
+               SysScanDesc     scan;
+               ScanKeyData     skey;
+
+               Assert(OidIsValid(oidIndexId));
+
+               ScanKeyInit(&skey,
+                                       ObjectIdAttributeNumber,
+                                       BTEqualStrategyNumber, F_OIDEQ,
+                                       ObjectIdGetDatum(objectId));
+
+               scan = systable_beginscan(catalog, oidIndexId, true,
+                                                                 SnapshotNow, 1, &skey);
+               tuple = systable_getnext(scan);
+               if (!HeapTupleIsValid(tuple))
+               {
+                       systable_endscan(scan);
+                       return NULL;
+               }
+               tuple = heap_copytuple(tuple);
+
+               systable_endscan(scan);
+       }
+
+       return tuple;
+}
+
+/*
+ * getObjectDescription: build an object description for messages
+ *
+ * The result is a palloc'd string.
+ */
+char *
+getObjectDescription(const ObjectAddress *object)
+{
+       StringInfoData buffer;
+
+       initStringInfo(&buffer);
+
+       switch (getObjectClass(object))
+       {
+               case OCLASS_CLASS:
+                       getRelationDescription(&buffer, object->objectId);
+                       if (object->objectSubId != 0)
+                               appendStringInfo(&buffer, _(" column %s"),
+                                                                get_relid_attribute_name(object->objectId,
+                                                                                                          object->objectSubId));
+                       break;
+
+               case OCLASS_PROC:
+                       appendStringInfo(&buffer, _("function %s"),
+                                                        format_procedure(object->objectId));
+                       break;
+
+               case OCLASS_TYPE:
+                       appendStringInfo(&buffer, _("type %s"),
+                                                        format_type_be(object->objectId));
+                       break;
+
+               case OCLASS_CAST:
+                       {
+                               Relation        castDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc rcscan;
+                               HeapTuple       tup;
+                               Form_pg_cast castForm;
+
+                               castDesc = heap_open(CastRelationId, AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(rcscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for cast %u",
+                                                object->objectId);
+
+                               castForm = (Form_pg_cast) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer, _("cast from %s to %s"),
+                                                                format_type_be(castForm->castsource),
+                                                                format_type_be(castForm->casttarget));
+
+                               systable_endscan(rcscan);
+                               heap_close(castDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_COLLATION:
+                       {
+                               HeapTuple       collTup;
+                               Form_pg_collation coll;
+
+                               collTup = SearchSysCache1(COLLOID,
+                                                                                 ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(collTup))
+                                       elog(ERROR, "cache lookup failed for collation %u",
+                                                object->objectId);
+                               coll = (Form_pg_collation) GETSTRUCT(collTup);
+                               appendStringInfo(&buffer, _("collation %s"),
+                                                                NameStr(coll->collname));
+                               ReleaseSysCache(collTup);
+                               break;
+                       }
+
+               case OCLASS_CONSTRAINT:
+                       {
+                               HeapTuple       conTup;
+                               Form_pg_constraint con;
+
+                               conTup = SearchSysCache1(CONSTROID,
+                                                                                ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(conTup))
+                                       elog(ERROR, "cache lookup failed for constraint %u",
+                                                object->objectId);
+                               con = (Form_pg_constraint) GETSTRUCT(conTup);
+
+                               if (OidIsValid(con->conrelid))
+                               {
+                                       StringInfoData rel;
+
+                                       initStringInfo(&rel);
+                                       getRelationDescription(&rel, con->conrelid);
+                                       appendStringInfo(&buffer, _("constraint %s on %s"),
+                                                                        NameStr(con->conname), rel.data);
+                                       pfree(rel.data);
+                               }
+                               else
+                               {
+                                       appendStringInfo(&buffer, _("constraint %s"),
+                                                                        NameStr(con->conname));
+                               }
+
+                               ReleaseSysCache(conTup);
+                               break;
+                       }
+
+               case OCLASS_CONVERSION:
+                       {
+                               HeapTuple       conTup;
+
+                               conTup = SearchSysCache1(CONVOID,
+                                                                                ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(conTup))
+                                       elog(ERROR, "cache lookup failed for conversion %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("conversion %s"),
+                                NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
+                               ReleaseSysCache(conTup);
+                               break;
+                       }
+
+               case OCLASS_DEFAULT:
+                       {
+                               Relation        attrdefDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc adscan;
+                               HeapTuple       tup;
+                               Form_pg_attrdef attrdef;
+                               ObjectAddress colobject;
+
+                               attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
+                                                                                       true, SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(adscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for attrdef %u",
+                                                object->objectId);
+
+                               attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
+
+                               colobject.classId = RelationRelationId;
+                               colobject.objectId = attrdef->adrelid;
+                               colobject.objectSubId = attrdef->adnum;
+
+                               appendStringInfo(&buffer, _("default for %s"),
+                                                                getObjectDescription(&colobject));
+
+                               systable_endscan(adscan);
+                               heap_close(attrdefDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_LANGUAGE:
+                       {
+                               HeapTuple       langTup;
+
+                               langTup = SearchSysCache1(LANGOID,
+                                                                                 ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(langTup))
+                                       elog(ERROR, "cache lookup failed for language %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("language %s"),
+                                 NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
+                               ReleaseSysCache(langTup);
+                               break;
+                       }
+               case OCLASS_LARGEOBJECT:
+                       appendStringInfo(&buffer, _("large object %u"),
+                                                        object->objectId);
+                       break;
+
+               case OCLASS_OPERATOR:
+                       appendStringInfo(&buffer, _("operator %s"),
+                                                        format_operator(object->objectId));
+                       break;
+
+               case OCLASS_OPCLASS:
+                       {
+                               HeapTuple       opcTup;
+                               Form_pg_opclass opcForm;
+                               HeapTuple       amTup;
+                               Form_pg_am      amForm;
+                               char       *nspname;
+
+                               opcTup = SearchSysCache1(CLAOID,
+                                                                                ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(opcTup))
+                                       elog(ERROR, "cache lookup failed for opclass %u",
+                                                object->objectId);
+                               opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
+
+                               amTup = SearchSysCache1(AMOID,
+                                                                               ObjectIdGetDatum(opcForm->opcmethod));
+                               if (!HeapTupleIsValid(amTup))
+                                       elog(ERROR, "cache lookup failed for access method %u",
+                                                opcForm->opcmethod);
+                               amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+                               /* Qualify the name if not visible in search path */
+                               if (OpclassIsVisible(object->objectId))
+                                       nspname = NULL;
+                               else
+                                       nspname = get_namespace_name(opcForm->opcnamespace);
+
+                               appendStringInfo(&buffer, _("operator class %s for access method %s"),
+                                                                quote_qualified_identifier(nspname,
+                                                                                                 NameStr(opcForm->opcname)),
+                                                                NameStr(amForm->amname));
+
+                               ReleaseSysCache(amTup);
+                               ReleaseSysCache(opcTup);
+                               break;
+                       }
+
+               case OCLASS_OPFAMILY:
+                       getOpFamilyDescription(&buffer, object->objectId);
+                       break;
+
+               case OCLASS_AMOP:
+                       {
+                               Relation        amopDesc;
+                               HeapTuple       tup;
+                               ScanKeyData skey[1];
+                               SysScanDesc amscan;
+                               Form_pg_amop amopForm;
+                               StringInfoData opfam;
+
+                               amopDesc = heap_open(AccessMethodOperatorRelationId,
+                                                                        AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(amscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for amop entry %u",
+                                                object->objectId);
+
+                               amopForm = (Form_pg_amop) GETSTRUCT(tup);
+
+                               initStringInfo(&opfam);
+                               getOpFamilyDescription(&opfam, amopForm->amopfamily);
+
+                               /*------
+                                  translator: %d is the operator strategy (a number), the
+                                  first two %s's are data type names, the third %s is the
+                                  description of the operator family, and the last %s is the
+                                  textual form of the operator with arguments.  */
+                               appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
+                                                                amopForm->amopstrategy,
+                                                                format_type_be(amopForm->amoplefttype),
+                                                                format_type_be(amopForm->amoprighttype),
+                                                                opfam.data,
+                                                                format_operator(amopForm->amopopr));
+
+                               pfree(opfam.data);
+
+                               systable_endscan(amscan);
+                               heap_close(amopDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_AMPROC:
+                       {
+                               Relation        amprocDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc amscan;
+                               HeapTuple       tup;
+                               Form_pg_amproc amprocForm;
+                               StringInfoData opfam;
+
+                               amprocDesc = heap_open(AccessMethodProcedureRelationId,
+                                                                          AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(amscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for amproc entry %u",
+                                                object->objectId);
+
+                               amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
+
+                               initStringInfo(&opfam);
+                               getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
+
+                               /*------
+                                  translator: %d is the function number, the first two %s's
+                                  are data type names, the third %s is the description of the
+                                  operator family, and the last %s is the textual form of the
+                                  function with arguments.  */
+                               appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
+                                                                amprocForm->amprocnum,
+                                                                format_type_be(amprocForm->amproclefttype),
+                                                                format_type_be(amprocForm->amprocrighttype),
+                                                                opfam.data,
+                                                                format_procedure(amprocForm->amproc));
+
+                               pfree(opfam.data);
+
+                               systable_endscan(amscan);
+                               heap_close(amprocDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_REWRITE:
+                       {
+                               Relation        ruleDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc rcscan;
+                               HeapTuple       tup;
+                               Form_pg_rewrite rule;
+
+                               ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(rcscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for rule %u",
+                                                object->objectId);
+
+                               rule = (Form_pg_rewrite) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer, _("rule %s on "),
+                                                                NameStr(rule->rulename));
+                               getRelationDescription(&buffer, rule->ev_class);
+
+                               systable_endscan(rcscan);
+                               heap_close(ruleDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_TRIGGER:
+                       {
+                               Relation        trigDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc tgscan;
+                               HeapTuple       tup;
+                               Form_pg_trigger trig;
+
+                               trigDesc = heap_open(TriggerRelationId, AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(tgscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for trigger %u",
+                                                object->objectId);
+
+                               trig = (Form_pg_trigger) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer, _("trigger %s on "),
+                                                                NameStr(trig->tgname));
+                               getRelationDescription(&buffer, trig->tgrelid);
+
+                               systable_endscan(tgscan);
+                               heap_close(trigDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_SCHEMA:
+                       {
+                               char       *nspname;
+
+                               nspname = get_namespace_name(object->objectId);
+                               if (!nspname)
+                                       elog(ERROR, "cache lookup failed for namespace %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("schema %s"), nspname);
+                               break;
+                       }
+
+               case OCLASS_TSPARSER:
+                       {
+                               HeapTuple       tup;
+
+                               tup = SearchSysCache1(TSPARSEROID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for text search parser %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("text search parser %s"),
+                                        NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               case OCLASS_TSDICT:
+                       {
+                               HeapTuple       tup;
+
+                               tup = SearchSysCache1(TSDICTOID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for text search dictionary %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("text search dictionary %s"),
+                                         NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               case OCLASS_TSTEMPLATE:
+                       {
+                               HeapTuple       tup;
+
+                               tup = SearchSysCache1(TSTEMPLATEOID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for text search template %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("text search template %s"),
+                                 NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               case OCLASS_TSCONFIG:
+                       {
+                               HeapTuple       tup;
+
+                               tup = SearchSysCache1(TSCONFIGOID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for text search configuration %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("text search configuration %s"),
+                                        NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               case OCLASS_ROLE:
+                       {
+                               appendStringInfo(&buffer, _("role %s"),
+                                                                GetUserNameFromId(object->objectId));
+                               break;
+                       }
+
+               case OCLASS_DATABASE:
+                       {
+                               char       *datname;
+
+                               datname = get_database_name(object->objectId);
+                               if (!datname)
+                                       elog(ERROR, "cache lookup failed for database %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("database %s"), datname);
+                               break;
+                       }
+
+               case OCLASS_TBLSPACE:
+                       {
+                               char       *tblspace;
+
+                               tblspace = get_tablespace_name(object->objectId);
+                               if (!tblspace)
+                                       elog(ERROR, "cache lookup failed for tablespace %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("tablespace %s"), tblspace);
+                               break;
+                       }
+
+               case OCLASS_FDW:
+                       {
+                               ForeignDataWrapper *fdw;
+
+                               fdw = GetForeignDataWrapper(object->objectId);
+                               appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
+                               break;
+                       }
+
+               case OCLASS_FOREIGN_SERVER:
+                       {
+                               ForeignServer *srv;
+
+                               srv = GetForeignServer(object->objectId);
+                               appendStringInfo(&buffer, _("server %s"), srv->servername);
+                               break;
+                       }
+
+               case OCLASS_USER_MAPPING:
+                       {
+                               HeapTuple       tup;
+                               Oid                     useid;
+                               char       *usename;
+
+                               tup = SearchSysCache1(USERMAPPINGOID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for user mapping %u",
+                                                object->objectId);
+
+                               useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
+
+                               ReleaseSysCache(tup);
+
+                               if (OidIsValid(useid))
+                                       usename = GetUserNameFromId(useid);
+                               else
+                                       usename = "public";
+
+                               appendStringInfo(&buffer, _("user mapping for %s"), usename);
+                               break;
+                       }
+
+               case OCLASS_DEFACL:
+                       {
+                               Relation        defaclrel;
+                               ScanKeyData skey[1];
+                               SysScanDesc rcscan;
+                               HeapTuple       tup;
+                               Form_pg_default_acl defacl;
+
+                               defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
+                                                                                       true, SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(rcscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for default ACL %u",
+                                                object->objectId);
+
+                               defacl = (Form_pg_default_acl) GETSTRUCT(tup);
+
+                               switch (defacl->defaclobjtype)
+                               {
+                                       case DEFACLOBJ_RELATION:
+                                               appendStringInfo(&buffer,
+                                                                                _("default privileges on new relations belonging to role %s"),
+                                                                         GetUserNameFromId(defacl->defaclrole));
+                                               break;
+                                       case DEFACLOBJ_SEQUENCE:
+                                               appendStringInfo(&buffer,
+                                                                                _("default privileges on new sequences belonging to role %s"),
+                                                                         GetUserNameFromId(defacl->defaclrole));
+                                               break;
+                                       case DEFACLOBJ_FUNCTION:
+                                               appendStringInfo(&buffer,
+                                                                                _("default privileges on new functions belonging to role %s"),
+                                                                         GetUserNameFromId(defacl->defaclrole));
+                                               break;
+                                       case DEFACLOBJ_TYPE:
+                                               appendStringInfo(&buffer,
+                                                                                _("default privileges on new types belonging to role %s"),
+                                                                         GetUserNameFromId(defacl->defaclrole));
+                                               break;
+                                       default:
+                                               /* shouldn't get here */
+                                               appendStringInfo(&buffer,
+                                                               _("default privileges belonging to role %s"),
+                                                                         GetUserNameFromId(defacl->defaclrole));
+                                               break;
+                               }
+
+                               if (OidIsValid(defacl->defaclnamespace))
+                               {
+                                       appendStringInfo(&buffer,
+                                                                        _(" in schema %s"),
+                                                               get_namespace_name(defacl->defaclnamespace));
+                               }
+
+                               systable_endscan(rcscan);
+                               heap_close(defaclrel, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_EXTENSION:
+                       {
+                               char       *extname;
+
+                               extname = get_extension_name(object->objectId);
+                               if (!extname)
+                                       elog(ERROR, "cache lookup failed for extension %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("extension %s"), extname);
+                               break;
+                       }
+
+        case OCLASS_EVENT_TRIGGER:
+                       {
+                               HeapTuple       tup;
+
+                               tup = SearchSysCache1(EVENTTRIGGEROID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for event trigger %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, _("event trigger %s"),
+                                        NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               default:
+                       appendStringInfo(&buffer, "unrecognized object %u %u %d",
+                                                        object->classId,
+                                                        object->objectId,
+                                                        object->objectSubId);
+                       break;
+       }
+
+       return buffer.data;
+}
+
+/*
+ * getObjectDescriptionOids: as above, except the object is specified by Oids
+ */
+char *
+getObjectDescriptionOids(Oid classid, Oid objid)
+{
+       ObjectAddress address;
+
+       address.classId = classid;
+       address.objectId = objid;
+       address.objectSubId = 0;
+
+       return getObjectDescription(&address);
+}
+
+/*
+ * subroutine for getObjectDescription: describe a relation
+ */
+static void
+getRelationDescription(StringInfo buffer, Oid relid)
+{
+       HeapTuple       relTup;
+       Form_pg_class relForm;
+       char       *nspname;
+       char       *relname;
+
+       relTup = SearchSysCache1(RELOID,
+                                                        ObjectIdGetDatum(relid));
+       if (!HeapTupleIsValid(relTup))
+               elog(ERROR, "cache lookup failed for relation %u", relid);
+       relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+       /* Qualify the name if not visible in search path */
+       if (RelationIsVisible(relid))
+               nspname = NULL;
+       else
+               nspname = get_namespace_name(relForm->relnamespace);
+
+       relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
+
+       switch (relForm->relkind)
+       {
+               case RELKIND_RELATION:
+                       appendStringInfo(buffer, _("table %s"),
+                                                        relname);
+                       break;
+               case RELKIND_INDEX:
+                       appendStringInfo(buffer, _("index %s"),
+                                                        relname);
+                       break;
+               case RELKIND_SEQUENCE:
+                       appendStringInfo(buffer, _("sequence %s"),
+                                                        relname);
+                       break;
+               case RELKIND_TOASTVALUE:
+                       appendStringInfo(buffer, _("toast table %s"),
+                                                        relname);
+                       break;
+               case RELKIND_VIEW:
+                       appendStringInfo(buffer, _("view %s"),
+                                                        relname);
+                       break;
+               case RELKIND_MATVIEW:
+                       appendStringInfo(buffer, _("materialized view %s"),
+                                                        relname);
+                       break;
+               case RELKIND_COMPOSITE_TYPE:
+                       appendStringInfo(buffer, _("composite type %s"),
+                                                        relname);
+                       break;
+               case RELKIND_FOREIGN_TABLE:
+                       appendStringInfo(buffer, _("foreign table %s"),
+                                                        relname);
+                       break;
+               default:
+                       /* shouldn't get here */
+                       appendStringInfo(buffer, _("relation %s"),
+                                                        relname);
+                       break;
+       }
+
+       ReleaseSysCache(relTup);
+}
+
+/*
+ * subroutine for getObjectDescription: describe an operator family
+ */
+static void
+getOpFamilyDescription(StringInfo buffer, Oid opfid)
+{
+       HeapTuple       opfTup;
+       Form_pg_opfamily opfForm;
+       HeapTuple       amTup;
+       Form_pg_am      amForm;
+       char       *nspname;
+
+       opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
+       if (!HeapTupleIsValid(opfTup))
+               elog(ERROR, "cache lookup failed for opfamily %u", opfid);
+       opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
+
+       amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
+       if (!HeapTupleIsValid(amTup))
+               elog(ERROR, "cache lookup failed for access method %u",
+                        opfForm->opfmethod);
+       amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+       /* Qualify the name if not visible in search path */
+       if (OpfamilyIsVisible(opfid))
+               nspname = NULL;
+       else
+               nspname = get_namespace_name(opfForm->opfnamespace);
+
+       appendStringInfo(buffer, _("operator family %s for access method %s"),
+                                        quote_qualified_identifier(nspname,
+                                                                                               NameStr(opfForm->opfname)),
+                                        NameStr(amForm->amname));
+
+       ReleaseSysCache(amTup);
+       ReleaseSysCache(opfTup);
+}
+
+/*
+ * SQL-level callable version of getObjectDescription
+ */
+Datum
+pg_describe_object(PG_FUNCTION_ARGS)
+{
+       Oid                     classid = PG_GETARG_OID(0);
+       Oid                     objid = PG_GETARG_OID(1);
+       int32           subobjid = PG_GETARG_INT32(2);
+       char       *description;
+       ObjectAddress address;
+
+       /* for "pinned" items in pg_depend, return null */
+       if (!OidIsValid(classid) && !OidIsValid(objid))
+               PG_RETURN_NULL();
+
+       address.classId = classid;
+       address.objectId = objid;
+       address.objectSubId = subobjid;
+
+       description = getObjectDescription(&address);
+       PG_RETURN_TEXT_P(cstring_to_text(description));
+}
+
+/*
+ * SQL-level callable function to obtain object type + identity
+ */
+Datum
+pg_identify_object(PG_FUNCTION_ARGS)
+{
+       Oid                     classid = PG_GETARG_OID(0);
+       Oid                     objid = PG_GETARG_OID(1);
+       int32           subobjid = PG_GETARG_INT32(2);
+       Oid                     schema_oid = InvalidOid;
+       const char *objname = NULL;
+       ObjectAddress address;
+       Datum           values[4];
+       bool            nulls[4];
+       TupleDesc       tupdesc;
+       HeapTuple       htup;
+
+       address.classId = classid;
+       address.objectId = objid;
+       address.objectSubId = subobjid;
+
+       /*
+        * Construct a tuple descriptor for the result row.  This must match this
+        * function's pg_proc entry!
+        */
+       tupdesc = CreateTemplateTupleDesc(4, false);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
+                                          TEXTOID, -1, 0);
+
+       tupdesc = BlessTupleDesc(tupdesc);
+
+       if (is_objectclass_supported(address.classId))
+       {
+               HeapTuple       objtup;
+               Relation        catalog = heap_open(address.classId, AccessShareLock);
+
+               objtup = get_catalog_object_by_oid(catalog, address.objectId);
+               if (objtup != NULL)
+               {
+                       bool            isnull;
+                       AttrNumber      nspAttnum;
+                       AttrNumber      nameAttnum;
+
+                       nspAttnum = get_object_attnum_namespace(address.classId);
+                       if (nspAttnum != InvalidAttrNumber)
+                       {
+                               schema_oid = heap_getattr(objtup, nspAttnum,
+                                                                                 RelationGetDescr(catalog), &isnull);
+                               if (isnull)
+                                       elog(ERROR, "invalid null namespace in object %u/%u/%d",
+                                                address.classId, address.objectId, address.objectSubId);
+                       }
+
+                       /*
+                        * We only return the object name if it can be used (together
+                        * with the schema name, if any) as an unique identifier.
+                        */
+                       if (get_object_namensp_unique(address.classId))
+                       {
+                               nameAttnum = get_object_attnum_name(address.classId);
+                               if (nameAttnum != InvalidAttrNumber)
+                               {
+                                       Datum   nameDatum;
+
+                                       nameDatum = heap_getattr(objtup, nameAttnum,
+                                                                                        RelationGetDescr(catalog), &isnull);
+                                       if (isnull)
+                                               elog(ERROR, "invalid null name in object %u/%u/%d",
+                                                        address.classId, address.objectId, address.objectSubId);
+                                       objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
+                               }
+                       }
+               }
+
+               heap_close(catalog, AccessShareLock);
+       }
+
+       /* object type */
+       values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
+       nulls[0] = false;
+
+       /* schema name */
+       if (OidIsValid(schema_oid))
+       {
+               const char      *schema = quote_identifier(get_namespace_name(schema_oid));
+
+               values[1] = CStringGetTextDatum(schema);
+               nulls[1] = false;
+       }
+       else
+               nulls[1] = true;
+
+       /* object name */
+       if (objname)
+       {
+               values[2] = CStringGetTextDatum(objname);
+               nulls[2] = false;
+       }
+       else
+               nulls[2] = true;
+
+       /* object identity */
+       values[3] = CStringGetTextDatum(getObjectIdentity(&address));
+       nulls[3] = false;
+
+       htup = heap_form_tuple(tupdesc, values, nulls);
+
+       PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+}
+
+/*
+ * Return a palloc'ed string that describes the type of object that the
+ * passed address is for.
+ */
+char *
+getObjectTypeDescription(const ObjectAddress *object)
+{
+       StringInfoData buffer;
+
+       initStringInfo(&buffer);
+
+       switch (getObjectClass(object))
+       {
+               case OCLASS_CLASS:
+                       getRelationTypeDescription(&buffer, object->objectId,
+                                                                          object->objectSubId);
+                       break;
+
+               case OCLASS_PROC:
+                       getProcedureTypeDescription(&buffer, object->objectId);
+                       break;
+
+               case OCLASS_TYPE:
+                       appendStringInfo(&buffer, "type");
+                       break;
+
+               case OCLASS_CAST:
+                       appendStringInfo(&buffer, "cast");
+                       break;
+
+               case OCLASS_COLLATION:
+                       appendStringInfo(&buffer, "collation");
+                       break;
+
+               case OCLASS_CONSTRAINT:
+                       getConstraintTypeDescription(&buffer, object->objectId);
+                       break;
+
+               case OCLASS_CONVERSION:
+                       appendStringInfo(&buffer, "conversion");
+                       break;
+
+               case OCLASS_DEFAULT:
+                       appendStringInfo(&buffer, "default value");
+                       break;
+
+               case OCLASS_LANGUAGE:
+                       appendStringInfo(&buffer, "language");
+                       break;
+
+               case OCLASS_LARGEOBJECT:
+                       appendStringInfo(&buffer, "large object");
+                       break;
+
+               case OCLASS_OPERATOR:
+                       appendStringInfo(&buffer, "operator");
+                       break;
+
+               case OCLASS_OPCLASS:
+                       appendStringInfo(&buffer, "operator class");
+                       break;
+
+               case OCLASS_OPFAMILY:
+                       appendStringInfo(&buffer, "operator family");
+                       break;
+
+               case OCLASS_AMOP:
+                       appendStringInfo(&buffer, "operator of access method");
+                       break;
+
+               case OCLASS_AMPROC:
+                       appendStringInfo(&buffer, "function of access method");
+                       break;
+
+               case OCLASS_REWRITE:
+                       appendStringInfo(&buffer, "rule");
+                       break;
+
+               case OCLASS_TRIGGER:
+                       appendStringInfo(&buffer, "trigger");
+                       break;
+
+               case OCLASS_SCHEMA:
+                       appendStringInfo(&buffer, "schema");
+                       break;
+
+               case OCLASS_TSPARSER:
+                       appendStringInfo(&buffer, "text search parser");
+                       break;
+
+               case OCLASS_TSDICT:
+                       appendStringInfo(&buffer, "text search dictionary");
+                       break;
+
+               case OCLASS_TSTEMPLATE:
+                       appendStringInfo(&buffer, "text search template");
+                       break;
+
+               case OCLASS_TSCONFIG:
+                       appendStringInfo(&buffer, "text search configuration");
+                       break;
+
+               case OCLASS_ROLE:
+                       appendStringInfo(&buffer, "role");
+                       break;
+
+               case OCLASS_DATABASE:
+                       appendStringInfo(&buffer, "database");
+                       break;
+
+               case OCLASS_TBLSPACE:
+                       appendStringInfo(&buffer, "tablespace");
+                       break;
+
+               case OCLASS_FDW:
+                       appendStringInfo(&buffer, "foreign-data wrapper");
+                       break;
+
+               case OCLASS_FOREIGN_SERVER:
+                       appendStringInfo(&buffer, "server");
+                       break;
+
+               case OCLASS_USER_MAPPING:
+                       appendStringInfo(&buffer, "user mapping");
+                       break;
+
+               case OCLASS_DEFACL:
+                       appendStringInfo(&buffer, "default acl");
+                       break;
+
+               case OCLASS_EXTENSION:
+                       appendStringInfo(&buffer, "extension");
+                       break;
+
+               case OCLASS_EVENT_TRIGGER:
+                       appendStringInfo(&buffer, "event trigger");
+                       break;
+
+               default:
+                       appendStringInfo(&buffer, "unrecognized %u", object->classId);
+                       break;
+       }
+
+       return buffer.data;
+}
+
+/*
+ * subroutine for getObjectTypeDescription: describe a relation type
+ */
+static void
+getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
+{
+       HeapTuple       relTup;
+       Form_pg_class relForm;
+
+       relTup = SearchSysCache1(RELOID,
+                                                        ObjectIdGetDatum(relid));
+       if (!HeapTupleIsValid(relTup))
+               elog(ERROR, "cache lookup failed for relation %u", relid);
+       relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+       switch (relForm->relkind)
+       {
+               case RELKIND_RELATION:
+                       appendStringInfo(buffer, "table");
+                       break;
+               case RELKIND_INDEX:
+                       appendStringInfo(buffer, "index");
+                       break;
+               case RELKIND_SEQUENCE:
+                       appendStringInfo(buffer, "sequence");
+                       break;
+               case RELKIND_TOASTVALUE:
+                       appendStringInfo(buffer, "toast table");
+                       break;
+               case RELKIND_VIEW:
+                       appendStringInfo(buffer, "view");
+                       break;
+               case RELKIND_MATVIEW:
+                       appendStringInfo(buffer, "materialized view");
+                       break;
+               case RELKIND_COMPOSITE_TYPE:
+                       appendStringInfo(buffer, "composite type");
+                       break;
+               case RELKIND_FOREIGN_TABLE:
+                       appendStringInfo(buffer, "foreign table");
+                       break;
+               default:
+                       /* shouldn't get here */
+                       appendStringInfo(buffer, "relation");
+                       break;
+       }
+
+       if (objectSubId != 0)
+               appendStringInfo(buffer, " column");
+
+       ReleaseSysCache(relTup);
+}
+
+/*
+ * subroutine for getObjectTypeDescription: describe a constraint type
+ */
+static void
+getConstraintTypeDescription(StringInfo buffer, Oid constroid)
+{
+       Relation        constrRel;
+       HeapTuple       constrTup;
+       Form_pg_constraint      constrForm;
+
+       constrRel = heap_open(ConstraintRelationId, AccessShareLock);
+       constrTup = get_catalog_object_by_oid(constrRel, constroid);
+       if (!HeapTupleIsValid(constrTup))
+               elog(ERROR, "cache lookup failed for constraint %u", constroid);
+
+       constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
+
+       if (OidIsValid(constrForm->conrelid))
+               appendStringInfoString(buffer, "table constraint");
+       else if (OidIsValid(constrForm->contypid))
+               appendStringInfoString(buffer, "domain constraint");
+       else
+               elog(ERROR, "invalid constraint %u", HeapTupleGetOid(constrTup));
+
+       heap_close(constrRel, AccessShareLock);
+}
+
+/*
+ * subroutine for getObjectTypeDescription: describe a procedure type
+ */
+static void
+getProcedureTypeDescription(StringInfo buffer, Oid procid)
+{
+       HeapTuple       procTup;
+       Form_pg_proc procForm;
+
+       procTup = SearchSysCache1(PROCOID,
+                                                        ObjectIdGetDatum(procid));
+       if (!HeapTupleIsValid(procTup))
+               elog(ERROR, "cache lookup failed for procedure %u", procid);
+       procForm = (Form_pg_proc) GETSTRUCT(procTup);
+
+       if (procForm->proisagg)
+               appendStringInfo(buffer, "aggregate");
+       else
+               appendStringInfo(buffer, "function");
+
+       ReleaseSysCache(procTup);
+}
+
+/*
+ * Return a palloc'ed string that identifies an object.
+ *
+ * This is for machine consumption, so it's not translated.  All elements are
+ * schema-qualified when appropriate.
+ */
+char *
+getObjectIdentity(const ObjectAddress *object)
+{
+       StringInfoData buffer;
+
+       initStringInfo(&buffer);
+
+       switch (getObjectClass(object))
+       {
+               case OCLASS_CLASS:
+                       getRelationIdentity(&buffer, object->objectId);
+                       if (object->objectSubId != 0)
+                       {
+                               char   *attr;
+
+                               attr = get_relid_attribute_name(object->objectId,
+                                                                                               object->objectSubId);
+                               appendStringInfo(&buffer, ".%s", quote_identifier(attr));
+                       }
+                       break;
+
+               case OCLASS_PROC:
+                       appendStringInfo(&buffer, "%s",
+                                                        format_procedure_qualified(object->objectId));
+                       break;
+
+               case OCLASS_TYPE:
+                       appendStringInfo(&buffer, "%s",
+                                                        format_type_be_qualified(object->objectId));
+                       break;
+
+               case OCLASS_CAST:
+                       {
+                               Relation        castRel;
+                               HeapTuple       tup;
+                               Form_pg_cast castForm;
+
+                               castRel = heap_open(CastRelationId, AccessShareLock);
+
+                               tup = get_catalog_object_by_oid(castRel, object->objectId);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for cast %u",
+                                                object->objectId);
+
+                               castForm = (Form_pg_cast) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer, "(%s AS %s)",
+                                                                format_type_be_qualified(castForm->castsource),
+                                                                format_type_be_qualified(castForm->casttarget));
+
+                               heap_close(castRel, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_COLLATION:
+                       {
+                               HeapTuple       collTup;
+                               Form_pg_collation coll;
+                               char   *schema;
+
+                               collTup = SearchSysCache1(COLLOID,
+                                                                                 ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(collTup))
+                                       elog(ERROR, "cache lookup failed for collation %u",
+                                                object->objectId);
+                               coll = (Form_pg_collation) GETSTRUCT(collTup);
+                               schema = get_namespace_name(coll->collnamespace);
+                               appendStringInfoString(&buffer,
+                                                                          quote_qualified_identifier(schema,
+                                                                                                                                 NameStr(coll->collname)));
+                               ReleaseSysCache(collTup);
+                               break;
+                       }
+
+               case OCLASS_CONSTRAINT:
+                       {
+                               HeapTuple       conTup;
+                               Form_pg_constraint con;
+
+                               conTup = SearchSysCache1(CONSTROID,
+                                                                                ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(conTup))
+                                       elog(ERROR, "cache lookup failed for constraint %u",
+                                                object->objectId);
+                               con = (Form_pg_constraint) GETSTRUCT(conTup);
+
+                               if (OidIsValid(con->conrelid))
+                               {
+                                       appendStringInfo(&buffer, "%s on ",
+                                                                        quote_identifier(NameStr(con->conname)));
+                                       getRelationIdentity(&buffer, con->conrelid);
+                               }
+                               else
+                               {
+                                       ObjectAddress   domain;
+
+                                       domain.classId = TypeRelationId;
+                                       domain.objectId = con->contypid;
+                                       domain.objectSubId = 0;
+
+                                       appendStringInfo(&buffer, "%s on %s",
+                                                                        quote_identifier(NameStr(con->conname)),
+                                                                        getObjectIdentity(&domain));
+                               }
+
+                               ReleaseSysCache(conTup);
+                               break;
+                       }
+
+               case OCLASS_CONVERSION:
+                       {
+                               HeapTuple       conTup;
+                               Form_pg_conversion conForm;
+
+                               conTup = SearchSysCache1(CONVOID,
+                                                                                ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(conTup))
+                                       elog(ERROR, "cache lookup failed for conversion %u",
+                                                object->objectId);
+                               conForm = (Form_pg_conversion) GETSTRUCT(conTup);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(NameStr(conForm->conname)));
+                               ReleaseSysCache(conTup);
+                               break;
+                       }
+
+               case OCLASS_DEFAULT:
+                       {
+                               Relation        attrdefDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc adscan;
+
+                               HeapTuple       tup;
+                               Form_pg_attrdef attrdef;
+                               ObjectAddress colobject;
+
+                               attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
+                                                                                       true, SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(adscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for attrdef %u",
+                                                object->objectId);
+
+                               attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
+
+                               colobject.classId = RelationRelationId;
+                               colobject.objectId = attrdef->adrelid;
+                               colobject.objectSubId = attrdef->adnum;
+
+                               appendStringInfo(&buffer, "for %s",
+                                                                getObjectIdentity(&colobject));
+
+                               systable_endscan(adscan);
+                               heap_close(attrdefDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_LANGUAGE:
+                       {
+                               HeapTuple       langTup;
+                               Form_pg_language langForm;
+
+                               langTup = SearchSysCache1(LANGOID,
+                                                                                 ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(langTup))
+                                       elog(ERROR, "cache lookup failed for language %u",
+                                                object->objectId);
+                               langForm = (Form_pg_language) GETSTRUCT(langTup);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(NameStr(langForm->lanname)));
+                               ReleaseSysCache(langTup);
+                               break;
+                       }
+               case OCLASS_LARGEOBJECT:
+                       appendStringInfo(&buffer, "%u",
+                                                        object->objectId);
+                       break;
+
+               case OCLASS_OPERATOR:
+                       appendStringInfo(&buffer, "%s",
+                                                        format_operator_qualified(object->objectId));
+                       break;
+
+               case OCLASS_OPCLASS:
+                       {
+                               HeapTuple       opcTup;
+                               Form_pg_opclass opcForm;
+                               HeapTuple       amTup;
+                               Form_pg_am      amForm;
+                               char       *schema;
+
+                               opcTup = SearchSysCache1(CLAOID,
+                                                                                ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(opcTup))
+                                       elog(ERROR, "cache lookup failed for opclass %u",
+                                                object->objectId);
+                               opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
+                               schema = get_namespace_name(opcForm->opcnamespace);
+
+                               amTup = SearchSysCache1(AMOID,
+                                                                               ObjectIdGetDatum(opcForm->opcmethod));
+                               if (!HeapTupleIsValid(amTup))
+                                       elog(ERROR, "cache lookup failed for access method %u",
+                                                opcForm->opcmethod);
+                               amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+                               appendStringInfo(&buffer,
+                                                                "%s",
+                                                                quote_qualified_identifier(schema,
+                                                                                                                       NameStr(opcForm->opcname)));
+                               appendStringInfo(&buffer, " for %s",
+                                                                quote_identifier(NameStr(amForm->amname)));
+
+                               ReleaseSysCache(amTup);
+                               ReleaseSysCache(opcTup);
+                               break;
+                       }
+
+               case OCLASS_OPFAMILY:
+                       getOpFamilyIdentity(&buffer, object->objectId);
+                       break;
+
+               case OCLASS_AMOP:
+                       {
+                               Relation        amopDesc;
+                               HeapTuple       tup;
+                               ScanKeyData skey[1];
+                               SysScanDesc amscan;
+                               Form_pg_amop amopForm;
+                               StringInfoData opfam;
+
+                               amopDesc = heap_open(AccessMethodOperatorRelationId,
+                                                                        AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(amscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for amop entry %u",
+                                                object->objectId);
+
+                               amopForm = (Form_pg_amop) GETSTRUCT(tup);
+
+                               initStringInfo(&opfam);
+                               getOpFamilyIdentity(&opfam, amopForm->amopfamily);
+
+                               appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
+                                                                amopForm->amopstrategy,
+                                                                format_type_be_qualified(amopForm->amoplefttype),
+                                                                format_type_be_qualified(amopForm->amoprighttype),
+                                                                opfam.data);
+
+                               pfree(opfam.data);
+
+                               systable_endscan(amscan);
+                               heap_close(amopDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_AMPROC:
+                       {
+                               Relation        amprocDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc amscan;
+                               HeapTuple       tup;
+                               Form_pg_amproc amprocForm;
+                               StringInfoData opfam;
+
+                               amprocDesc = heap_open(AccessMethodProcedureRelationId,
+                                                                          AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(amscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for amproc entry %u",
+                                                object->objectId);
+
+                               amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
+
+                               initStringInfo(&opfam);
+                               getOpFamilyIdentity(&opfam, amprocForm->amprocfamily);
+
+                               appendStringInfo(&buffer, "function %d (%s, %s) of %s",
+                                                                amprocForm->amprocnum,
+                                                                format_type_be_qualified(amprocForm->amproclefttype),
+                                                                format_type_be_qualified(amprocForm->amprocrighttype),
+                                                                opfam.data);
+
+                               pfree(opfam.data);
+
+                               systable_endscan(amscan);
+                               heap_close(amprocDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_REWRITE:
+                       {
+                               Relation        ruleDesc;
+                               HeapTuple       tup;
+                               Form_pg_rewrite rule;
+
+                               ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
+
+                               tup = get_catalog_object_by_oid(ruleDesc, object->objectId);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for rule %u",
+                                                object->objectId);
+
+                               rule = (Form_pg_rewrite) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer, "%s on ",
+                                                                quote_identifier(NameStr(rule->rulename)));
+                               getRelationIdentity(&buffer, rule->ev_class);
+
+                               heap_close(ruleDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_TRIGGER:
+                       {
+                               Relation        trigDesc;
+                               HeapTuple       tup;
+                               Form_pg_trigger trig;
+
+                               trigDesc = heap_open(TriggerRelationId, AccessShareLock);
+
+                               tup = get_catalog_object_by_oid(trigDesc, object->objectId);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for trigger %u",
+                                                object->objectId);
+
+                               trig = (Form_pg_trigger) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer, "%s on ",
+                                                                quote_identifier(NameStr(trig->tgname)));
+                               getRelationIdentity(&buffer, trig->tgrelid);
+
+                               heap_close(trigDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_SCHEMA:
+                       {
+                               char       *nspname;
+
+                               nspname = get_namespace_name(object->objectId);
+                               if (!nspname)
+                                       elog(ERROR, "cache lookup failed for namespace %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(nspname));
+                               break;
+                       }
+
+               case OCLASS_TSPARSER:
+                       {
+                               HeapTuple       tup;
+                               Form_pg_ts_parser       formParser;
+
+                               tup = SearchSysCache1(TSPARSEROID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for text search parser %u",
+                                                object->objectId);
+                               formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(NameStr(formParser->prsname)));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               case OCLASS_TSDICT:
+                       {
+                               HeapTuple       tup;
+                               Form_pg_ts_dict         formDict;
+
+                               tup = SearchSysCache1(TSDICTOID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for text search dictionary %u",
+                                                object->objectId);
+                               formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(NameStr(formDict->dictname)));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               case OCLASS_TSTEMPLATE:
+                       {
+                               HeapTuple       tup;
+                               Form_pg_ts_template formTmpl;
+
+                               tup = SearchSysCache1(TSTEMPLATEOID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for text search template %u",
+                                                object->objectId);
+                               formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(NameStr(formTmpl->tmplname)));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               case OCLASS_TSCONFIG:
+                       {
+                               HeapTuple       tup;
+                               Form_pg_ts_config formCfg;
+
+                               tup = SearchSysCache1(TSCONFIGOID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for text search configuration %u",
+                                                object->objectId);
+                               formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(NameStr(formCfg->cfgname)));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               case OCLASS_ROLE:
+                       {
+                               char   *username;
+
+                               username = GetUserNameFromId(object->objectId);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(username));
+                               break;
+                       }
+
+               case OCLASS_DATABASE:
+                       {
+                               char       *datname;
+
+                               datname = get_database_name(object->objectId);
+                               if (!datname)
+                                       elog(ERROR, "cache lookup failed for database %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(datname));
+                               break;
+                       }
+
+               case OCLASS_TBLSPACE:
+                       {
+                               char       *tblspace;
+
+                               tblspace = get_tablespace_name(object->objectId);
+                               if (!tblspace)
+                                       elog(ERROR, "cache lookup failed for tablespace %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(tblspace));
+                               break;
+                       }
+
+               case OCLASS_FDW:
+                       {
+                               ForeignDataWrapper *fdw;
+
+                               fdw = GetForeignDataWrapper(object->objectId);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(fdw->fdwname));
+                               break;
+                       }
+
+               case OCLASS_FOREIGN_SERVER:
+                       {
+                               ForeignServer *srv;
+
+                               srv = GetForeignServer(object->objectId);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(srv->servername));
+                               break;
+                       }
+
+               case OCLASS_USER_MAPPING:
+                       {
+                               HeapTuple       tup;
+                               Oid                     useid;
+                               const char *usename;
+
+                               tup = SearchSysCache1(USERMAPPINGOID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for user mapping %u",
+                                                object->objectId);
+
+                               useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
+
+                               ReleaseSysCache(tup);
+
+                               if (OidIsValid(useid))
+                                       usename = quote_identifier(GetUserNameFromId(useid));
+                               else
+                                       usename = "public";
+
+                               appendStringInfo(&buffer, "%s", usename);
+                               break;
+                       }
+
+               case OCLASS_DEFACL:
+                       {
+                               Relation        defaclrel;
+                               ScanKeyData skey[1];
+                               SysScanDesc rcscan;
+
+                               HeapTuple       tup;
+                               Form_pg_default_acl defacl;
+
+                               defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
+                                                                                       true, SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(rcscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for default ACL %u",
+                                                object->objectId);
+
+                               defacl = (Form_pg_default_acl) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer,
+                                                                "for role %s",
+                                                                quote_identifier(GetUserNameFromId(defacl->defaclrole)));
+
+                               if (OidIsValid(defacl->defaclnamespace))
+                               {
+                                       char   *schema;
+
+                                       schema = get_namespace_name(defacl->defaclnamespace);
+                                       appendStringInfo(&buffer,
+                                                                        " in schema %s",
+                                                                        quote_identifier(schema));
+                               }
+
+                               switch (defacl->defaclobjtype)
+                               {
+                                       case DEFACLOBJ_RELATION:
+                                               appendStringInfoString(&buffer,
+                                                                                          " on tables");
+                                               break;
+                                       case DEFACLOBJ_SEQUENCE:
+                                               appendStringInfoString(&buffer,
+                                                                                          " on sequences");
+                                               break;
+                                       case DEFACLOBJ_FUNCTION:
+                                               appendStringInfoString(&buffer,
+                                                                                          " on functions");
+                                               break;
+                                       case DEFACLOBJ_TYPE:
+                                               appendStringInfoString(&buffer,
+                                                                                          " on types");
+                                               break;
+                               }
+
+                               systable_endscan(rcscan);
+                               heap_close(defaclrel, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_EXTENSION:
+                       {
+                               char       *extname;
+
+                               extname = get_extension_name(object->objectId);
+                               if (!extname)
+                                       elog(ERROR, "cache lookup failed for extension %u",
+                                                object->objectId);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(extname));
+                               break;
+                       }
+
+               case OCLASS_EVENT_TRIGGER:
+                       {
+                               HeapTuple       tup;
+                               Form_pg_event_trigger trigForm;
+
+                               tup = SearchSysCache1(EVENTTRIGGEROID,
+                                                                         ObjectIdGetDatum(object->objectId));
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "cache lookup failed for event trigger %u",
+                                                object->objectId);
+                               trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
+                               appendStringInfo(&buffer, "%s",
+                                                                quote_identifier(NameStr(trigForm->evtname)));
+                               ReleaseSysCache(tup);
+                               break;
+                       }
+
+               default:
+                       appendStringInfo(&buffer, "unrecognized object %u %u %d",
+                                                        object->classId,
+                                                        object->objectId,
+                                                        object->objectSubId);
+                       break;
+       }
+
+       return buffer.data;
+}
+
+static void
+getOpFamilyIdentity(StringInfo buffer, Oid opfid)
+{
+       HeapTuple       opfTup;
+       Form_pg_opfamily opfForm;
+       HeapTuple       amTup;
+       Form_pg_am      amForm;
+       char       *schema;
+
+       opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
+       if (!HeapTupleIsValid(opfTup))
+               elog(ERROR, "cache lookup failed for opfamily %u", opfid);
+       opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
+
+       amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
+       if (!HeapTupleIsValid(amTup))
+               elog(ERROR, "cache lookup failed for access method %u",
+                        opfForm->opfmethod);
+       amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+       schema = get_namespace_name(opfForm->opfnamespace);
+       appendStringInfo(buffer, "%s for %s",
+                                        quote_qualified_identifier(schema,
+                                                                                               NameStr(opfForm->opfname)),
+                                        NameStr(amForm->amname));
+
+       ReleaseSysCache(amTup);
+       ReleaseSysCache(opfTup);
+}
+
+/*
+ * Append the relation identity (quoted qualified name) to the given
+ * StringInfo.
+ */
+static void
+getRelationIdentity(StringInfo buffer, Oid relid)
+{
+       HeapTuple       relTup;
+       Form_pg_class relForm;
+       char       *schema;
+
+       relTup = SearchSysCache1(RELOID,
+                                                        ObjectIdGetDatum(relid));
+       if (!HeapTupleIsValid(relTup))
+               elog(ERROR, "cache lookup failed for relation %u", relid);
+       relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+       schema = get_namespace_name(relForm->relnamespace);
+       appendStringInfo(buffer, "%s",
+                                        quote_qualified_identifier(schema,
+                                                                                               NameStr(relForm->relname)));
+
+       ReleaseSysCache(relTup);
+}
index 2d2ab1bcfb148079757e7789853388fb6228f44e..665b3804d57e3b79afbf44f2094a7194a9648135 100644 (file)
@@ -752,58 +752,6 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
        }
 }
 
-/*
- * Return a copy of the tuple for the object with the given object OID, from
- * the given catalog (which must have been opened by the caller and suitably
- * locked).  NULL is returned if the OID is not found.
- *
- * We try a syscache first, if available.
- *
- * XXX this function seems general in possible usage.  Given sufficient callers
- * elsewhere, we should consider moving it to a more appropriate place.
- */
-static HeapTuple
-get_catalog_object_by_oid(Relation catalog, Oid objectId)
-{
-       HeapTuple       tuple;
-       Oid                     classId = RelationGetRelid(catalog);
-       int                     oidCacheId = get_object_catcache_oid(classId);
-
-       if (oidCacheId > 0)
-       {
-               tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
-               if (!HeapTupleIsValid(tuple))  /* should not happen */
-                       return NULL;
-       }
-       else
-       {
-               Oid                     oidIndexId = get_object_oid_index(classId);
-               SysScanDesc     scan;
-               ScanKeyData     skey;
-
-               Assert(OidIsValid(oidIndexId));
-
-               ScanKeyInit(&skey,
-                                       ObjectIdAttributeNumber,
-                                       BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(objectId));
-
-               scan = systable_beginscan(catalog, oidIndexId, true,
-                                                                 SnapshotNow, 1, &skey);
-               tuple = systable_getnext(scan);
-               if (!HeapTupleIsValid(tuple))
-               {
-                       systable_endscan(scan);
-                       return NULL;
-               }
-               tuple = heap_copytuple(tuple);
-
-               systable_endscan(scan);
-       }
-
-       return tuple;
-}
-
 /*
  * Generic function to change the ownership of a given object, for simple
  * cases (won't work for tables, nor other cases where we need to do more than
index 9d07f30906c4bfeaa7625e6c0a3e54f343bf9d02..0d82141fef6cb9ae697ae0833febff15bf9236c9 100644 (file)
@@ -5195,20 +5195,25 @@ opt_restart_seqs:
  *     The COMMENT ON statement can take different forms based upon the type of
  *     the object associated with the comment. The form of the statement is:
  *
- *     COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
- *                                COLLATION | CONVERSION | LANGUAGE | OPERATOR CLASS |
- *                                LARGE OBJECT | CAST | COLUMN | SCHEMA | TABLESPACE |
- *                                EXTENSION | ROLE | TEXT SEARCH PARSER |
- *                                TEXT SEARCH DICTIONARY | TEXT SEARCH TEMPLATE |
- *                                TEXT SEARCH CONFIGURATION | FOREIGN TABLE |
- *                                FOREIGN DATA WRAPPER | SERVER | EVENT TRIGGER |
- *                                MATERIALIZED VIEW] <objname> |
+ *     COMMENT ON [ [ CONVERSION | COLLATION | DATABASE | DOMAIN |
+ *                 EXTENSION | EVENT TRIGGER | FOREIGN DATA WRAPPER |
+ *                 FOREIGN TABLE | INDEX | [PROCEDURAL] LANGUAGE |
+ *                 MATERIALIZED VIEW | ROLE | SCHEMA | SEQUENCE |
+ *                 SERVER | TABLE | TABLESPACE |
+ *                 TEXT SEARCH CONFIGURATION | TEXT SEARCH DICTIONARY |
+ *                 TEXT SEARCH PARSER | TEXT SEARCH TEMPLATE | TYPE |
+ *                 VIEW] <objname> |
  *                              AGGREGATE <aggname> (arg1, ...) |
+ *                              CAST (<src type> AS <dst type>) |
+ *                              COLUMN <relname>.<colname> |
+ *                              CONSTRAINT <constraintname> ON <relname> |
  *                              FUNCTION <funcname> (arg1, arg2, ...) |
+ *                              LARGE OBJECT <oid> |
  *                              OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
- *                              TRIGGER <triggername> ON <relname> |
- *                              CONSTRAINT <constraintname> ON <relname> |
- *                              RULE <rulename> ON <relname> ]
+ *                              OPERATOR CLASS <name> USING <access-method> |
+ *                              OPERATOR FAMILY <name> USING <access-method> |
+ *                              RULE <rulename> ON <relname> |
+ *                              TRIGGER <triggername> ON <relname> ]
  *                        IS 'text'
  *
  *****************************************************************************/
@@ -5332,38 +5337,6 @@ CommentStmt:
                                        n->comment = $7;
                                        $$ = (Node *) n;
                                }
-                       | COMMENT ON TEXT_P SEARCH PARSER any_name IS comment_text
-                               {
-                                       CommentStmt *n = makeNode(CommentStmt);
-                                       n->objtype = OBJECT_TSPARSER;
-                                       n->objname = $6;
-                                       n->comment = $8;
-                                       $$ = (Node *) n;
-                               }
-                       | COMMENT ON TEXT_P SEARCH DICTIONARY any_name IS comment_text
-                               {
-                                       CommentStmt *n = makeNode(CommentStmt);
-                                       n->objtype = OBJECT_TSDICTIONARY;
-                                       n->objname = $6;
-                                       n->comment = $8;
-                                       $$ = (Node *) n;
-                               }
-                       | COMMENT ON TEXT_P SEARCH TEMPLATE any_name IS comment_text
-                               {
-                                       CommentStmt *n = makeNode(CommentStmt);
-                                       n->objtype = OBJECT_TSTEMPLATE;
-                                       n->objname = $6;
-                                       n->comment = $8;
-                                       $$ = (Node *) n;
-                               }
-                       | COMMENT ON TEXT_P SEARCH CONFIGURATION any_name IS comment_text
-                               {
-                                       CommentStmt *n = makeNode(CommentStmt);
-                                       n->objtype = OBJECT_TSCONFIGURATION;
-                                       n->objname = $6;
-                                       n->comment = $8;
-                                       $$ = (Node *) n;
-                               }
                ;
 
 comment_type:
@@ -5386,6 +5359,10 @@ comment_type:
                        | SERVER                                                        { $$ = OBJECT_FOREIGN_SERVER; }
                        | FOREIGN DATA_P WRAPPER                        { $$ = OBJECT_FDW; }
                        | EVENT TRIGGER                                         { $$ = OBJECT_EVENT_TRIGGER; }
+                       | TEXT_P SEARCH CONFIGURATION           { $$ = OBJECT_TSCONFIGURATION; }
+                       | TEXT_P SEARCH DICTIONARY                      { $$ = OBJECT_TSDICTIONARY; }
+                       | TEXT_P SEARCH PARSER                          { $$ = OBJECT_TSPARSER; }
+                       | TEXT_P SEARCH TEMPLATE                        { $$ = OBJECT_TSTEMPLATE; }
                ;
 
 comment_text:
index 99771ec53c09b7e1916321eec6f548a55e4cf572..cd164c7e7ea7b7267db5cf8c4fde774a2dfd37a8 100644 (file)
@@ -29,7 +29,8 @@
 #define MAX_INT32_LEN 11
 
 static char *format_type_internal(Oid type_oid, int32 typemod,
-                                        bool typemod_given, bool allow_invalid);
+                                        bool typemod_given, bool allow_invalid,
+                                        bool force_qualify);
 static char *printTypmod(const char *typname, int32 typmod, Oid typmodout);
 static char *
 psnprintf(size_t len, const char *fmt,...)
@@ -77,11 +78,11 @@ format_type(PG_FUNCTION_ARGS)
        type_oid = PG_GETARG_OID(0);
 
        if (PG_ARGISNULL(1))
-               result = format_type_internal(type_oid, -1, false, true);
+               result = format_type_internal(type_oid, -1, false, true, false);
        else
        {
                typemod = PG_GETARG_INT32(1);
-               result = format_type_internal(type_oid, typemod, true, true);
+               result = format_type_internal(type_oid, typemod, true, true, false);
        }
 
        PG_RETURN_TEXT_P(cstring_to_text(result));
@@ -96,7 +97,13 @@ format_type(PG_FUNCTION_ARGS)
 char *
 format_type_be(Oid type_oid)
 {
-       return format_type_internal(type_oid, -1, false, false);
+       return format_type_internal(type_oid, -1, false, false, false);
+}
+
+char *
+format_type_be_qualified(Oid type_oid)
+{
+       return format_type_internal(type_oid, -1, false, false, true);
 }
 
 /*
@@ -105,14 +112,13 @@ format_type_be(Oid type_oid)
 char *
 format_type_with_typemod(Oid type_oid, int32 typemod)
 {
-       return format_type_internal(type_oid, typemod, true, false);
+       return format_type_internal(type_oid, typemod, true, false, false);
 }
 
-
-
 static char *
 format_type_internal(Oid type_oid, int32 typemod,
-                                        bool typemod_given, bool allow_invalid)
+                                        bool typemod_given, bool allow_invalid,
+                                        bool force_qualify)
 {
        bool            with_typemod = typemod_given && (typemod >= 0);
        HeapTuple       tuple;
@@ -300,7 +306,7 @@ format_type_internal(Oid type_oid, int32 typemod,
                char       *nspname;
                char       *typname;
 
-               if (TypeIsVisible(type_oid))
+               if (!force_qualify && TypeIsVisible(type_oid))
                        nspname = NULL;
                else
                        nspname = get_namespace_name(typeform->typnamespace);
@@ -421,7 +427,7 @@ oidvectortypes(PG_FUNCTION_ARGS)
        for (num = 0; num < numargs; num++)
        {
                char       *typename = format_type_internal(oidArray->values[num], -1,
-                                                                                                       false, true);
+                                                                                                       false, true, false);
                size_t          slen = strlen(typename);
 
                if (left < (slen + 2))
index cb11bd0ade63adf8a203a59fc16cf296c0549060..94599aa44ba73367c3660f38ad30f648bcd0028d 100644 (file)
@@ -41,6 +41,8 @@
 #include "utils/syscache.h"
 #include "utils/tqual.h"
 
+static char *format_operator_internal(Oid operator_oid, bool force_qualify);
+static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
 static void parseNameAndArgTypes(const char *string, bool allowNone,
                                         List **names, int *nargs, Oid *argtypes);
 
@@ -303,6 +305,25 @@ regprocedurein(PG_FUNCTION_ARGS)
  */
 char *
 format_procedure(Oid procedure_oid)
+{
+       return format_procedure_internal(procedure_oid, false);
+}
+
+char *
+format_procedure_qualified(Oid procedure_oid)
+{
+       return format_procedure_internal(procedure_oid, true);
+}
+
+/*
+ * Routine to produce regprocedure names; see format_procedure above.
+ *
+ * force_qualify says whether to schema-qualify; if true, the name is always
+ * qualified regardless of search_path visibility.  Otherwise the name is only
+ * qualified if the function is not in path.
+ */
+static char *
+format_procedure_internal(Oid procedure_oid, bool force_qualify)
 {
        char       *result;
        HeapTuple       proctup;
@@ -326,7 +347,7 @@ format_procedure(Oid procedure_oid)
                 * Would this proc be found (given the right args) by regprocedurein?
                 * If not, we need to qualify it.
                 */
-               if (FunctionIsVisible(procedure_oid))
+               if (!force_qualify && FunctionIsVisible(procedure_oid))
                        nspname = NULL;
                else
                        nspname = get_namespace_name(procform->pronamespace);
@@ -339,7 +360,10 @@ format_procedure(Oid procedure_oid)
 
                        if (i > 0)
                                appendStringInfoChar(&buf, ',');
-                       appendStringInfoString(&buf, format_type_be(thisargtype));
+                       appendStringInfoString(&buf,
+                                                                  force_qualify ?
+                                                                  format_type_be_qualified(thisargtype) :
+                                                                  format_type_be(thisargtype));
                }
                appendStringInfoChar(&buf, ')');
 
@@ -653,8 +677,8 @@ regoperatorin(PG_FUNCTION_ARGS)
  * This exports the useful functionality of regoperatorout for use
  * in other backend modules.  The result is a palloc'd string.
  */
-char *
-format_operator(Oid operator_oid)
+static char *
+format_operator_internal(Oid operator_oid, bool force_qualify)
 {
        char       *result;
        HeapTuple       opertup;
@@ -674,9 +698,9 @@ format_operator(Oid operator_oid)
 
                /*
                 * Would this oper be found (given the right args) by regoperatorin?
-                * If not, we need to qualify it.
+                * If not, or if caller explicitely requests it, we need to qualify it.
                 */
-               if (!OperatorIsVisible(operator_oid))
+               if (force_qualify || !OperatorIsVisible(operator_oid))
                {
                        nspname = get_namespace_name(operform->oprnamespace);
                        appendStringInfo(&buf, "%s.",
@@ -687,12 +711,16 @@ format_operator(Oid operator_oid)
 
                if (operform->oprleft)
                        appendStringInfo(&buf, "%s,",
+                                                        force_qualify ?
+                                                        format_type_be_qualified(operform->oprleft) :
                                                         format_type_be(operform->oprleft));
                else
                        appendStringInfo(&buf, "NONE,");
 
                if (operform->oprright)
                        appendStringInfo(&buf, "%s)",
+                                                        force_qualify ?
+                                                        format_type_be_qualified(operform->oprright) :
                                                         format_type_be(operform->oprright));
                else
                        appendStringInfo(&buf, "NONE)");
@@ -713,6 +741,18 @@ format_operator(Oid operator_oid)
        return result;
 }
 
+char *
+format_operator(Oid operator_oid)
+{
+       return format_operator_internal(operator_oid, false);
+}
+
+char *
+format_operator_qualified(Oid operator_oid)
+{
+       return format_operator_internal(operator_oid, true);
+}
+
 /*
  * regoperatorout              - converts operator OID to "opr_name(args)"
  */
index db0776e24d15377607ccab0cf65dd12c8bd94a8a..cbc4673d1b497db7c7488eb8f6ddda38f2b521fa 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201303141
+#define CATALOG_VERSION_NO     201303201
 
 #endif
index 8e0837f7d617fbf0bd59adfabeb0bd64ec4f64f7..3aefbb5e6a9066170f493007ee966fa6485c264e 100644 (file)
@@ -176,9 +176,6 @@ extern void recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
 
 extern ObjectClass getObjectClass(const ObjectAddress *object);
 
-extern char *getObjectDescription(const ObjectAddress *object);
-extern char *getObjectDescriptionOids(Oid classid, Oid objid);
-
 extern ObjectAddresses *new_object_addresses(void);
 
 extern void add_exact_object_address(const ObjectAddress *object,
index ffaf4ea25a132a027baa250937085a69790c2779..2f8f58da9bce3f1e3e29d63e41ea0bab7662d9d2 100644 (file)
@@ -38,6 +38,7 @@ extern void check_object_ownership(Oid roleid,
 
 extern Oid     get_object_namespace(const ObjectAddress *address);
 
+extern bool                            is_objectclass_supported(Oid class_id);
 extern Oid                             get_object_oid_index(Oid class_id);
 extern int                             get_object_catcache_oid(Oid class_id);
 extern int                             get_object_catcache_name(Oid class_id);
@@ -46,5 +47,15 @@ extern AttrNumber            get_object_attnum_namespace(Oid class_id);
 extern AttrNumber              get_object_attnum_owner(Oid class_id);
 extern AttrNumber              get_object_attnum_acl(Oid class_id);
 extern AclObjectKind   get_object_aclkind(Oid class_id);
+extern bool                            get_object_namensp_unique(Oid class_id);
 
-#endif   /* PARSE_OBJECT_H */
+extern HeapTuple               get_catalog_object_by_oid(Relation catalog,
+                                                 Oid objectId);
+
+extern char *getObjectDescription(const ObjectAddress *object);
+extern char *getObjectDescriptionOids(Oid classid, Oid objid);
+
+extern char *getObjectTypeDescription(const ObjectAddress *object);
+extern char *getObjectIdentity(const ObjectAddress *address);
+
+#endif   /* OBJECTADDRESS_H */
index c97056e167399207c3278ca6bf72d01290f888ab..4aee00233a9b06adea1976f107fb20d4e1a64de2 100644 (file)
@@ -2917,6 +2917,9 @@ DESCR("view members of a multixactid");
 DATA(insert OID = 3537 (  pg_describe_object           PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 25 "26 26 23" _null_ _null_ _null_ _null_ pg_describe_object _null_ _null_ _null_ ));
 DESCR("get identification of SQL object");
 
+DATA(insert OID = 3839 (  pg_identify_object           PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 2249 "26 26 23" "{26,23,23,25,25,25,25}" "{i,i,i,o,o,o,o}" "{classid,objid,subobjid,type,schema,name,identity}" _null_ pg_identify_object _null_ _null_ _null_ ));
+DESCR("get machine-parseable identification of SQL object");
+
 DATA(insert OID = 2079 (  pg_table_is_visible          PGNSP PGUID 12 10 0 0 0 f f f f t f s 1 0 16 "26" _null_ _null_ _null_ _null_ pg_table_is_visible _null_ _null_ _null_ ));
 DESCR("is table visible in search path?");
 DATA(insert OID = 2080 (  pg_type_is_visible           PGNSP PGUID 12 10 0 0 0 f f f f t f s 1 0 16 "26" _null_ _null_ _null_ _null_ pg_type_is_visible _null_ _null_ _null_ ));
index c0debe400c472a5638f68278535dfef2d9fd1547..cd8ac9462b53ef3f9c4bd9fe7469ad24a11f8e13 100644 (file)
@@ -615,7 +615,9 @@ extern Datum regdictionarysend(PG_FUNCTION_ARGS);
 extern Datum text_regclass(PG_FUNCTION_ARGS);
 extern List *stringToQualifiedNameList(const char *string);
 extern char *format_procedure(Oid procedure_oid);
+extern char *format_procedure_qualified(Oid procedure_oid);
 extern char *format_operator(Oid operator_oid);
+extern char *format_operator_qualified(Oid operator_oid);
 
 /* rowtypes.c */
 extern Datum record_in(PG_FUNCTION_ARGS);
@@ -1027,6 +1029,7 @@ extern Datum pg_encoding_max_length_sql(PG_FUNCTION_ARGS);
 /* format_type.c */
 extern Datum format_type(PG_FUNCTION_ARGS);
 extern char *format_type_be(Oid type_oid);
+extern char *format_type_be_qualified(Oid type_oid);
 extern char *format_type_with_typemod(Oid type_oid, int32 typemod);
 extern Datum oidvectortypes(PG_FUNCTION_ARGS);
 extern int32 type_maximum_size(Oid type_oid, int32 typemod);
@@ -1143,6 +1146,7 @@ extern Datum pg_get_multixact_members(PG_FUNCTION_ARGS);
 
 /* catalogs/dependency.c */
 extern Datum pg_describe_object(PG_FUNCTION_ARGS);
+extern Datum pg_identify_object(PG_FUNCTION_ARGS);
 
 /* commands/constraint.c */
 extern Datum unique_key_recheck(PG_FUNCTION_ARGS);