]> granicus.if.org Git - postgresql/commitdiff
Add pg_identify_object_as_address
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 30 Dec 2014 18:41:50 +0000 (15:41 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 30 Dec 2014 18:41:50 +0000 (15:41 -0300)
This function returns object type and objname/objargs arrays, which can
be passed to pg_get_object_address.  This is especially useful because
the textual representation can be copied to a remote server in order to
obtain the corresponding OID-based address.  In essence, this function
is the inverse of recently added pg_get_object_address().

Catalog version bumped due to the addition of the new function.

Also add docs to pg_get_object_address.

doc/src/sgml/func.sgml
src/backend/catalog/objectaddress.c
src/backend/utils/adt/regproc.c
src/include/catalog/catversion.h
src/include/catalog/objectaddress.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/test/regress/expected/object_address.out
src/test/regress/sql/object_address.sql

index 24c64b7187f2fa5f27612528608cb1eead714cff..53aeb12f9a51e53dcd950de198971ffa133ce7b8 100644 (file)
@@ -15307,14 +15307,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
     <primary>format_type</primary>
    </indexterm>
 
-   <indexterm>
-    <primary>pg_describe_object</primary>
-   </indexterm>
-
-   <indexterm>
-    <primary>pg_identify_object</primary>
-   </indexterm>
-
    <indexterm>
     <primary>pg_get_constraintdef</primary>
    </indexterm>
@@ -15429,16 +15421,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
        <entry><type>text</type></entry>
        <entry>get SQL name of a data type</entry>
       </row>
-      <row>
-       <entry><literal><function>pg_describe_object(<parameter>catalog_id</parameter>, <parameter>object_id</parameter>, <parameter>object_sub_id</parameter>)</function></literal></entry>
-       <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>
@@ -15707,31 +15689,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
    <structname>pg_class</> catalogs.
   </para>
 
-  <para>
-   <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 a 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
@@ -15790,6 +15747,112 @@ SELECT collation for ('foo' COLLATE "de_DE");
    the given name matches multiple objects).
   </para>
 
+   <indexterm>
+    <primary>pg_describe_object</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_identify_object</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_identify_object_as_address</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_get_object_address</primary>
+   </indexterm>
+
+  <para>
+   <xref linkend="functions-info-object-table"> lists functions related to
+   database object identification and addressing.
+  </para>
+
+   <table id="functions-info-object-table">
+    <title>Object Information and Addressing Functions</title>
+    <tgroup cols="3">
+     <thead>
+      <row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
+     </thead>
+
+     <tbody>
+      <row>
+       <entry><literal><function>pg_describe_object(<parameter>catalog_id</parameter>, <parameter>object_id</parameter>, <parameter>object_sub_id</parameter>)</function></literal></entry>
+       <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_identify_object_as_address(<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>name</> <type>text[]</>, <parameter>args</> <type>text[]</></entry>
+       <entry>get external representation of a database object's address</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_get_object_address(<parameter>type</parameter> <type>text</>, <parameter>name</parameter> <type>text[]</>, <parameter>args</parameter> <type>text[]</>)</function></literal></entry>
+       <entry><parameter>catalog_id</> <type>oid</>, <parameter>object_id</> <type>oid</>, <parameter>object_sub_id</> <type>int32</></entry>
+       <entry>get address of a database object, from its external representation</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+  <para>
+   <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 a 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_identify_object_as_address</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.  The returned
+   information is independent of the current server, that is, it could be used
+   to identify an identically named object in another server.
+   <parameter>type</> identifies the type of database object;
+   <parameter>name</> and <parameter>args</> are text arrays that together
+   form a reference to the object.  These three columns can be passed to
+   <function>pg_get_object_address</> to obtain the internal address
+   of the object.
+   This function is the inverse of <function>pg_get_object_address</function>.
+  </para>
+
+  <para>
+   <function>pg_get_object_address</function> returns a row containing enough
+   information to uniquely identify the database object specified by its
+   type and object name and argument arrays.  The returned values are the
+   ones that would be used in system catalogs such as <structname>pg_depend</>
+   and can be passed to other system functions such as
+   <function>pg_identify_object</> or <function>pg_describe_object</>.
+   <parameter>catalog_id</> is the OID of the system catalog containing the
+   object;
+   <parameter>object_id</> is the OID of the object itself, and
+   <parameter>object_sub_id</> is the object sub-ID, or zero if none.
+   This function is the inverse of <function>pg_identify_object_as_address</function>.
+  </para>
+
    <indexterm>
     <primary>col_description</primary>
    </indexterm>
index 9ca609d886881d93b8daac268699496b5e52a66b..cd763b3b91d03dc95865b6391c1b3d9870002d80 100644 (file)
@@ -74,6 +74,7 @@
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
+#include "utils/memutils.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
 
@@ -556,8 +557,9 @@ 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);
+static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname,
+                                       List **objargs);
+static void getRelationIdentity(StringInfo buffer, Oid relid, List **objname);
 
 /*
  * Translate an object name and arguments (as passed by the parser) to an
@@ -2931,6 +2933,66 @@ pg_identify_object(PG_FUNCTION_ARGS)
        PG_RETURN_DATUM(HeapTupleGetDatum(htup));
 }
 
+/*
+ * SQL-level callable function to obtain object type + identity
+ */
+Datum
+pg_identify_object_as_address(PG_FUNCTION_ARGS)
+{
+       Oid                     classid = PG_GETARG_OID(0);
+       Oid                     objid = PG_GETARG_OID(1);
+       int32           subobjid = PG_GETARG_INT32(2);
+       ObjectAddress address;
+       char       *identity;
+       List       *names;
+       List       *args;
+       Datum           values[3];
+       bool            nulls[3];
+       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(3, false);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "object_names",
+                                          TEXTARRAYOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_args",
+                                          TEXTARRAYOID, -1, 0);
+
+       tupdesc = BlessTupleDesc(tupdesc);
+
+       /* object type */
+       values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
+       nulls[0] = false;
+
+       /* object identity */
+       identity = getObjectIdentityParts(&address, &names, &args);
+       pfree(identity);
+
+       /* object_names */
+       values[1] = PointerGetDatum(strlist_to_textarray(names));
+       nulls[1] = false;
+
+       /* object_args */
+       if (args)
+               values[2] = PointerGetDatum(strlist_to_textarray(args));
+       else
+               values[2] = PointerGetDatum(construct_empty_array(TEXTOID));
+       nulls[2] = 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.
@@ -3187,22 +3249,50 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid)
 }
 
 /*
- * Return a palloc'ed string that identifies an object.
+ * Obtain a given object's identity, as a palloc'ed string.
  *
  * This is for machine consumption, so it's not translated.  All elements are
  * schema-qualified when appropriate.
  */
 char *
 getObjectIdentity(const ObjectAddress *object)
+{
+       return getObjectIdentityParts(object, NULL, NULL);
+}
+
+/*
+ * As above, but more detailed.
+ *
+ * There are two sets of return values: the identity itself as a palloc'd
+ * string is returned.  objname and objargs, if not NULL, are output parameters
+ * that receive lists of C-strings that are useful to give back to
+ * get_object_address() to reconstruct the ObjectAddress.
+ */
+char *
+getObjectIdentityParts(const ObjectAddress *object,
+                                          List **objname, List **objargs)
 {
        StringInfoData buffer;
 
        initStringInfo(&buffer);
 
+       /*
+        * Make sure that both objname and objargs were passed, or none was; and
+        * initialize them to empty lists.  For objname this is useless because it
+        * will be initialized in all cases inside the switch; but we do it anyway
+        * so that we can test below that no branch leaves it unset.
+        */
+       Assert(PointerIsValid(objname) == PointerIsValid(objargs));
+       if (objname)
+       {
+               *objname = NIL;
+               *objargs = NIL;
+       }
+
        switch (getObjectClass(object))
        {
                case OCLASS_CLASS:
-                       getRelationIdentity(&buffer, object->objectId);
+                       getRelationIdentity(&buffer, object->objectId, objname);
                        if (object->objectSubId != 0)
                        {
                                char       *attr;
@@ -3210,17 +3300,27 @@ getObjectIdentity(const ObjectAddress *object)
                                attr = get_relid_attribute_name(object->objectId,
                                                                                                object->objectSubId);
                                appendStringInfo(&buffer, ".%s", quote_identifier(attr));
+                               if (objname)
+                                       *objname = lappend(*objname, attr);
                        }
                        break;
 
                case OCLASS_PROC:
                        appendStringInfoString(&buffer,
                                                           format_procedure_qualified(object->objectId));
+                       if (objname)
+                               format_procedure_parts(object->objectId, objname, objargs);
                        break;
 
                case OCLASS_TYPE:
-                       appendStringInfoString(&buffer,
-                                                                format_type_be_qualified(object->objectId));
+                       {
+                               char *typeout;
+
+                               typeout = format_type_be_qualified(object->objectId);
+                               appendStringInfoString(&buffer, typeout);
+                               if (objname)
+                                       *objname = list_make1(typeout);
+                       }
                        break;
 
                case OCLASS_CAST:
@@ -3243,6 +3343,12 @@ getObjectIdentity(const ObjectAddress *object)
                                                          format_type_be_qualified(castForm->castsource),
                                                         format_type_be_qualified(castForm->casttarget));
 
+                               if (objname)
+                               {
+                                       *objname = list_make1(format_type_be_qualified(castForm->castsource));
+                                       *objargs = list_make1(format_type_be_qualified(castForm->casttarget));
+                               }
+
                                heap_close(castRel, AccessShareLock);
                                break;
                        }
@@ -3263,6 +3369,8 @@ getObjectIdentity(const ObjectAddress *object)
                                appendStringInfoString(&buffer,
                                                                           quote_qualified_identifier(schema,
                                                                                                   NameStr(coll->collname)));
+                               if (objname)
+                                       *objname = list_make2(schema, NameStr(coll->collname));
                                ReleaseSysCache(collTup);
                                break;
                        }
@@ -3283,19 +3391,25 @@ getObjectIdentity(const ObjectAddress *object)
                                {
                                        appendStringInfo(&buffer, "%s on ",
                                                                         quote_identifier(NameStr(con->conname)));
-                                       getRelationIdentity(&buffer, con->conrelid);
+                                       getRelationIdentity(&buffer, con->conrelid, objname);
+                                       if (objname)
+                                               *objname = lappend(*objname, pstrdup(NameStr(con->conname)));
                                }
                                else
                                {
                                        ObjectAddress domain;
 
+                                       Assert(OidIsValid(con->contypid));
                                        domain.classId = TypeRelationId;
                                        domain.objectId = con->contypid;
                                        domain.objectSubId = 0;
 
                                        appendStringInfo(&buffer, "%s on %s",
                                                                         quote_identifier(NameStr(con->conname)),
-                                                                        getObjectIdentity(&domain));
+                                                                        getObjectIdentityParts(&domain, objname, objargs));
+
+                                       if (objname)
+                                               *objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
                                }
 
                                ReleaseSysCache(conTup);
@@ -3315,6 +3429,8 @@ getObjectIdentity(const ObjectAddress *object)
                                conForm = (Form_pg_conversion) GETSTRUCT(conTup);
                                appendStringInfoString(&buffer,
                                                                quote_identifier(NameStr(conForm->conname)));
+                               if (objname)
+                                       *objname = list_make1(pstrdup(NameStr(conForm->conname)));
                                ReleaseSysCache(conTup);
                                break;
                        }
@@ -3352,7 +3468,8 @@ getObjectIdentity(const ObjectAddress *object)
                                colobject.objectSubId = attrdef->adnum;
 
                                appendStringInfo(&buffer, "for %s",
-                                                                getObjectIdentity(&colobject));
+                                                                getObjectIdentityParts(&colobject,
+                                                                                                               objname, objargs));
 
                                systable_endscan(adscan);
                                heap_close(attrdefDesc, AccessShareLock);
@@ -3372,17 +3489,23 @@ getObjectIdentity(const ObjectAddress *object)
                                langForm = (Form_pg_language) GETSTRUCT(langTup);
                                appendStringInfoString(&buffer,
                                                           quote_identifier(NameStr(langForm->lanname)));
+                               if (objname)
+                                       *objname = list_make1(pstrdup(NameStr(langForm->lanname)));
                                ReleaseSysCache(langTup);
                                break;
                        }
                case OCLASS_LARGEOBJECT:
                        appendStringInfo(&buffer, "%u",
                                                         object->objectId);
+                       if (objname)
+                               *objname = list_make1(psprintf("%u", object->objectId));
                        break;
 
                case OCLASS_OPERATOR:
                        appendStringInfoString(&buffer,
                                                                format_operator_qualified(object->objectId));
+                       if (objname)
+                               format_operator_parts(object->objectId, objname, objargs);
                        break;
 
                case OCLASS_OPCLASS:
@@ -3413,14 +3536,19 @@ getObjectIdentity(const ObjectAddress *object)
                                                                                                 NameStr(opcForm->opcname)));
                                appendStringInfo(&buffer, " for %s",
                                                                 quote_identifier(NameStr(amForm->amname)));
-
+                               if (objname)
+                               {
+                                       *objname = list_make2(pstrdup(schema),
+                                                                                 pstrdup(NameStr(opcForm->opcname)));
+                                       *objargs = list_make1(pstrdup(NameStr(amForm->amname)));
+                               }
                                ReleaseSysCache(amTup);
                                ReleaseSysCache(opcTup);
                                break;
                        }
 
                case OCLASS_OPFAMILY:
-                       getOpFamilyIdentity(&buffer, object->objectId);
+                       getOpFamilyIdentity(&buffer, object->objectId, objname, objargs);
                        break;
 
                case OCLASS_AMOP:
@@ -3432,6 +3560,10 @@ getObjectIdentity(const ObjectAddress *object)
                                Form_pg_amop amopForm;
                                StringInfoData opfam;
 
+                               /* no objname support here */
+                               if (objname)
+                                       *objname = NIL;
+
                                amopDesc = heap_open(AccessMethodOperatorRelationId,
                                                                         AccessShareLock);
 
@@ -3452,7 +3584,7 @@ getObjectIdentity(const ObjectAddress *object)
                                amopForm = (Form_pg_amop) GETSTRUCT(tup);
 
                                initStringInfo(&opfam);
-                               getOpFamilyIdentity(&opfam, amopForm->amopfamily);
+                               getOpFamilyIdentity(&opfam, amopForm->amopfamily, NULL, NULL);
 
                                appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
                                                                 amopForm->amopstrategy,
@@ -3476,6 +3608,10 @@ getObjectIdentity(const ObjectAddress *object)
                                Form_pg_amproc amprocForm;
                                StringInfoData opfam;
 
+                               /* no objname support here */
+                               if (objname)
+                                       *objname = NIL;
+
                                amprocDesc = heap_open(AccessMethodProcedureRelationId,
                                                                           AccessShareLock);
 
@@ -3496,7 +3632,7 @@ getObjectIdentity(const ObjectAddress *object)
                                amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
 
                                initStringInfo(&opfam);
-                               getOpFamilyIdentity(&opfam, amprocForm->amprocfamily);
+                               getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, NULL, NULL);
 
                                appendStringInfo(&buffer, "function %d (%s, %s) of %s",
                                                                 amprocForm->amprocnum,
@@ -3529,7 +3665,9 @@ getObjectIdentity(const ObjectAddress *object)
 
                                appendStringInfo(&buffer, "%s on ",
                                                                 quote_identifier(NameStr(rule->rulename)));
-                               getRelationIdentity(&buffer, rule->ev_class);
+                               getRelationIdentity(&buffer, rule->ev_class, objname);
+                               if (objname)
+                                       *objname = lappend(*objname, NameStr(rule->rulename));
 
                                heap_close(ruleDesc, AccessShareLock);
                                break;
@@ -3553,7 +3691,9 @@ getObjectIdentity(const ObjectAddress *object)
 
                                appendStringInfo(&buffer, "%s on ",
                                                                 quote_identifier(NameStr(trig->tgname)));
-                               getRelationIdentity(&buffer, trig->tgrelid);
+                               getRelationIdentity(&buffer, trig->tgrelid, objname);
+                               if (objname)
+                                       *objname = lappend(*objname, NameStr(trig->tgname));
 
                                heap_close(trigDesc, AccessShareLock);
                                break;
@@ -3577,7 +3717,9 @@ getObjectIdentity(const ObjectAddress *object)
 
                                appendStringInfo(&buffer, "%s on ",
                                                                 quote_identifier(NameStr(policy->polname)));
-                               getRelationIdentity(&buffer, policy->polrelid);
+                               getRelationIdentity(&buffer, policy->polrelid, objname);
+                               if (objname)
+                                       *objname = lappend(*objname, NameStr(policy->polname));
 
                                heap_close(polDesc, AccessShareLock);
                                break;
@@ -3593,6 +3735,8 @@ getObjectIdentity(const ObjectAddress *object)
                                                 object->objectId);
                                appendStringInfoString(&buffer,
                                                                           quote_identifier(nspname));
+                               if (objname)
+                                       *objname = list_make1(nspname);
                                break;
                        }
 
@@ -3612,6 +3756,9 @@ getObjectIdentity(const ObjectAddress *object)
                                appendStringInfoString(&buffer,
                                                                           quote_qualified_identifier(schema,
                                                                                          NameStr(formParser->prsname)));
+                               if (objname)
+                                       *objname = list_make2(schema,
+                                                                                 pstrdup(NameStr(formParser->prsname)));
                                ReleaseSysCache(tup);
                                break;
                        }
@@ -3632,6 +3779,9 @@ getObjectIdentity(const ObjectAddress *object)
                                appendStringInfoString(&buffer,
                                                                           quote_qualified_identifier(schema,
                                                                                           NameStr(formDict->dictname)));
+                               if (objname)
+                                       *objname = list_make2(schema,
+                                                                                 pstrdup(NameStr(formDict->dictname)));
                                ReleaseSysCache(tup);
                                break;
                        }
@@ -3652,7 +3802,9 @@ getObjectIdentity(const ObjectAddress *object)
                                appendStringInfoString(&buffer,
                                                                           quote_qualified_identifier(schema,
                                                                                           NameStr(formTmpl->tmplname)));
-                               pfree(schema);
+                               if (objname)
+                                       *objname = list_make2(schema,
+                                                                                 pstrdup(NameStr(formTmpl->tmplname)));
                                ReleaseSysCache(tup);
                                break;
                        }
@@ -3673,6 +3825,9 @@ getObjectIdentity(const ObjectAddress *object)
                                appendStringInfoString(&buffer,
                                                                           quote_qualified_identifier(schema,
                                                                                                 NameStr(formCfg->cfgname)));
+                               if (objname)
+                                       *objname = list_make2(schema,
+                                                                                 pstrdup(NameStr(formCfg->cfgname)));
                                ReleaseSysCache(tup);
                                break;
                        }
@@ -3682,6 +3837,8 @@ getObjectIdentity(const ObjectAddress *object)
                                char       *username;
 
                                username = GetUserNameFromId(object->objectId);
+                               if (objname)
+                                       *objname = list_make1(username);
                                appendStringInfoString(&buffer,
                                                                           quote_identifier(username));
                                break;
@@ -3695,6 +3852,8 @@ getObjectIdentity(const ObjectAddress *object)
                                if (!datname)
                                        elog(ERROR, "cache lookup failed for database %u",
                                                 object->objectId);
+                               if (objname)
+                                       *objname = list_make1(datname);
                                appendStringInfoString(&buffer,
                                                                           quote_identifier(datname));
                                break;
@@ -3708,6 +3867,8 @@ getObjectIdentity(const ObjectAddress *object)
                                if (!tblspace)
                                        elog(ERROR, "cache lookup failed for tablespace %u",
                                                 object->objectId);
+                               if (objname)
+                                       *objname = list_make1(tblspace);
                                appendStringInfoString(&buffer,
                                                                           quote_identifier(tblspace));
                                break;
@@ -3719,6 +3880,8 @@ getObjectIdentity(const ObjectAddress *object)
 
                                fdw = GetForeignDataWrapper(object->objectId);
                                appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
+                               if (objname)
+                                       *objname = list_make1(pstrdup(fdw->fdwname));
                                break;
                        }
 
@@ -3729,6 +3892,8 @@ getObjectIdentity(const ObjectAddress *object)
                                srv = GetForeignServer(object->objectId);
                                appendStringInfoString(&buffer,
                                                                           quote_identifier(srv->servername));
+                               if (objname)
+                                       *objname = list_make1(pstrdup(srv->servername));
                                break;
                        }
 
@@ -3738,6 +3903,10 @@ getObjectIdentity(const ObjectAddress *object)
                                Oid                     useid;
                                const char *usename;
 
+                               /* no objname support */
+                               if (objname)
+                                       *objname = NIL;
+
                                tup = SearchSysCache1(USERMAPPINGOID,
                                                                          ObjectIdGetDatum(object->objectId));
                                if (!HeapTupleIsValid(tup))
@@ -3762,10 +3931,13 @@ getObjectIdentity(const ObjectAddress *object)
                                Relation        defaclrel;
                                ScanKeyData skey[1];
                                SysScanDesc rcscan;
-
                                HeapTuple       tup;
                                Form_pg_default_acl defacl;
 
+                               /* no objname support */
+                               if (objname)
+                                       *objname = NIL;
+
                                defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
 
                                ScanKeyInit(&skey[0],
@@ -3832,6 +4004,8 @@ getObjectIdentity(const ObjectAddress *object)
                                        elog(ERROR, "cache lookup failed for extension %u",
                                                 object->objectId);
                                appendStringInfoString(&buffer, quote_identifier(extname));
+                               if (objname)
+                                       *objname = list_make1(extname);
                                break;
                        }
 
@@ -3840,6 +4014,10 @@ getObjectIdentity(const ObjectAddress *object)
                                HeapTuple       tup;
                                Form_pg_event_trigger trigForm;
 
+                               /* no objname support here */
+                               if (objname)
+                                       *objname = NIL;
+
                                tup = SearchSysCache1(EVENTTRIGGEROID,
                                                                          ObjectIdGetDatum(object->objectId));
                                if (!HeapTupleIsValid(tup))
@@ -3860,11 +4038,21 @@ getObjectIdentity(const ObjectAddress *object)
                        break;
        }
 
+       /*
+        * If a get_object_address representation was requested, make sure we are
+        * providing one.  We don't check for objargs, because many of the cases
+        * above leave it as NIL.
+        */
+       if (objname && *objname == NIL)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("requested object address for object type that cannot support it")));
+
        return buffer.data;
 }
 
 static void
-getOpFamilyIdentity(StringInfo buffer, Oid opfid)
+getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname, List **objargs)
 {
        HeapTuple       opfTup;
        Form_pg_opfamily opfForm;
@@ -3889,6 +4077,13 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid)
                                                                                                NameStr(opfForm->opfname)),
                                         NameStr(amForm->amname));
 
+       if (objname)
+       {
+               *objname = list_make2(pstrdup(schema),
+                                                         pstrdup(NameStr(opfForm->opfname)));
+               *objargs = list_make1(pstrdup(NameStr(amForm->amname)));
+       }
+
        ReleaseSysCache(amTup);
        ReleaseSysCache(opfTup);
 }
@@ -3898,7 +4093,7 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid)
  * StringInfo.
  */
 static void
-getRelationIdentity(StringInfo buffer, Oid relid)
+getRelationIdentity(StringInfo buffer, Oid relid, List **objname)
 {
        HeapTuple       relTup;
        Form_pg_class relForm;
@@ -3914,6 +4109,45 @@ getRelationIdentity(StringInfo buffer, Oid relid)
        appendStringInfoString(buffer,
                                                   quote_qualified_identifier(schema,
                                                                                                 NameStr(relForm->relname)));
+       if (objname)
+               *objname = list_make2(schema, pstrdup(NameStr(relForm->relname)));
 
        ReleaseSysCache(relTup);
 }
+
+/*
+ * Auxiliary function to return a TEXT array out of a list of C-strings.
+ */
+ArrayType *
+strlist_to_textarray(List *list)
+{
+       ArrayType *arr;
+       Datum   *datums;
+       int             j = 0;
+       ListCell *cell;
+       MemoryContext memcxt;
+       MemoryContext oldcxt;
+
+       memcxt = AllocSetContextCreate(CurrentMemoryContext,
+                                                                  "strlist to array",
+                                                                  ALLOCSET_DEFAULT_MINSIZE,
+                                                                  ALLOCSET_DEFAULT_INITSIZE,
+                                                                  ALLOCSET_DEFAULT_MAXSIZE);
+       oldcxt = MemoryContextSwitchTo(memcxt);
+
+       datums = palloc(sizeof(text *) * list_length(list));
+       foreach(cell, list)
+       {
+               char   *name = lfirst(cell);
+
+               datums[j++] = CStringGetTextDatum(name);
+       }
+
+       MemoryContextSwitchTo(oldcxt);
+
+       arr = construct_array(datums, list_length(list),
+                                                 TEXTOID, -1, false, 'i');
+       MemoryContextDelete(memcxt);
+
+       return arr;
+}
index c0314ee53227c39a6b3ac9b4b5d14b69203f2371..8cda52ba8cb342af268732452766a405f953cd9e 100644 (file)
@@ -438,6 +438,41 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify)
        return result;
 }
 
+/*
+ * Output a objname/objargs representation for the procedure with the
+ * given OID.  If it doesn't exist, an error is thrown.
+ *
+ * This can be used to feed get_object_address.
+ */
+void
+format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs)
+{
+       HeapTuple       proctup;
+       Form_pg_proc procform;
+       int                     nargs;
+       int                     i;
+
+       proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
+
+       if (!HeapTupleIsValid(proctup))
+               elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
+
+       procform = (Form_pg_proc) GETSTRUCT(proctup);
+       nargs = procform->pronargs;
+
+       *objnames = list_make2(get_namespace_name(procform->pronamespace),
+                                                  pstrdup(NameStr(procform->proname)));
+       *objargs = NIL;
+       for (i = 0; i < nargs; i++)
+       {
+               Oid             thisargtype = procform->proargtypes.values[i];
+
+               *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
+       }
+
+       ReleaseSysCache(proctup);
+}
+
 /*
  * regprocedureout             - converts proc OID to "pro_name(args)"
  */
@@ -875,6 +910,31 @@ format_operator_qualified(Oid operator_oid)
        return format_operator_internal(operator_oid, true);
 }
 
+void
+format_operator_parts(Oid operator_oid, List **objnames, List **objargs)
+{
+       HeapTuple       opertup;
+       Form_pg_operator oprForm;
+
+       opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
+       if (!HeapTupleIsValid(opertup))
+               elog(ERROR, "cache lookup failed for operator with OID %u",
+                        operator_oid);
+
+       oprForm = (Form_pg_operator) GETSTRUCT(opertup);
+       *objnames = list_make2(get_namespace_name(oprForm->oprnamespace),
+                                                  pstrdup(NameStr(oprForm->oprname)));
+       *objargs = NIL;
+       if (oprForm->oprleft)
+               *objargs = lappend(*objargs,
+                                                  format_type_be_qualified(oprForm->oprleft));
+       if (oprForm->oprright)
+               *objargs = lappend(*objargs,
+                                                  format_type_be_qualified(oprForm->oprright));
+
+       ReleaseSysCache(opertup);
+}
+
 /*
  * regoperatorout              - converts operator OID to "opr_name(args)"
  */
index 042ecef8029fd1be937f77539aa43e1509ec3e76..b4c08136f621cf79d6de9f700dcf72f084cdf092 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201412234
+#define CATALOG_VERSION_NO     201412301
 
 #endif
index d885692a43a8944f99afb1888eaf2bc691bbb971..27cae445a1a3da408ddddf3ede109ecdf3b31339 100644 (file)
@@ -58,5 +58,8 @@ extern char *getObjectDescriptionOids(Oid classid, Oid objid);
 extern int read_objtype_from_string(const char *objtype);
 extern char *getObjectTypeDescription(const ObjectAddress *object);
 extern char *getObjectIdentity(const ObjectAddress *address);
+extern char *getObjectIdentityParts(const ObjectAddress *address,
+                                          List **objname, List **objargs);
+extern ArrayType *strlist_to_textarray(List *list);
 
 #endif   /* OBJECTADDRESS_H */
index 484b853a10e38de949581859bd21f125e92a4009..5c10d96ce293c72e99396cebde63fbc3574fb12c 100644 (file)
@@ -3036,6 +3036,9 @@ 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,26,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 = 3382 (  pg_identify_object_as_address        PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 2249 "26 26 23" "{26,26,23,25,1009,1009}" "{i,i,i,o,o,o}" "{classid,objid,subobjid,type,object_names,object_args}" _null_ pg_identify_object_as_address _null_ _null_ _null_ ));
+DESCR("get identification of SQL object for pg_get_object_address()");
+
 DATA(insert OID = 3954 (  pg_get_object_address    PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 2249 "25 1009 1009" "{25,1009,1009,26,26,23}" "{i,i,i,o,o,o}" "{type,name,args,classid,objid,subobjid}" _null_ pg_get_object_address _null_ _null_ _null_ ));
 DESCR("get OID-based object address from name/args arrays");
 
index 7c4d29145e9d2d2c4953572ba2daf7e15e0ec06d..e05ffb28ca4caf79a53d4e0674613b1c129e8fcf 100644 (file)
@@ -642,8 +642,12 @@ 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 void format_procedure_parts(Oid operator_oid, List **objnames,
+                                         List **objargs);
 extern char *format_operator(Oid operator_oid);
 extern char *format_operator_qualified(Oid operator_oid);
+extern void format_operator_parts(Oid operator_oid, List **objnames,
+                                         List **objargs);
 
 /* rowtypes.c */
 extern Datum record_in(PG_FUNCTION_ARGS);
@@ -1194,6 +1198,7 @@ extern Datum pg_last_committed_xact(PG_FUNCTION_ARGS);
 /* catalogs/dependency.c */
 extern Datum pg_describe_object(PG_FUNCTION_ARGS);
 extern Datum pg_identify_object(PG_FUNCTION_ARGS);
+extern Datum pg_identify_object_as_address(PG_FUNCTION_ARGS);
 
 /* catalog/objectaddress.c */
 extern Datum pg_get_object_address(PG_FUNCTION_ARGS);
index 87c08daba81fe18ea3167128ca5089d271e28598..8e11b427590c7675f8c7c02f935edce3eff82a1d 100644 (file)
@@ -339,46 +339,51 @@ WITH objects (type, name, args) AS (VALUES
                                -- event trigger
                                ('policy', '{addr_nsp, gentable, genpol}', '{}')
         )
-SELECT (pg_identify_object(classid, objid, subobjid)).*
-  FROM objects, pg_get_object_address(type, name, args)
-ORDER BY classid, objid;
-           type            |   schema   |       name        |                               identity                               
----------------------------+------------+-------------------+----------------------------------------------------------------------
- type                      | pg_catalog | _int4             | integer[]
- type                      | addr_nsp   | gencomptype       | addr_nsp.gencomptype
- type                      | addr_nsp   | genenum           | addr_nsp.genenum
- type                      | addr_nsp   | gendomain         | addr_nsp.gendomain
- function                  | pg_catalog |                   | pg_catalog.pg_identify_object(pg_catalog.oid,pg_catalog.oid,integer)
- aggregate                 | addr_nsp   |                   | addr_nsp.genaggr(integer)
- sequence                  | addr_nsp   | gentable_a_seq    | addr_nsp.gentable_a_seq
- table                     | addr_nsp   | gentable          | addr_nsp.gentable
- table column              | addr_nsp   | gentable          | addr_nsp.gentable.b
- index                     | addr_nsp   | gentable_pkey     | addr_nsp.gentable_pkey
- view                      | addr_nsp   | genview           | addr_nsp.genview
- materialized view         | addr_nsp   | genmatview        | addr_nsp.genmatview
- foreign table column      | addr_nsp   | genftable         | addr_nsp.genftable.a
- foreign table             | addr_nsp   | genftable         | addr_nsp.genftable
- role                      |            | regtest_addr_user | regtest_addr_user
- server                    |            | addr_fserv        | addr_fserv
- foreign-data wrapper      |            | addr_fdw          | addr_fdw
- default value             |            |                   | for addr_nsp.gentable.b
- cast                      |            |                   | (bigint AS integer)
- table constraint          | addr_nsp   |                   | a_chk on addr_nsp.gentable
- domain constraint         | addr_nsp   |                   | domconstr on addr_nsp.gendomain
- conversion                | pg_catalog | ascii_to_mic      | ascii_to_mic
- language                  |            | plpgsql           | plpgsql
- schema                    |            | addr_nsp          | addr_nsp
- operator class            | pg_catalog | int4_ops          | pg_catalog.int4_ops for btree
- operator                  | pg_catalog |                   | pg_catalog.+(integer,integer)
- rule                      |            |                   | "_RETURN" on addr_nsp.genview
- trigger                   |            |                   | t on addr_nsp.gentable
- operator family           | pg_catalog | integer_ops       | pg_catalog.integer_ops for btree
- policy                    |            |                   | genpol on addr_nsp.gentable
- collation                 | pg_catalog | "default"         | pg_catalog."default"
- text search dictionary    | addr_nsp   | addr_ts_dict      | addr_nsp.addr_ts_dict
- text search parser        | addr_nsp   | addr_ts_prs       | addr_nsp.addr_ts_prs
- text search configuration | addr_nsp   | addr_ts_conf      | addr_nsp.addr_ts_conf
- text search template      | addr_nsp   | addr_ts_temp      | addr_nsp.addr_ts_temp
+SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*,
+       -- test roundtrip through pg_identify_object_as_address
+       ROW(pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)) =
+       ROW(pg_identify_object(addr2.classid, addr2.objid, addr2.subobjid))
+         FROM objects, pg_get_object_address(type, name, args) addr1,
+                       pg_identify_object_as_address(classid, objid, subobjid) ioa(typ,nms,args),
+                       pg_get_object_address(typ, nms, ioa.args) as addr2
+       ORDER BY addr1.classid, addr1.objid;
+           type            |   schema   |       name        |                               identity                               | ?column? 
+---------------------------+------------+-------------------+----------------------------------------------------------------------+----------
+ type                      | pg_catalog | _int4             | integer[]                                                            | t
+ type                      | addr_nsp   | gencomptype       | addr_nsp.gencomptype                                                 | t
+ type                      | addr_nsp   | genenum           | addr_nsp.genenum                                                     | t
+ type                      | addr_nsp   | gendomain         | addr_nsp.gendomain                                                   | t
+ function                  | pg_catalog |                   | pg_catalog.pg_identify_object(pg_catalog.oid,pg_catalog.oid,integer) | t
+ aggregate                 | addr_nsp   |                   | addr_nsp.genaggr(integer)                                            | t
+ sequence                  | addr_nsp   | gentable_a_seq    | addr_nsp.gentable_a_seq                                              | t
+ table                     | addr_nsp   | gentable          | addr_nsp.gentable                                                    | t
+ table column              | addr_nsp   | gentable          | addr_nsp.gentable.b                                                  | t
+ index                     | addr_nsp   | gentable_pkey     | addr_nsp.gentable_pkey                                               | t
+ view                      | addr_nsp   | genview           | addr_nsp.genview                                                     | t
+ materialized view         | addr_nsp   | genmatview        | addr_nsp.genmatview                                                  | t
+ foreign table column      | addr_nsp   | genftable         | addr_nsp.genftable.a                                                 | t
+ foreign table             | addr_nsp   | genftable         | addr_nsp.genftable                                                   | t
+ role                      |            | regtest_addr_user | regtest_addr_user                                                    | t
+ server                    |            | addr_fserv        | addr_fserv                                                           | t
+ foreign-data wrapper      |            | addr_fdw          | addr_fdw                                                             | t
+ default value             |            |                   | for addr_nsp.gentable.b                                              | t
+ cast                      |            |                   | (bigint AS integer)                                                  | t
+ table constraint          | addr_nsp   |                   | a_chk on addr_nsp.gentable                                           | t
+ domain constraint         | addr_nsp   |                   | domconstr on addr_nsp.gendomain                                      | t
+ conversion                | pg_catalog | ascii_to_mic      | ascii_to_mic                                                         | t
+ language                  |            | plpgsql           | plpgsql                                                              | t
+ schema                    |            | addr_nsp          | addr_nsp                                                             | t
+ operator class            | pg_catalog | int4_ops          | pg_catalog.int4_ops for btree                                        | t
+ operator                  | pg_catalog |                   | pg_catalog.+(integer,integer)                                        | t
+ rule                      |            |                   | "_RETURN" on addr_nsp.genview                                        | t
+ trigger                   |            |                   | t on addr_nsp.gentable                                               | t
+ operator family           | pg_catalog | integer_ops       | pg_catalog.integer_ops for btree                                     | t
+ policy                    |            |                   | genpol on addr_nsp.gentable                                          | t
+ collation                 | pg_catalog | "default"         | pg_catalog."default"                                                 | t
+ text search dictionary    | addr_nsp   | addr_ts_dict      | addr_nsp.addr_ts_dict                                                | t
+ text search parser        | addr_nsp   | addr_ts_prs       | addr_nsp.addr_ts_prs                                                 | t
+ text search configuration | addr_nsp   | addr_ts_conf      | addr_nsp.addr_ts_conf                                                | t
+ text search template      | addr_nsp   | addr_ts_temp      | addr_nsp.addr_ts_temp                                                | t
 (35 rows)
 
 ---
index dc55895d9325f7095049fa37b3ffdd2928c1a301..9fc27d8f6e61b6cd9ec9324d9bc75ef0fa353bcd 100644 (file)
@@ -159,9 +159,14 @@ WITH objects (type, name, args) AS (VALUES
                                -- event trigger
                                ('policy', '{addr_nsp, gentable, genpol}', '{}')
         )
-SELECT (pg_identify_object(classid, objid, subobjid)).*
-  FROM objects, pg_get_object_address(type, name, args)
-ORDER BY classid, objid;
+SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*,
+       -- test roundtrip through pg_identify_object_as_address
+       ROW(pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)) =
+       ROW(pg_identify_object(addr2.classid, addr2.objid, addr2.subobjid))
+         FROM objects, pg_get_object_address(type, name, args) addr1,
+                       pg_identify_object_as_address(classid, objid, subobjid) ioa(typ,nms,args),
+                       pg_get_object_address(typ, nms, ioa.args) as addr2
+       ORDER BY addr1.classid, addr1.objid;
 
 ---
 --- Cleanup resources