Commit f8348ea3 authored by Alvaro Herrera's avatar Alvaro Herrera

Allow extracting machine-readable object identity

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.
parent a7921f71
......@@ -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
......
This diff is collapsed.
This diff is collapsed.
......@@ -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
......
......@@ -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:
......
......@@ -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))
......
......@@ -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)"
*/
......
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201303141
#define CATALOG_VERSION_NO 201303201
#endif
......@@ -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,
......
......@@ -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 */
......@@ -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_ ));
......
......@@ -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);
......
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