Commit a6762014 authored by Alvaro Herrera's avatar Alvaro Herrera

Add pg_identify_object_as_address

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.
parent 5b447ad3
...@@ -15307,14 +15307,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); ...@@ -15307,14 +15307,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<primary>format_type</primary> <primary>format_type</primary>
</indexterm> </indexterm>
<indexterm>
<primary>pg_describe_object</primary>
</indexterm>
<indexterm>
<primary>pg_identify_object</primary>
</indexterm>
<indexterm> <indexterm>
<primary>pg_get_constraintdef</primary> <primary>pg_get_constraintdef</primary>
</indexterm> </indexterm>
...@@ -15429,16 +15421,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); ...@@ -15429,16 +15421,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>get SQL name of a data type</entry> <entry>get SQL name of a data type</entry>
</row> </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> <row>
<entry><literal><function>pg_get_constraintdef(<parameter>constraint_oid</parameter>)</function></literal></entry> <entry><literal><function>pg_get_constraintdef(<parameter>constraint_oid</parameter>)</function></literal></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
...@@ -15707,31 +15689,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); ...@@ -15707,31 +15689,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<structname>pg_class</> catalogs. <structname>pg_class</> catalogs.
</para> </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> <para>
<function>pg_typeof</function> returns the OID of the data type of the <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 value that is passed to it. This can be helpful for troubleshooting or
...@@ -15790,6 +15747,112 @@ SELECT collation for ('foo' COLLATE "de_DE"); ...@@ -15790,6 +15747,112 @@ SELECT collation for ('foo' COLLATE "de_DE");
the given name matches multiple objects). the given name matches multiple objects).
</para> </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> <indexterm>
<primary>col_description</primary> <primary>col_description</primary>
</indexterm> </indexterm>
......
This diff is collapsed.
...@@ -438,6 +438,41 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify) ...@@ -438,6 +438,41 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify)
return result; 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)" * regprocedureout - converts proc OID to "pro_name(args)"
*/ */
...@@ -875,6 +910,31 @@ format_operator_qualified(Oid operator_oid) ...@@ -875,6 +910,31 @@ format_operator_qualified(Oid operator_oid)
return format_operator_internal(operator_oid, true); 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)" * regoperatorout - converts operator OID to "opr_name(args)"
*/ */
......
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201412234 #define CATALOG_VERSION_NO 201412301
#endif #endif
...@@ -58,5 +58,8 @@ extern char *getObjectDescriptionOids(Oid classid, Oid objid); ...@@ -58,5 +58,8 @@ extern char *getObjectDescriptionOids(Oid classid, Oid objid);
extern int read_objtype_from_string(const char *objtype); extern int read_objtype_from_string(const char *objtype);
extern char *getObjectTypeDescription(const ObjectAddress *object); extern char *getObjectTypeDescription(const ObjectAddress *object);
extern char *getObjectIdentity(const ObjectAddress *address); 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 */ #endif /* OBJECTADDRESS_H */
...@@ -3036,6 +3036,9 @@ DESCR("get identification of SQL object"); ...@@ -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_ )); 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"); 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_ )); 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"); DESCR("get OID-based object address from name/args arrays");
......
...@@ -642,8 +642,12 @@ extern Datum text_regclass(PG_FUNCTION_ARGS); ...@@ -642,8 +642,12 @@ extern Datum text_regclass(PG_FUNCTION_ARGS);
extern List *stringToQualifiedNameList(const char *string); extern List *stringToQualifiedNameList(const char *string);
extern char *format_procedure(Oid procedure_oid); extern char *format_procedure(Oid procedure_oid);
extern char *format_procedure_qualified(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(Oid operator_oid);
extern char *format_operator_qualified(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 */ /* rowtypes.c */
extern Datum record_in(PG_FUNCTION_ARGS); extern Datum record_in(PG_FUNCTION_ARGS);
...@@ -1194,6 +1198,7 @@ extern Datum pg_last_committed_xact(PG_FUNCTION_ARGS); ...@@ -1194,6 +1198,7 @@ extern Datum pg_last_committed_xact(PG_FUNCTION_ARGS);
/* catalogs/dependency.c */ /* catalogs/dependency.c */
extern Datum pg_describe_object(PG_FUNCTION_ARGS); extern Datum pg_describe_object(PG_FUNCTION_ARGS);
extern Datum pg_identify_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 */ /* catalog/objectaddress.c */
extern Datum pg_get_object_address(PG_FUNCTION_ARGS); extern Datum pg_get_object_address(PG_FUNCTION_ARGS);
......
...@@ -339,46 +339,51 @@ WITH objects (type, name, args) AS (VALUES ...@@ -339,46 +339,51 @@ WITH objects (type, name, args) AS (VALUES
-- event trigger -- event trigger
('policy', '{addr_nsp, gentable, genpol}', '{}') ('policy', '{addr_nsp, gentable, genpol}', '{}')
) )
SELECT (pg_identify_object(classid, objid, subobjid)).* SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*,
FROM objects, pg_get_object_address(type, name, args) -- test roundtrip through pg_identify_object_as_address
ORDER BY classid, objid; ROW(pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)) =
type | schema | name | identity ROW(pg_identify_object(addr2.classid, addr2.objid, addr2.subobjid))
---------------------------+------------+-------------------+---------------------------------------------------------------------- FROM objects, pg_get_object_address(type, name, args) addr1,
type | pg_catalog | _int4 | integer[] pg_identify_object_as_address(classid, objid, subobjid) ioa(typ,nms,args),
type | addr_nsp | gencomptype | addr_nsp.gencomptype pg_get_object_address(typ, nms, ioa.args) as addr2
type | addr_nsp | genenum | addr_nsp.genenum ORDER BY addr1.classid, addr1.objid;
type | addr_nsp | gendomain | addr_nsp.gendomain type | schema | name | identity | ?column?
function | pg_catalog | | pg_catalog.pg_identify_object(pg_catalog.oid,pg_catalog.oid,integer) ---------------------------+------------+-------------------+----------------------------------------------------------------------+----------
aggregate | addr_nsp | | addr_nsp.genaggr(integer) type | pg_catalog | _int4 | integer[] | t
sequence | addr_nsp | gentable_a_seq | addr_nsp.gentable_a_seq type | addr_nsp | gencomptype | addr_nsp.gencomptype | t
table | addr_nsp | gentable | addr_nsp.gentable type | addr_nsp | genenum | addr_nsp.genenum | t
table column | addr_nsp | gentable | addr_nsp.gentable.b type | addr_nsp | gendomain | addr_nsp.gendomain | t
index | addr_nsp | gentable_pkey | addr_nsp.gentable_pkey function | pg_catalog | | pg_catalog.pg_identify_object(pg_catalog.oid,pg_catalog.oid,integer) | t
view | addr_nsp | genview | addr_nsp.genview aggregate | addr_nsp | | addr_nsp.genaggr(integer) | t
materialized view | addr_nsp | genmatview | addr_nsp.genmatview sequence | addr_nsp | gentable_a_seq | addr_nsp.gentable_a_seq | t
foreign table column | addr_nsp | genftable | addr_nsp.genftable.a table | addr_nsp | gentable | addr_nsp.gentable | t
foreign table | addr_nsp | genftable | addr_nsp.genftable table column | addr_nsp | gentable | addr_nsp.gentable.b | t
role | | regtest_addr_user | regtest_addr_user index | addr_nsp | gentable_pkey | addr_nsp.gentable_pkey | t
server | | addr_fserv | addr_fserv view | addr_nsp | genview | addr_nsp.genview | t
foreign-data wrapper | | addr_fdw | addr_fdw materialized view | addr_nsp | genmatview | addr_nsp.genmatview | t
default value | | | for addr_nsp.gentable.b foreign table column | addr_nsp | genftable | addr_nsp.genftable.a | t
cast | | | (bigint AS integer) foreign table | addr_nsp | genftable | addr_nsp.genftable | t
table constraint | addr_nsp | | a_chk on addr_nsp.gentable role | | regtest_addr_user | regtest_addr_user | t
domain constraint | addr_nsp | | domconstr on addr_nsp.gendomain server | | addr_fserv | addr_fserv | t
conversion | pg_catalog | ascii_to_mic | ascii_to_mic foreign-data wrapper | | addr_fdw | addr_fdw | t
language | | plpgsql | plpgsql default value | | | for addr_nsp.gentable.b | t
schema | | addr_nsp | addr_nsp cast | | | (bigint AS integer) | t
operator class | pg_catalog | int4_ops | pg_catalog.int4_ops for btree table constraint | addr_nsp | | a_chk on addr_nsp.gentable | t
operator | pg_catalog | | pg_catalog.+(integer,integer) domain constraint | addr_nsp | | domconstr on addr_nsp.gendomain | t
rule | | | "_RETURN" on addr_nsp.genview conversion | pg_catalog | ascii_to_mic | ascii_to_mic | t
trigger | | | t on addr_nsp.gentable language | | plpgsql | plpgsql | t
operator family | pg_catalog | integer_ops | pg_catalog.integer_ops for btree schema | | addr_nsp | addr_nsp | t
policy | | | genpol on addr_nsp.gentable operator class | pg_catalog | int4_ops | pg_catalog.int4_ops for btree | t
collation | pg_catalog | "default" | pg_catalog."default" operator | pg_catalog | | pg_catalog.+(integer,integer) | t
text search dictionary | addr_nsp | addr_ts_dict | addr_nsp.addr_ts_dict rule | | | "_RETURN" on addr_nsp.genview | t
text search parser | addr_nsp | addr_ts_prs | addr_nsp.addr_ts_prs trigger | | | t on addr_nsp.gentable | t
text search configuration | addr_nsp | addr_ts_conf | addr_nsp.addr_ts_conf operator family | pg_catalog | integer_ops | pg_catalog.integer_ops for btree | t
text search template | addr_nsp | addr_ts_temp | addr_nsp.addr_ts_temp 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) (35 rows)
--- ---
......
...@@ -159,9 +159,14 @@ WITH objects (type, name, args) AS (VALUES ...@@ -159,9 +159,14 @@ WITH objects (type, name, args) AS (VALUES
-- event trigger -- event trigger
('policy', '{addr_nsp, gentable, genpol}', '{}') ('policy', '{addr_nsp, gentable, genpol}', '{}')
) )
SELECT (pg_identify_object(classid, objid, subobjid)).* SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*,
FROM objects, pg_get_object_address(type, name, args) -- test roundtrip through pg_identify_object_as_address
ORDER BY classid, objid; 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 --- Cleanup resources
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment