.. and here's the patch.
--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 67,72 ****
--- 67,73 ----
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "foreign/foreign.h"
+ #include "funcapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
***************
*** 198,203 **** static bool stack_address_present_add_flags(const ObjectAddress *object,
--- 199,210 ----
ObjectAddressStack *stack);
static void getRelationDescription(StringInfo buffer, Oid relid);
static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
+ static void getRelationTypeDescription(StringInfo buffer, Oid relid,
+ int32 objectSubId);
+ static void getProcedureTypeDescription(StringInfo buffer, Oid procid);
+ static void getConstraintTypeDescription(StringInfo buffer, Oid constroid);
+ static void getOpFamilyIdentity(StringInfo buffer, Oid opfid);
+ static void getRelationIdentity(StringInfo buffer, Oid relid);
/*
***************
*** 2193,2199 **** getObjectClass(const ObjectAddress *object)
/* only pg_class entries can have nonzero objectSubId */
if (object->classId != RelationRelationId &&
object->objectSubId != 0)
! elog(ERROR, "invalid objectSubId 0 for object class %u",
object->classId);
switch (object->classId)
--- 2200,2206 ----
/* only pg_class entries can have nonzero objectSubId */
if (object->classId != RelationRelationId &&
object->objectSubId != 0)
! elog(ERROR, "invalid non-zero objectSubId for object class %u",
object->classId);
switch (object->classId)
***************
*** 3087,3093 **** pg_describe_object(PG_FUNCTION_ARGS)
Oid classid = PG_GETARG_OID(0);
Oid objid = PG_GETARG_OID(1);
int32 subobjid = PG_GETARG_INT32(2);
! char *description = NULL;
ObjectAddress address;
/* for "pinned" items in pg_depend, return null */
--- 3094,3100 ----
Oid classid = PG_GETARG_OID(0);
Oid objid = PG_GETARG_OID(1);
int32 subobjid = PG_GETARG_INT32(2);
! char *description;
ObjectAddress address;
/* for "pinned" items in pg_depend, return null */
***************
*** 3101,3103 **** pg_describe_object(PG_FUNCTION_ARGS)
--- 3108,4145 ----
description = getObjectDescription(&address);
PG_RETURN_TEXT_P(cstring_to_text(description));
}
+
+ Datum
+ pg_identify_object(PG_FUNCTION_ARGS)
+ {
+ Oid classid = PG_GETARG_OID(0);
+ Oid objid = PG_GETARG_OID(1);
+ int32 subobjid = PG_GETARG_INT32(2);
+ Oid schema_oid = InvalidOid;
+ const char *objname = NULL;
+ ObjectAddress address;
+ Datum values[4];
+ bool nulls[4];
+ TupleDesc tupdesc;
+ HeapTuple htup;
+
+ address.classId = classid;
+ address.objectId = objid;
+ address.objectSubId = subobjid;
+
+ /*
+ * Construct a tuple descriptor for the result row. This must match this
+ * function's pg_proc entry!
+ */
+ tupdesc = CreateTemplateTupleDesc(4, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
+ TEXTOID, -1, 0);
+
+ tupdesc = BlessTupleDesc(tupdesc);
+
+ if (is_objectclass_supported(address.classId))
+ {
+ HeapTuple objtup;
+ Relation catalog = heap_open(address.classId, AccessShareLock);
+
+ objtup = get_catalog_object_by_oid(catalog, address.objectId);
+ if (objtup != NULL)
+ {
+ bool isnull;
+ AttrNumber nspAttnum;
+ AttrNumber nameAttnum;
+
+ nspAttnum = get_object_attnum_namespace(address.classId);
+ if (nspAttnum != InvalidAttrNumber)
+ {
+ schema_oid = heap_getattr(objtup, nspAttnum,
+ RelationGetDescr(catalog), &isnull);
+ if (isnull)
+ elog(ERROR, "invalid null namespace in object %u/%u/%d",
+ address.classId, address.objectId, address.objectSubId);
+ }
+
+ nameAttnum = get_object_attnum_name(address.classId);
+ if (nameAttnum != InvalidAttrNumber)
+ {
+ Datum nameDatum;
+
+ nameDatum = heap_getattr(objtup, nameAttnum,
+ RelationGetDescr(catalog), &isnull);
+ if (isnull)
+ elog(ERROR, "invalid null name in object %u/%u/%d",
+ address.classId, address.objectId, address.objectSubId);
+ objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
+ }
+ }
+
+ heap_close(catalog, AccessShareLock);
+ }
+
+ /* object type */
+ values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
+ nulls[0] = false;
+
+ /* schema name */
+ if (OidIsValid(schema_oid))
+ {
+ const char *schema = quote_identifier(get_namespace_name(schema_oid));
+
+ values[1] = CStringGetTextDatum(schema);
+ nulls[1] = false;
+ }
+ else
+ nulls[1] = true;
+
+ /* object name */
+ if (objname)
+ {
+ values[2] = CStringGetTextDatum(objname);
+ nulls[2] = false;
+ }
+ else
+ nulls[2] = true;
+
+ /* object identity */
+ values[3] = CStringGetTextDatum(getObjectIdentity(&address));
+ nulls[3] = false;
+
+ htup = heap_form_tuple(tupdesc, values, nulls);
+
+ PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+ }
+
+ /*
+ * Return a palloc'ed string that describes the type of object that the
+ * passed address is for.
+ */
+ char *
+ getObjectTypeDescription(const ObjectAddress *object)
+ {
+ StringInfoData buffer;
+
+ initStringInfo(&buffer);
+
+ switch (getObjectClass(object))
+ {
+ case OCLASS_CLASS:
+ getRelationTypeDescription(&buffer, object->objectId,
+ object->objectSubId);
+ break;
+
+ case OCLASS_PROC:
+ getProcedureTypeDescription(&buffer, object->objectId);
+ break;
+
+ case OCLASS_TYPE:
+ appendStringInfo(&buffer, "type");
+ break;
+
+ case OCLASS_CAST:
+ appendStringInfo(&buffer, "cast");
+ break;
+
+ case OCLASS_COLLATION:
+ appendStringInfo(&buffer, "collation");
+ break;
+
+ case OCLASS_CONSTRAINT:
+ getConstraintTypeDescription(&buffer, object->objectId);
+ break;
+
+ case OCLASS_CONVERSION:
+ appendStringInfo(&buffer, "conversion");
+ break;
+
+ case OCLASS_DEFAULT:
+ appendStringInfo(&buffer, "default value");
+ break;
+
+ case OCLASS_LANGUAGE:
+ appendStringInfo(&buffer, "language");
+ break;
+
+ case OCLASS_LARGEOBJECT:
+ appendStringInfo(&buffer, "large object");
+ break;
+
+ case OCLASS_OPERATOR:
+ appendStringInfo(&buffer, "operator");
+ break;
+
+ case OCLASS_OPCLASS:
+ appendStringInfo(&buffer, "operator class");
+ break;
+
+ case OCLASS_OPFAMILY:
+ appendStringInfo(&buffer, "operator family");
+ break;
+
+ case OCLASS_AMOP:
+ appendStringInfo(&buffer, "operator of access method");
+ break;
+
+ case OCLASS_AMPROC:
+ appendStringInfo(&buffer, "function of access method");
+ break;
+
+ case OCLASS_REWRITE:
+ appendStringInfo(&buffer, "rule");
+ break;
+
+ case OCLASS_TRIGGER:
+ appendStringInfo(&buffer, "trigger");
+ break;
+
+ case OCLASS_SCHEMA:
+ appendStringInfo(&buffer, "schema");
+ break;
+
+ case OCLASS_TSPARSER:
+ appendStringInfo(&buffer, "text search parser");
+ break;
+
+ case OCLASS_TSDICT:
+ appendStringInfo(&buffer, "text search dictionary");
+ break;
+
+ case OCLASS_TSTEMPLATE:
+ appendStringInfo(&buffer, "text search template");
+ break;
+
+ case OCLASS_TSCONFIG:
+ appendStringInfo(&buffer, "text search configuration");
+ break;
+
+ case OCLASS_ROLE:
+ appendStringInfo(&buffer, "role");
+ break;
+
+ case OCLASS_DATABASE:
+ appendStringInfo(&buffer, "database");
+ break;
+
+ case OCLASS_TBLSPACE:
+ appendStringInfo(&buffer, "tablespace");
+ break;
+
+ case OCLASS_FDW:
+ appendStringInfo(&buffer, "foreign-data wrapper");
+ break;
+
+ case OCLASS_FOREIGN_SERVER:
+ appendStringInfo(&buffer, "server");
+ break;
+
+ case OCLASS_USER_MAPPING:
+ appendStringInfo(&buffer, "user mapping");
+ break;
+
+ case OCLASS_DEFACL:
+ appendStringInfo(&buffer, "default acl");
+ break;
+
+ case OCLASS_EXTENSION:
+ appendStringInfo(&buffer, "extension");
+ break;
+
+ case OCLASS_EVENT_TRIGGER:
+ appendStringInfo(&buffer, "event trigger");
+ break;
+
+ default:
+ appendStringInfo(&buffer, "unrecognized %u", object->classId);
+ break;
+ }
+
+ return buffer.data;
+ }
+
+ /*
+ * subroutine for getObjectTypeDescription: describe a relation type
+ */
+ static void
+ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
+ {
+ HeapTuple relTup;
+ Form_pg_class relForm;
+
+ relTup = SearchSysCache1(RELOID,
+ ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(relTup))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+ switch (relForm->relkind)
+ {
+ case RELKIND_RELATION:
+ appendStringInfo(buffer, "table");
+ break;
+ case RELKIND_INDEX:
+ appendStringInfo(buffer, "index");
+ break;
+ case RELKIND_SEQUENCE:
+ appendStringInfo(buffer, "sequence");
+ break;
+ case RELKIND_TOASTVALUE:
+ appendStringInfo(buffer, "toast table");
+ break;
+ case RELKIND_VIEW:
+ appendStringInfo(buffer, "view");
+ break;
+ case RELKIND_MATVIEW:
+ appendStringInfo(buffer, "materialized view");
+ break;
+ case RELKIND_COMPOSITE_TYPE:
+ appendStringInfo(buffer, "composite type");
+ break;
+ case RELKIND_FOREIGN_TABLE:
+ appendStringInfo(buffer, "foreign table");
+ break;
+ default:
+ /* shouldn't get here */
+ appendStringInfo(buffer, "relation");
+ break;
+ }
+
+ if (objectSubId != 0)
+ appendStringInfo(buffer, " column");
+
+ ReleaseSysCache(relTup);
+ }
+
+ /*
+ * subroutine for getObjectTypeDescription: describe a constraint type
+ */
+ static void
+ getConstraintTypeDescription(StringInfo buffer, Oid constroid)
+ {
+ Relation constrRel;
+ HeapTuple constrTup;
+ Form_pg_constraint constrForm;
+
+ constrRel = heap_open(ConstraintRelationId, AccessShareLock);
+ constrTup = get_catalog_object_by_oid(constrRel, constroid);
+ if (!HeapTupleIsValid(constrTup))
+ elog(ERROR, "cache lookup failed for constraint %u", constroid);
+
+ constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
+
+ if (OidIsValid(constrForm->conrelid))
+ appendStringInfoString(buffer, "table constraint");
+ else if (OidIsValid(constrForm->contypid))
+ appendStringInfoString(buffer, "domain constraint");
+ else
+ elog(ERROR, "invalid constraint %u", HeapTupleGetOid(constrTup));
+
+ heap_close(constrRel, AccessShareLock);
+ }
+
+ /*
+ * subroutine for getObjectTypeDescription: describe a procedure type
+ */
+ static void
+ getProcedureTypeDescription(StringInfo buffer, Oid procid)
+ {
+ HeapTuple procTup;
+ Form_pg_proc procForm;
+
+ procTup = SearchSysCache1(PROCOID,
+ ObjectIdGetDatum(procid));
+ if (!HeapTupleIsValid(procTup))
+ elog(ERROR, "cache lookup failed for procedure %u", procid);
+ procForm = (Form_pg_proc) GETSTRUCT(procTup);
+
+ if (procForm->proisagg)
+ appendStringInfo(buffer, "aggregate");
+ else
+ appendStringInfo(buffer, "function");
+
+ ReleaseSysCache(procTup);
+ }
+
+ /*
+ * Return a palloc'ed string that identifies an object.
+ *
+ * This is for machine consumption, so it's not translated. All elements are
+ * schema-qualified when appropriate.
+ */
+ char *
+ getObjectIdentity(const ObjectAddress *object)
+ {
+ StringInfoData buffer;
+
+ initStringInfo(&buffer);
+
+ switch (getObjectClass(object))
+ {
+ case OCLASS_CLASS:
+ getRelationIdentity(&buffer, object->objectId);
+ if (object->objectSubId != 0)
+ {
+ char *attr;
+
+ attr = get_relid_attribute_name(object->objectId,
+ object->objectSubId);
+ appendStringInfo(&buffer, ".%s", quote_identifier(attr));
+ }
+ break;
+
+ case OCLASS_PROC:
+ appendStringInfo(&buffer, "%s",
+ format_procedure_qualified(object->objectId));
+ break;
+
+ case OCLASS_TYPE:
+ appendStringInfo(&buffer, "%s",
+ format_type_be_qualified(object->objectId));
+ break;
+
+ case OCLASS_CAST:
+ {
+ Relation castRel;
+ HeapTuple tup;
+ Form_pg_cast castForm;
+
+ castRel = heap_open(CastRelationId, AccessShareLock);
+
+ tup = get_catalog_object_by_oid(castRel, object->objectId);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for cast %u",
+ object->objectId);
+
+ castForm = (Form_pg_cast) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, "(%s AS %s)",
+ format_type_be_qualified(castForm->castsource),
+ format_type_be_qualified(castForm->casttarget));
+
+ heap_close(castRel, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_COLLATION:
+ {
+ HeapTuple collTup;
+ Form_pg_collation coll;
+ char *schema;
+
+ collTup = SearchSysCache1(COLLOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(collTup))
+ elog(ERROR, "cache lookup failed for collation %u",
+ object->objectId);
+ coll = (Form_pg_collation) GETSTRUCT(collTup);
+ schema = get_namespace_name(coll->collnamespace);
+ appendStringInfoString(&buffer,
+ quote_qualified_identifier(schema,
+ NameStr(coll->collname)));
+ ReleaseSysCache(collTup);
+ break;
+ }
+
+ case OCLASS_CONSTRAINT:
+ {
+ HeapTuple conTup;
+ Form_pg_constraint con;
+
+ conTup = SearchSysCache1(CONSTROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(conTup))
+ elog(ERROR, "cache lookup failed for constraint %u",
+ object->objectId);
+ con = (Form_pg_constraint) GETSTRUCT(conTup);
+
+ if (OidIsValid(con->conrelid))
+ {
+ appendStringInfo(&buffer, "%s on ",
+ quote_identifier(NameStr(con->conname)));
+ getRelationIdentity(&buffer, con->conrelid);
+ }
+ else
+ {
+ ObjectAddress domain;
+
+ domain.classId = TypeRelationId;
+ domain.objectId = con->contypid;
+ domain.objectSubId = 0;
+
+ appendStringInfo(&buffer, "%s on %s",
+ quote_identifier(NameStr(con->conname)),
+ getObjectIdentity(&domain));
+ }
+
+ ReleaseSysCache(conTup);
+ break;
+ }
+
+ case OCLASS_CONVERSION:
+ {
+ HeapTuple conTup;
+ Form_pg_conversion conForm;
+
+ conTup = SearchSysCache1(CONVOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(conTup))
+ elog(ERROR, "cache lookup failed for conversion %u",
+ object->objectId);
+ conForm = (Form_pg_conversion) GETSTRUCT(conTup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(conForm->conname)));
+ ReleaseSysCache(conTup);
+ break;
+ }
+
+ case OCLASS_DEFAULT:
+ {
+ Relation attrdefDesc;
+ ScanKeyData skey[1];
+ SysScanDesc adscan;
+
+ HeapTuple tup;
+ Form_pg_attrdef attrdef;
+ ObjectAddress colobject;
+
+ attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
+ true, SnapshotNow, 1, skey);
+
+ tup = systable_getnext(adscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for attrdef %u",
+ object->objectId);
+
+ attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
+
+ colobject.classId = RelationRelationId;
+ colobject.objectId = attrdef->adrelid;
+ colobject.objectSubId = attrdef->adnum;
+
+ appendStringInfo(&buffer, "for %s",
+ getObjectIdentity(&colobject));
+
+ systable_endscan(adscan);
+ heap_close(attrdefDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_LANGUAGE:
+ {
+ HeapTuple langTup;
+ Form_pg_language langForm;
+
+ langTup = SearchSysCache1(LANGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(langTup))
+ elog(ERROR, "cache lookup failed for language %u",
+ object->objectId);
+ langForm = (Form_pg_language) GETSTRUCT(langTup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(langForm->lanname)));
+ ReleaseSysCache(langTup);
+ break;
+ }
+ case OCLASS_LARGEOBJECT:
+ appendStringInfo(&buffer, "%u",
+ object->objectId);
+ break;
+
+ case OCLASS_OPERATOR:
+ appendStringInfo(&buffer, "%s",
+ format_operator_qualified(object->objectId));
+ break;
+
+ case OCLASS_OPCLASS:
+ {
+ HeapTuple opcTup;
+ Form_pg_opclass opcForm;
+ HeapTuple amTup;
+ Form_pg_am amForm;
+ char *schema;
+
+ opcTup = SearchSysCache1(CLAOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(opcTup))
+ elog(ERROR, "cache lookup failed for opclass %u",
+ object->objectId);
+ opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
+ schema = get_namespace_name(opcForm->opcnamespace);
+
+ amTup = SearchSysCache1(AMOID,
+ ObjectIdGetDatum(opcForm->opcmethod));
+ if (!HeapTupleIsValid(amTup))
+ elog(ERROR, "cache lookup failed for access method %u",
+ opcForm->opcmethod);
+ amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+ appendStringInfo(&buffer,
+ "%s",
+ quote_qualified_identifier(schema,
+ NameStr(opcForm->opcname)));
+ appendStringInfo(&buffer, " for %s",
+ quote_identifier(NameStr(amForm->amname)));
+
+ ReleaseSysCache(amTup);
+ ReleaseSysCache(opcTup);
+ break;
+ }
+
+ case OCLASS_OPFAMILY:
+ getOpFamilyIdentity(&buffer, object->objectId);
+ break;
+
+ case OCLASS_AMOP:
+ {
+ Relation amopDesc;
+ HeapTuple tup;
+ Form_pg_amop amopForm;
+ StringInfoData opfam;
+
+ amopDesc = heap_open(AccessMethodOperatorRelationId,
+ AccessShareLock);
+
+ tup = get_catalog_object_by_oid(amopDesc, object->objectId);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for amop entry %u",
+ object->objectId);
+
+ amopForm = (Form_pg_amop) GETSTRUCT(tup);
+
+ initStringInfo(&opfam);
+ getOpFamilyIdentity(&opfam, amopForm->amopfamily);
+
+ /* XXX is this too verbose? */
+ appendStringInfo(&buffer, "%d (%s, %s) of %s: %s",
+ amopForm->amopstrategy,
+ format_type_be_qualified(amopForm->amoplefttype),
+ format_type_be_qualified(amopForm->amoprighttype),
+ opfam.data,
+ format_operator_qualified(amopForm->amopopr));
+
+ pfree(opfam.data);
+
+ heap_close(amopDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_AMPROC:
+ {
+ Relation amprocDesc;
+ HeapTuple tup;
+ Form_pg_amproc amprocForm;
+ StringInfoData opfam;
+
+ amprocDesc = heap_open(AccessMethodProcedureRelationId,
+ AccessShareLock);
+
+ tup = get_catalog_object_by_oid(amprocDesc, object->objectId);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for amproc entry %u",
+ object->objectId);
+
+ amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
+
+ initStringInfo(&opfam);
+ getOpFamilyIdentity(&opfam, amprocForm->amprocfamily);
+
+ /* XXX is this too verbose? */
+ appendStringInfo(&buffer, "%d (%s, %s) of %s: %s",
+ amprocForm->amprocnum,
+ format_type_be_qualified(amprocForm->amproclefttype),
+ format_type_be_qualified(amprocForm->amprocrighttype),
+ opfam.data,
+ format_procedure_qualified(amprocForm->amproc));
+
+ pfree(opfam.data);
+
+ heap_close(amprocDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_REWRITE:
+ {
+ Relation ruleDesc;
+ HeapTuple tup;
+ Form_pg_rewrite rule;
+
+ ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
+
+ tup = get_catalog_object_by_oid(ruleDesc, object->objectId);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for rule %u",
+ object->objectId);
+
+ rule = (Form_pg_rewrite) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, "%s on ",
+ quote_identifier(NameStr(rule->rulename)));
+ getRelationIdentity(&buffer, rule->ev_class);
+
+ heap_close(ruleDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_TRIGGER:
+ {
+ Relation trigDesc;
+ HeapTuple tup;
+ Form_pg_trigger trig;
+
+ trigDesc = heap_open(TriggerRelationId, AccessShareLock);
+
+ tup = get_catalog_object_by_oid(trigDesc, object->objectId);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for trigger %u",
+ object->objectId);
+
+ trig = (Form_pg_trigger) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, "%s on ",
+ quote_identifier(NameStr(trig->tgname)));
+ getRelationIdentity(&buffer, trig->tgrelid);
+
+ heap_close(trigDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_SCHEMA:
+ {
+ char *nspname;
+
+ nspname = get_namespace_name(object->objectId);
+ if (!nspname)
+ elog(ERROR, "cache lookup failed for namespace %u",
+ object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(nspname));
+ break;
+ }
+
+ case OCLASS_TSPARSER:
+ {
+ HeapTuple tup;
+ Form_pg_ts_parser formParser;
+
+ tup = SearchSysCache1(TSPARSEROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search parser %u",
+ object->objectId);
+ formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(formParser->prsname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSDICT:
+ {
+ HeapTuple tup;
+ Form_pg_ts_dict formDict;
+
+ tup = SearchSysCache1(TSDICTOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search dictionary %u",
+ object->objectId);
+ formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(formDict->dictname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSTEMPLATE:
+ {
+ HeapTuple tup;
+ Form_pg_ts_template formTmpl;
+
+ tup = SearchSysCache1(TSTEMPLATEOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search template %u",
+ object->objectId);
+ formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(formTmpl->tmplname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSCONFIG:
+ {
+ HeapTuple tup;
+ Form_pg_ts_config formCfg;
+
+ tup = SearchSysCache1(TSCONFIGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search configuration %u",
+ object->objectId);
+ formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(formCfg->cfgname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_ROLE:
+ {
+ char *username;
+
+ username = GetUserNameFromId(object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(username));
+ break;
+ }
+
+ case OCLASS_DATABASE:
+ {
+ char *datname;
+
+ datname = get_database_name(object->objectId);
+ if (!datname)
+ elog(ERROR, "cache lookup failed for database %u",
+ object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(datname));
+ break;
+ }
+
+ case OCLASS_TBLSPACE:
+ {
+ char *tblspace;
+
+ tblspace = get_tablespace_name(object->objectId);
+ if (!tblspace)
+ elog(ERROR, "cache lookup failed for tablespace %u",
+ object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(tblspace));
+ break;
+ }
+
+ case OCLASS_FDW:
+ {
+ ForeignDataWrapper *fdw;
+
+ fdw = GetForeignDataWrapper(object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(fdw->fdwname));
+ break;
+ }
+
+ case OCLASS_FOREIGN_SERVER:
+ {
+ ForeignServer *srv;
+
+ srv = GetForeignServer(object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(srv->servername));
+ break;
+ }
+
+ case OCLASS_USER_MAPPING:
+ {
+ HeapTuple tup;
+ Oid useid;
+ const char *usename;
+
+ tup = SearchSysCache1(USERMAPPINGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for user mapping %u",
+ object->objectId);
+
+ useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
+
+ ReleaseSysCache(tup);
+
+ if (OidIsValid(useid))
+ usename = quote_identifier(GetUserNameFromId(useid));
+ else
+ usename = "public";
+
+ appendStringInfo(&buffer, "%s", usename);
+ break;
+ }
+
+ case OCLASS_DEFACL:
+ {
+ Relation defaclrel;
+ ScanKeyData skey[1];
+ SysScanDesc rcscan;
+
+ HeapTuple tup;
+ Form_pg_default_acl defacl;
+
+ defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
+ true, SnapshotNow, 1, skey);
+
+ tup = systable_getnext(rcscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for default ACL %u",
+ object->objectId);
+
+ defacl = (Form_pg_default_acl) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer,
+ "for role %s",
+ quote_identifier(GetUserNameFromId(defacl->defaclrole)));
+
+ if (OidIsValid(defacl->defaclnamespace))
+ {
+ char *schema;
+
+ schema = get_namespace_name(defacl->defaclnamespace);
+ appendStringInfo(&buffer,
+ " in schema %s",
+ quote_identifier(schema));
+ }
+
+ switch (defacl->defaclobjtype)
+ {
+ case DEFACLOBJ_RELATION:
+ appendStringInfoString(&buffer,
+ " on tables");
+ break;
+ case DEFACLOBJ_SEQUENCE:
+ appendStringInfoString(&buffer,
+ " on sequences");
+ break;
+ case DEFACLOBJ_FUNCTION:
+ appendStringInfoString(&buffer,
+ " on functions");
+ break;
+ case DEFACLOBJ_TYPE:
+ appendStringInfoString(&buffer,
+ " on types");
+ break;
+ }
+
+ systable_endscan(rcscan);
+ heap_close(defaclrel, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_EXTENSION:
+ {
+ char *extname;
+
+ extname = get_extension_name(object->objectId);
+ if (!extname)
+ elog(ERROR, "cache lookup failed for extension %u",
+ object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(extname));
+ break;
+ }
+
+ case OCLASS_EVENT_TRIGGER:
+ {
+ HeapTuple tup;
+ Form_pg_event_trigger trigForm;
+
+ tup = SearchSysCache1(EVENTTRIGGEROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for event trigger %u",
+ object->objectId);
+ trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(trigForm->evtname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ default:
+ appendStringInfo(&buffer, "unrecognized object %u %u %d",
+ object->classId,
+ object->objectId,
+ object->objectSubId);
+ break;
+ }
+
+ return buffer.data;
+ }
+
+ static void
+ getOpFamilyIdentity(StringInfo buffer, Oid opfid)
+ {
+ HeapTuple opfTup;
+ Form_pg_opfamily opfForm;
+ HeapTuple amTup;
+ Form_pg_am amForm;
+ char *schema;
+
+ opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
+ if (!HeapTupleIsValid(opfTup))
+ elog(ERROR, "cache lookup failed for opfamily %u", opfid);
+ opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
+
+ amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
+ if (!HeapTupleIsValid(amTup))
+ elog(ERROR, "cache lookup failed for access method %u",
+ opfForm->opfmethod);
+ amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+ schema = get_namespace_name(opfForm->opfnamespace);
+ appendStringInfo(buffer, "%s for %s",
+ quote_qualified_identifier(schema,
+ NameStr(opfForm->opfname)),
+ NameStr(amForm->amname));
+
+ ReleaseSysCache(amTup);
+ ReleaseSysCache(opfTup);
+ }
+
+ /*
+ * Append the relation identity (quoted qualified name) to the given
+ * StringInfo.
+ */
+ static void
+ getRelationIdentity(StringInfo buffer, Oid relid)
+ {
+ HeapTuple relTup;
+ Form_pg_class relForm;
+ char *schema;
+
+ relTup = SearchSysCache1(RELOID,
+ ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(relTup))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+ schema = get_namespace_name(relForm->relnamespace);
+ appendStringInfo(buffer, "%s",
+ quote_qualified_identifier(schema,
+ NameStr(relForm->relname)));
+
+ ReleaseSysCache(relTup);
+ }
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 1345,1350 **** get_object_aclkind(Oid class_id)
--- 1345,1368 ----
}
/*
+ * Return whether we have useful data for the given object class in the
+ * ObjectProperty table.
+ */
+ bool
+ is_objectclass_supported(Oid class_id)
+ {
+ int index;
+
+ for (index = 0; index < lengthof(ObjectProperty); index++)
+ {
+ if (ObjectProperty[index].class_oid == class_id)
+ return true;
+ }
+
+ return false;
+ }
+
+ /*
* Find ObjectProperty structure by class_id.
*/
static ObjectPropertyType *
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 753,810 **** 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
* change the ownership column of a single catalog entry).
--- 753,758 ----
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 5195,5214 **** 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> |
* AGGREGATE <aggname> (arg1, ...) |
* FUNCTION <funcname> (arg1, arg2, ...) |
* OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
* TRIGGER <triggername> ON <relname> |
- * CONSTRAINT <constraintname> ON <relname> |
- * RULE <rulename> ON <relname> ]
* IS 'text'
*
*****************************************************************************/
--- 5195,5219 ----
* 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 [ [ 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) |
+ * OPERATOR CLASS <name> USING <access-method> |
+ * OPERATOR FAMILY <name> USING <access-method> |
+ * RULE <rulename> ON <relname> |
* TRIGGER <triggername> ON <relname> |
* IS 'text'
*
*****************************************************************************/
*** a/src/backend/utils/adt/format_type.c
--- b/src/backend/utils/adt/format_type.c
***************
*** 29,35 ****
#define MAX_INT32_LEN 11
static char *format_type_internal(Oid type_oid, int32 typemod,
! bool typemod_given, bool allow_invalid);
static char *printTypmod(const char *typname, int32 typmod, Oid typmodout);
static char *
psnprintf(size_t len, const char *fmt,...)
--- 29,36 ----
#define MAX_INT32_LEN 11
static char *format_type_internal(Oid type_oid, int32 typemod,
! 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,87 **** format_type(PG_FUNCTION_ARGS)
type_oid = PG_GETARG_OID(0);
if (PG_ARGISNULL(1))
! result = format_type_internal(type_oid, -1, false, true);
else
{
typemod = PG_GETARG_INT32(1);
! result = format_type_internal(type_oid, typemod, true, true);
}
PG_RETURN_TEXT_P(cstring_to_text(result));
--- 78,88 ----
type_oid = PG_GETARG_OID(0);
if (PG_ARGISNULL(1))
! 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, false);
}
PG_RETURN_TEXT_P(cstring_to_text(result));
***************
*** 96,102 **** format_type(PG_FUNCTION_ARGS)
char *
format_type_be(Oid type_oid)
{
! return format_type_internal(type_oid, -1, false, false);
}
/*
--- 97,109 ----
char *
format_type_be(Oid type_oid)
{
! 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,118 **** 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);
}
-
-
static char *
format_type_internal(Oid type_oid, int32 typemod,
! bool typemod_given, bool allow_invalid)
{
bool with_typemod = typemod_given && (typemod >= 0);
HeapTuple tuple;
--- 112,124 ----
char *
format_type_with_typemod(Oid type_oid, int32 typemod)
{
! 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 force_qualify)
{
bool with_typemod = typemod_given && (typemod >= 0);
HeapTuple tuple;
***************
*** 300,306 **** format_type_internal(Oid type_oid, int32 typemod,
char *nspname;
char *typname;
! if (TypeIsVisible(type_oid))
nspname = NULL;
else
nspname = get_namespace_name(typeform->typnamespace);
--- 306,312 ----
char *nspname;
char *typname;
! if (!force_qualify && TypeIsVisible(type_oid))
nspname = NULL;
else
nspname = get_namespace_name(typeform->typnamespace);
***************
*** 421,427 **** oidvectortypes(PG_FUNCTION_ARGS)
for (num = 0; num < numargs; num++)
{
char *typename = format_type_internal(oidArray->values[num], -1,
! false, true);
size_t slen = strlen(typename);
if (left < (slen + 2))
--- 427,433 ----
for (num = 0; num < numargs; num++)
{
char *typename = format_type_internal(oidArray->values[num], -1,
! false, true, false);
size_t slen = strlen(typename);
if (left < (slen + 2))
*** a/src/backend/utils/adt/regproc.c
--- b/src/backend/utils/adt/regproc.c
***************
*** 41,46 ****
--- 41,48 ----
#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);
***************
*** 304,309 **** regprocedurein(PG_FUNCTION_ARGS)
--- 306,330 ----
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,332 **** 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))
nspname = NULL;
else
nspname = get_namespace_name(procform->pronamespace);
--- 347,353 ----
* Would this proc be found (given the right args) by regprocedurein?
* If not, we need to qualify it.
*/
! if (!force_qualify && FunctionIsVisible(procedure_oid))
nspname = NULL;
else
nspname = get_namespace_name(procform->pronamespace);
***************
*** 339,345 **** format_procedure(Oid procedure_oid)
if (i > 0)
appendStringInfoChar(&buf, ',');
! appendStringInfoString(&buf, format_type_be(thisargtype));
}
appendStringInfoChar(&buf, ')');
--- 360,369 ----
if (i > 0)
appendStringInfoChar(&buf, ',');
! appendStringInfoString(&buf,
! force_qualify ?
! format_type_be_qualified(thisargtype) :
! format_type_be(thisargtype));
}
appendStringInfoChar(&buf, ')');
***************
*** 653,660 **** 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)
{
char *result;
HeapTuple opertup;
--- 677,684 ----
* This exports the useful functionality of regoperatorout for use
* in other backend modules. The result is a palloc'd string.
*/
! static char *
! format_operator_internal(Oid operator_oid, bool force_qualify)
{
char *result;
HeapTuple opertup;
***************
*** 674,682 **** format_operator(Oid operator_oid)
/*
* Would this oper be found (given the right args) by regoperatorin?
! * If not, we need to qualify it.
*/
! if (!OperatorIsVisible(operator_oid))
{
nspname = get_namespace_name(operform->oprnamespace);
appendStringInfo(&buf, "%s.",
--- 698,706 ----
/*
* Would this oper be found (given the right args) by regoperatorin?
! * If not, or if caller explicitely requests it, we need to qualify it.
*/
! if (force_qualify || !OperatorIsVisible(operator_oid))
{
nspname = get_namespace_name(operform->oprnamespace);
appendStringInfo(&buf, "%s.",
***************
*** 687,698 **** format_operator(Oid operator_oid)
--- 711,726 ----
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,718 **** format_operator(Oid operator_oid)
--- 741,758 ----
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)"
*/
*** a/src/backend/utils/cache/lsyscache.c
--- b/src/backend/utils/cache/lsyscache.c
***************
*** 18,23 ****
--- 18,24 ----
#include "access/hash.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
+ #include "access/sysattr.h"
#include "bootstrap/bootstrap.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
***************
*** 40,45 ****
--- 41,47 ----
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
+ #include "utils/tqual.h"
#include "utils/typcache.h"
/* Hook for plugins to get control in get_attavgwidth() */
***************
*** 2926,2928 **** get_range_subtype(Oid rangeOid)
--- 2928,2981 ----
else
return InvalidOid;
}
+
+ /* ------------- GENERIC -------------- */
+
+ /*
+ * Return a copy of the tuple for the object with the given object OID, from
+ * the given catalog (which must have been opened by the caller and suitably
+ * locked). NULL is returned if the OID is not found.
+ *
+ * We try a syscache first, if available.
+ */
+ HeapTuple
+ get_catalog_object_by_oid(Relation catalog, Oid objectId)
+ {
+ HeapTuple tuple;
+ Oid classId = RelationGetRelid(catalog);
+ int oidCacheId = get_object_catcache_oid(classId);
+
+ if (oidCacheId > 0)
+ {
+ tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
+ if (!HeapTupleIsValid(tuple)) /* should not happen */
+ return NULL;
+ }
+ else
+ {
+ Oid oidIndexId = get_object_oid_index(classId);
+ SysScanDesc scan;
+ ScanKeyData skey;
+
+ Assert(OidIsValid(oidIndexId));
+
+ ScanKeyInit(&skey,
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(objectId));
+
+ scan = systable_beginscan(catalog, oidIndexId, true,
+ SnapshotNow, 1, &skey);
+ tuple = systable_getnext(scan);
+ if (!HeapTupleIsValid(tuple))
+ {
+ systable_endscan(scan);
+ return NULL;
+ }
+ tuple = heap_copytuple(tuple);
+
+ systable_endscan(scan);
+ }
+
+ return tuple;
+ }
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 179,184 **** extern ObjectClass getObjectClass(const ObjectAddress *object);
--- 179,187 ----
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);
+
extern ObjectAddresses *new_object_addresses(void);
extern void add_exact_object_address(const ObjectAddress *object,
*** a/src/include/catalog/objectaddress.h
--- b/src/include/catalog/objectaddress.h
***************
*** 38,43 **** extern void check_object_ownership(Oid roleid,
--- 38,44 ----
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);
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 2917,2922 **** DESCR("view members of a multixactid");
--- 2917,2925 ----
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_ ));
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
***************
*** 615,621 **** extern Datum regdictionarysend(PG_FUNCTION_ARGS);
--- 615,623 ----
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,1032 **** extern Datum pg_encoding_max_length_sql(PG_FUNCTION_ARGS);
--- 1029,1035 ----
/* 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,1148 **** extern Datum pg_get_multixact_members(PG_FUNCTION_ARGS);
--- 1146,1152 ----
/* 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);
*** a/src/include/utils/lsyscache.h
--- b/src/include/utils/lsyscache.h
***************
*** 16,21 ****
--- 16,22 ----
#include "access/attnum.h"
#include "access/htup.h"
#include "nodes/pg_list.h"
+ #include "utils/relcache.h"
/* Result list element for get_op_btree_interpretation */
typedef struct OpBtreeInterpretation
***************
*** 152,157 **** extern void free_attstatsslot(Oid atttype,
--- 153,159 ----
float4 *numbers, int nnumbers);
extern char *get_namespace_name(Oid nspid);
extern Oid get_range_subtype(Oid rangeOid);
+ extern HeapTuple get_catalog_object_by_oid(Relation catalog, Oid objectId);
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
/* type_is_array_domain accepts both plain arrays and domains over arrays */
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers