#include "postgres.h"
#include "access/htup_details.h"
-#include "access/sysattr.h"
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
-#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_type.h"
#include "catalog/pg_user_mapping.h"
#include "commands/comment.h"
-#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
#include "commands/seclabel.h"
-#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
-#include "foreign/foreign.h"
-#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteRemove.h"
#include "storage/lmgr.h"
-#include "utils/acl.h"
-#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
static bool stack_address_present_add_flags(const ObjectAddress *object,
int flags,
ObjectAddressStack *stack);
-static void getRelationDescription(StringInfo buffer, Oid relid);
-static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
/*
/* only pg_class entries can have nonzero objectSubId */
if (object->classId != RelationRelationId &&
object->objectSubId != 0)
- elog(ERROR, "invalid objectSubId 0 for object class %u",
+ elog(ERROR, "invalid non-zero objectSubId for object class %u",
object->classId);
switch (object->classId)
elog(ERROR, "unrecognized object class: %u", object->classId);
return OCLASS_CLASS; /* keep compiler quiet */
}
-
-/*
- * getObjectDescription: build an object description for messages
- *
- * The result is a palloc'd string.
- */
-char *
-getObjectDescription(const ObjectAddress *object)
-{
- StringInfoData buffer;
-
- initStringInfo(&buffer);
-
- switch (getObjectClass(object))
- {
- case OCLASS_CLASS:
- getRelationDescription(&buffer, object->objectId);
- if (object->objectSubId != 0)
- appendStringInfo(&buffer, _(" column %s"),
- get_relid_attribute_name(object->objectId,
- object->objectSubId));
- break;
-
- case OCLASS_PROC:
- appendStringInfo(&buffer, _("function %s"),
- format_procedure(object->objectId));
- break;
-
- case OCLASS_TYPE:
- appendStringInfo(&buffer, _("type %s"),
- format_type_be(object->objectId));
- break;
-
- case OCLASS_CAST:
- {
- Relation castDesc;
- ScanKeyData skey[1];
- SysScanDesc rcscan;
- HeapTuple tup;
- Form_pg_cast castForm;
-
- castDesc = heap_open(CastRelationId, AccessShareLock);
-
- ScanKeyInit(&skey[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
- SnapshotNow, 1, skey);
-
- tup = systable_getnext(rcscan);
-
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "could not find tuple for cast %u",
- object->objectId);
-
- castForm = (Form_pg_cast) GETSTRUCT(tup);
-
- appendStringInfo(&buffer, _("cast from %s to %s"),
- format_type_be(castForm->castsource),
- format_type_be(castForm->casttarget));
-
- systable_endscan(rcscan);
- heap_close(castDesc, AccessShareLock);
- break;
- }
-
- case OCLASS_COLLATION:
- {
- HeapTuple collTup;
- Form_pg_collation coll;
-
- collTup = SearchSysCache1(COLLOID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(collTup))
- elog(ERROR, "cache lookup failed for collation %u",
- object->objectId);
- coll = (Form_pg_collation) GETSTRUCT(collTup);
- appendStringInfo(&buffer, _("collation %s"),
- NameStr(coll->collname));
- ReleaseSysCache(collTup);
- break;
- }
-
- case OCLASS_CONSTRAINT:
- {
- HeapTuple conTup;
- Form_pg_constraint con;
-
- conTup = SearchSysCache1(CONSTROID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(conTup))
- elog(ERROR, "cache lookup failed for constraint %u",
- object->objectId);
- con = (Form_pg_constraint) GETSTRUCT(conTup);
-
- if (OidIsValid(con->conrelid))
- {
- StringInfoData rel;
-
- initStringInfo(&rel);
- getRelationDescription(&rel, con->conrelid);
- appendStringInfo(&buffer, _("constraint %s on %s"),
- NameStr(con->conname), rel.data);
- pfree(rel.data);
- }
- else
- {
- appendStringInfo(&buffer, _("constraint %s"),
- NameStr(con->conname));
- }
-
- ReleaseSysCache(conTup);
- break;
- }
-
- case OCLASS_CONVERSION:
- {
- HeapTuple conTup;
-
- conTup = SearchSysCache1(CONVOID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(conTup))
- elog(ERROR, "cache lookup failed for conversion %u",
- object->objectId);
- appendStringInfo(&buffer, _("conversion %s"),
- NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
- ReleaseSysCache(conTup);
- break;
- }
-
- case OCLASS_DEFAULT:
- {
- Relation attrdefDesc;
- ScanKeyData skey[1];
- SysScanDesc adscan;
- HeapTuple tup;
- Form_pg_attrdef attrdef;
- ObjectAddress colobject;
-
- attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
-
- ScanKeyInit(&skey[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
- true, SnapshotNow, 1, skey);
-
- tup = systable_getnext(adscan);
-
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "could not find tuple for attrdef %u",
- object->objectId);
-
- attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
-
- colobject.classId = RelationRelationId;
- colobject.objectId = attrdef->adrelid;
- colobject.objectSubId = attrdef->adnum;
-
- appendStringInfo(&buffer, _("default for %s"),
- getObjectDescription(&colobject));
-
- systable_endscan(adscan);
- heap_close(attrdefDesc, AccessShareLock);
- break;
- }
-
- case OCLASS_LANGUAGE:
- {
- HeapTuple langTup;
-
- langTup = SearchSysCache1(LANGOID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(langTup))
- elog(ERROR, "cache lookup failed for language %u",
- object->objectId);
- appendStringInfo(&buffer, _("language %s"),
- NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
- ReleaseSysCache(langTup);
- break;
- }
- case OCLASS_LARGEOBJECT:
- appendStringInfo(&buffer, _("large object %u"),
- object->objectId);
- break;
-
- case OCLASS_OPERATOR:
- appendStringInfo(&buffer, _("operator %s"),
- format_operator(object->objectId));
- break;
-
- case OCLASS_OPCLASS:
- {
- HeapTuple opcTup;
- Form_pg_opclass opcForm;
- HeapTuple amTup;
- Form_pg_am amForm;
- char *nspname;
-
- opcTup = SearchSysCache1(CLAOID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(opcTup))
- elog(ERROR, "cache lookup failed for opclass %u",
- object->objectId);
- opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
-
- amTup = SearchSysCache1(AMOID,
- ObjectIdGetDatum(opcForm->opcmethod));
- if (!HeapTupleIsValid(amTup))
- elog(ERROR, "cache lookup failed for access method %u",
- opcForm->opcmethod);
- amForm = (Form_pg_am) GETSTRUCT(amTup);
-
- /* Qualify the name if not visible in search path */
- if (OpclassIsVisible(object->objectId))
- nspname = NULL;
- else
- nspname = get_namespace_name(opcForm->opcnamespace);
-
- appendStringInfo(&buffer, _("operator class %s for access method %s"),
- quote_qualified_identifier(nspname,
- NameStr(opcForm->opcname)),
- NameStr(amForm->amname));
-
- ReleaseSysCache(amTup);
- ReleaseSysCache(opcTup);
- break;
- }
-
- case OCLASS_OPFAMILY:
- getOpFamilyDescription(&buffer, object->objectId);
- break;
-
- case OCLASS_AMOP:
- {
- Relation amopDesc;
- ScanKeyData skey[1];
- SysScanDesc amscan;
- HeapTuple tup;
- Form_pg_amop amopForm;
- StringInfoData opfam;
-
- amopDesc = heap_open(AccessMethodOperatorRelationId,
- AccessShareLock);
-
- ScanKeyInit(&skey[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
- SnapshotNow, 1, skey);
-
- tup = systable_getnext(amscan);
-
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "could not find tuple for amop entry %u",
- object->objectId);
-
- amopForm = (Form_pg_amop) GETSTRUCT(tup);
-
- initStringInfo(&opfam);
- getOpFamilyDescription(&opfam, amopForm->amopfamily);
-
- /*------
- translator: %d is the operator strategy (a number), the
- first two %s's are data type names, the third %s is the
- description of the operator family, and the last %s is the
- textual form of the operator with arguments. */
- appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
- amopForm->amopstrategy,
- format_type_be(amopForm->amoplefttype),
- format_type_be(amopForm->amoprighttype),
- opfam.data,
- format_operator(amopForm->amopopr));
-
- pfree(opfam.data);
-
- systable_endscan(amscan);
- heap_close(amopDesc, AccessShareLock);
- break;
- }
-
- case OCLASS_AMPROC:
- {
- Relation amprocDesc;
- ScanKeyData skey[1];
- SysScanDesc amscan;
- HeapTuple tup;
- Form_pg_amproc amprocForm;
- StringInfoData opfam;
-
- amprocDesc = heap_open(AccessMethodProcedureRelationId,
- AccessShareLock);
-
- ScanKeyInit(&skey[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
- SnapshotNow, 1, skey);
-
- tup = systable_getnext(amscan);
-
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "could not find tuple for amproc entry %u",
- object->objectId);
-
- amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
-
- initStringInfo(&opfam);
- getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
-
- /*------
- translator: %d is the function number, the first two %s's
- are data type names, the third %s is the description of the
- operator family, and the last %s is the textual form of the
- function with arguments. */
- appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
- amprocForm->amprocnum,
- format_type_be(amprocForm->amproclefttype),
- format_type_be(amprocForm->amprocrighttype),
- opfam.data,
- format_procedure(amprocForm->amproc));
-
- pfree(opfam.data);
-
- systable_endscan(amscan);
- heap_close(amprocDesc, AccessShareLock);
- break;
- }
-
- case OCLASS_REWRITE:
- {
- Relation ruleDesc;
- ScanKeyData skey[1];
- SysScanDesc rcscan;
- HeapTuple tup;
- Form_pg_rewrite rule;
-
- ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
-
- ScanKeyInit(&skey[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
- SnapshotNow, 1, skey);
-
- tup = systable_getnext(rcscan);
-
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "could not find tuple for rule %u",
- object->objectId);
-
- rule = (Form_pg_rewrite) GETSTRUCT(tup);
-
- appendStringInfo(&buffer, _("rule %s on "),
- NameStr(rule->rulename));
- getRelationDescription(&buffer, rule->ev_class);
-
- systable_endscan(rcscan);
- heap_close(ruleDesc, AccessShareLock);
- break;
- }
-
- case OCLASS_TRIGGER:
- {
- Relation trigDesc;
- ScanKeyData skey[1];
- SysScanDesc tgscan;
- HeapTuple tup;
- Form_pg_trigger trig;
-
- trigDesc = heap_open(TriggerRelationId, AccessShareLock);
-
- ScanKeyInit(&skey[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
- SnapshotNow, 1, skey);
-
- tup = systable_getnext(tgscan);
-
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "could not find tuple for trigger %u",
- object->objectId);
-
- trig = (Form_pg_trigger) GETSTRUCT(tup);
-
- appendStringInfo(&buffer, _("trigger %s on "),
- NameStr(trig->tgname));
- getRelationDescription(&buffer, trig->tgrelid);
-
- systable_endscan(tgscan);
- heap_close(trigDesc, AccessShareLock);
- break;
- }
-
- case OCLASS_SCHEMA:
- {
- char *nspname;
-
- nspname = get_namespace_name(object->objectId);
- if (!nspname)
- elog(ERROR, "cache lookup failed for namespace %u",
- object->objectId);
- appendStringInfo(&buffer, _("schema %s"), nspname);
- break;
- }
-
- case OCLASS_TSPARSER:
- {
- HeapTuple tup;
-
- tup = SearchSysCache1(TSPARSEROID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for text search parser %u",
- object->objectId);
- appendStringInfo(&buffer, _("text search parser %s"),
- NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
- ReleaseSysCache(tup);
- break;
- }
-
- case OCLASS_TSDICT:
- {
- HeapTuple tup;
-
- tup = SearchSysCache1(TSDICTOID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for text search dictionary %u",
- object->objectId);
- appendStringInfo(&buffer, _("text search dictionary %s"),
- NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
- ReleaseSysCache(tup);
- break;
- }
-
- case OCLASS_TSTEMPLATE:
- {
- HeapTuple tup;
-
- tup = SearchSysCache1(TSTEMPLATEOID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for text search template %u",
- object->objectId);
- appendStringInfo(&buffer, _("text search template %s"),
- NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
- ReleaseSysCache(tup);
- break;
- }
-
- case OCLASS_TSCONFIG:
- {
- HeapTuple tup;
-
- tup = SearchSysCache1(TSCONFIGOID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for text search configuration %u",
- object->objectId);
- appendStringInfo(&buffer, _("text search configuration %s"),
- NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
- ReleaseSysCache(tup);
- break;
- }
-
- case OCLASS_ROLE:
- {
- appendStringInfo(&buffer, _("role %s"),
- GetUserNameFromId(object->objectId));
- break;
- }
-
- case OCLASS_DATABASE:
- {
- char *datname;
-
- datname = get_database_name(object->objectId);
- if (!datname)
- elog(ERROR, "cache lookup failed for database %u",
- object->objectId);
- appendStringInfo(&buffer, _("database %s"), datname);
- break;
- }
-
- case OCLASS_TBLSPACE:
- {
- char *tblspace;
-
- tblspace = get_tablespace_name(object->objectId);
- if (!tblspace)
- elog(ERROR, "cache lookup failed for tablespace %u",
- object->objectId);
- appendStringInfo(&buffer, _("tablespace %s"), tblspace);
- break;
- }
-
- case OCLASS_FDW:
- {
- ForeignDataWrapper *fdw;
-
- fdw = GetForeignDataWrapper(object->objectId);
- appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
- break;
- }
-
- case OCLASS_FOREIGN_SERVER:
- {
- ForeignServer *srv;
-
- srv = GetForeignServer(object->objectId);
- appendStringInfo(&buffer, _("server %s"), srv->servername);
- break;
- }
-
- case OCLASS_USER_MAPPING:
- {
- HeapTuple tup;
- Oid useid;
- char *usename;
-
- tup = SearchSysCache1(USERMAPPINGOID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for user mapping %u",
- object->objectId);
-
- useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
-
- ReleaseSysCache(tup);
-
- if (OidIsValid(useid))
- usename = GetUserNameFromId(useid);
- else
- usename = "public";
-
- appendStringInfo(&buffer, _("user mapping for %s"), usename);
- break;
- }
-
- case OCLASS_DEFACL:
- {
- Relation defaclrel;
- ScanKeyData skey[1];
- SysScanDesc rcscan;
- HeapTuple tup;
- Form_pg_default_acl defacl;
-
- defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
-
- ScanKeyInit(&skey[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
-
- rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
- true, SnapshotNow, 1, skey);
-
- tup = systable_getnext(rcscan);
-
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "could not find tuple for default ACL %u",
- object->objectId);
-
- defacl = (Form_pg_default_acl) GETSTRUCT(tup);
-
- switch (defacl->defaclobjtype)
- {
- case DEFACLOBJ_RELATION:
- appendStringInfo(&buffer,
- _("default privileges on new relations belonging to role %s"),
- GetUserNameFromId(defacl->defaclrole));
- break;
- case DEFACLOBJ_SEQUENCE:
- appendStringInfo(&buffer,
- _("default privileges on new sequences belonging to role %s"),
- GetUserNameFromId(defacl->defaclrole));
- break;
- case DEFACLOBJ_FUNCTION:
- appendStringInfo(&buffer,
- _("default privileges on new functions belonging to role %s"),
- GetUserNameFromId(defacl->defaclrole));
- break;
- case DEFACLOBJ_TYPE:
- appendStringInfo(&buffer,
- _("default privileges on new types belonging to role %s"),
- GetUserNameFromId(defacl->defaclrole));
- break;
- default:
- /* shouldn't get here */
- appendStringInfo(&buffer,
- _("default privileges belonging to role %s"),
- GetUserNameFromId(defacl->defaclrole));
- break;
- }
-
- if (OidIsValid(defacl->defaclnamespace))
- {
- appendStringInfo(&buffer,
- _(" in schema %s"),
- get_namespace_name(defacl->defaclnamespace));
- }
-
- systable_endscan(rcscan);
- heap_close(defaclrel, AccessShareLock);
- break;
- }
-
- case OCLASS_EXTENSION:
- {
- char *extname;
-
- extname = get_extension_name(object->objectId);
- if (!extname)
- elog(ERROR, "cache lookup failed for extension %u",
- object->objectId);
- appendStringInfo(&buffer, _("extension %s"), extname);
- break;
- }
-
- case OCLASS_EVENT_TRIGGER:
- {
- HeapTuple tup;
-
- tup = SearchSysCache1(EVENTTRIGGEROID,
- ObjectIdGetDatum(object->objectId));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for event trigger %u",
- object->objectId);
- appendStringInfo(&buffer, _("event trigger %s"),
- NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
- ReleaseSysCache(tup);
- break;
- }
-
- default:
- appendStringInfo(&buffer, "unrecognized object %u %u %d",
- object->classId,
- object->objectId,
- object->objectSubId);
- break;
- }
-
- return buffer.data;
-}
-
-/*
- * getObjectDescriptionOids: as above, except the object is specified by Oids
- */
-char *
-getObjectDescriptionOids(Oid classid, Oid objid)
-{
- ObjectAddress address;
-
- address.classId = classid;
- address.objectId = objid;
- address.objectSubId = 0;
-
- return getObjectDescription(&address);
-}
-
-/*
- * subroutine for getObjectDescription: describe a relation
- */
-static void
-getRelationDescription(StringInfo buffer, Oid relid)
-{
- HeapTuple relTup;
- Form_pg_class relForm;
- char *nspname;
- char *relname;
-
- relTup = SearchSysCache1(RELOID,
- ObjectIdGetDatum(relid));
- if (!HeapTupleIsValid(relTup))
- elog(ERROR, "cache lookup failed for relation %u", relid);
- relForm = (Form_pg_class) GETSTRUCT(relTup);
-
- /* Qualify the name if not visible in search path */
- if (RelationIsVisible(relid))
- nspname = NULL;
- else
- nspname = get_namespace_name(relForm->relnamespace);
-
- relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
-
- switch (relForm->relkind)
- {
- case RELKIND_RELATION:
- appendStringInfo(buffer, _("table %s"),
- relname);
- break;
- case RELKIND_INDEX:
- appendStringInfo(buffer, _("index %s"),
- relname);
- break;
- case RELKIND_SEQUENCE:
- appendStringInfo(buffer, _("sequence %s"),
- relname);
- break;
- case RELKIND_TOASTVALUE:
- appendStringInfo(buffer, _("toast table %s"),
- relname);
- break;
- case RELKIND_VIEW:
- appendStringInfo(buffer, _("view %s"),
- relname);
- break;
- case RELKIND_MATVIEW:
- appendStringInfo(buffer, _("materialized view %s"),
- relname);
- break;
- case RELKIND_COMPOSITE_TYPE:
- appendStringInfo(buffer, _("composite type %s"),
- relname);
- break;
- case RELKIND_FOREIGN_TABLE:
- appendStringInfo(buffer, _("foreign table %s"),
- relname);
- break;
- default:
- /* shouldn't get here */
- appendStringInfo(buffer, _("relation %s"),
- relname);
- break;
- }
-
- ReleaseSysCache(relTup);
-}
-
-/*
- * subroutine for getObjectDescription: describe an operator family
- */
-static void
-getOpFamilyDescription(StringInfo buffer, Oid opfid)
-{
- HeapTuple opfTup;
- Form_pg_opfamily opfForm;
- HeapTuple amTup;
- Form_pg_am amForm;
- char *nspname;
-
- opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
- if (!HeapTupleIsValid(opfTup))
- elog(ERROR, "cache lookup failed for opfamily %u", opfid);
- opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
-
- amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
- if (!HeapTupleIsValid(amTup))
- elog(ERROR, "cache lookup failed for access method %u",
- opfForm->opfmethod);
- amForm = (Form_pg_am) GETSTRUCT(amTup);
-
- /* Qualify the name if not visible in search path */
- if (OpfamilyIsVisible(opfid))
- nspname = NULL;
- else
- nspname = get_namespace_name(opfForm->opfnamespace);
-
- appendStringInfo(buffer, _("operator family %s for access method %s"),
- quote_qualified_identifier(nspname,
- NameStr(opfForm->opfname)),
- NameStr(amForm->amname));
-
- ReleaseSysCache(amTup);
- ReleaseSysCache(opfTup);
-}
-
-/*
- * SQL-level callable version of getObjectDescription
- */
-Datum
-pg_describe_object(PG_FUNCTION_ARGS)
-{
- Oid classid = PG_GETARG_OID(0);
- Oid objid = PG_GETARG_OID(1);
- int32 subobjid = PG_GETARG_INT32(2);
- char *description = NULL;
- ObjectAddress address;
-
- /* for "pinned" items in pg_depend, return null */
- if (!OidIsValid(classid) && !OidIsValid(objid))
- PG_RETURN_NULL();
-
- address.classId = classid;
- address.objectId = objid;
- address.objectSubId = subobjid;
-
- description = getObjectDescription(&address);
- PG_RETURN_TEXT_P(cstring_to_text(description));
-}
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/objectaddress.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
+#include "catalog/pg_attrdef.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
+#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_ts_parser.h"
#include "catalog/pg_ts_template.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "foreign/foreign.h"
+#include "funcapi.h"
#include "libpq/be-fsstubs.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
AttrNumber attnum_owner; /* attnum of owner field */
AttrNumber attnum_acl; /* attnum of acl field */
AclObjectKind acl_kind; /* ACL_KIND_* of this object type */
+ bool is_nsp_name_unique; /* can the nsp/name combination (or name
+ * alone, if there's no namespace) be
+ * considered an unique identifier for an
+ * object of this class? */
} ObjectPropertyType;
static ObjectPropertyType ObjectProperty[] =
InvalidAttrNumber,
InvalidAttrNumber,
InvalidAttrNumber,
- -1
+ -1,
+ false
},
{
CollationRelationId,
Anum_pg_collation_collnamespace,
Anum_pg_collation_collowner,
InvalidAttrNumber,
- ACL_KIND_COLLATION
+ ACL_KIND_COLLATION,
+ true
},
{
ConstraintRelationId,
Anum_pg_constraint_connamespace,
InvalidAttrNumber,
InvalidAttrNumber,
- -1
+ -1,
+ false
},
{
ConversionRelationId,
Anum_pg_conversion_connamespace,
Anum_pg_conversion_conowner,
InvalidAttrNumber,
- ACL_KIND_CONVERSION
+ ACL_KIND_CONVERSION,
+ true
},
{
DatabaseRelationId,
InvalidAttrNumber,
Anum_pg_database_datdba,
Anum_pg_database_datacl,
- ACL_KIND_DATABASE
+ ACL_KIND_DATABASE,
+ true
},
{
ExtensionRelationId,
InvalidAttrNumber, /* extension doesn't belong to extnamespace */
Anum_pg_extension_extowner,
InvalidAttrNumber,
- ACL_KIND_EXTENSION
+ ACL_KIND_EXTENSION,
+ true
},
{
ForeignDataWrapperRelationId,
InvalidAttrNumber,
Anum_pg_foreign_data_wrapper_fdwowner,
Anum_pg_foreign_data_wrapper_fdwacl,
- ACL_KIND_FDW
+ ACL_KIND_FDW,
+ true
},
{
ForeignServerRelationId,
InvalidAttrNumber,
Anum_pg_foreign_server_srvowner,
Anum_pg_foreign_server_srvacl,
- ACL_KIND_FOREIGN_SERVER
+ ACL_KIND_FOREIGN_SERVER,
+ true
},
{
ProcedureRelationId,
Anum_pg_proc_pronamespace,
Anum_pg_proc_proowner,
Anum_pg_proc_proacl,
- ACL_KIND_PROC
+ ACL_KIND_PROC,
+ false
},
{
LanguageRelationId,
InvalidAttrNumber,
Anum_pg_language_lanowner,
Anum_pg_language_lanacl,
- ACL_KIND_LANGUAGE
+ ACL_KIND_LANGUAGE,
+ true
},
{
LargeObjectMetadataRelationId,
InvalidAttrNumber,
Anum_pg_largeobject_metadata_lomowner,
Anum_pg_largeobject_metadata_lomacl,
- ACL_KIND_LARGEOBJECT
+ ACL_KIND_LARGEOBJECT,
+ false
},
{
OperatorClassRelationId,
Anum_pg_opclass_opcnamespace,
Anum_pg_opclass_opcowner,
InvalidAttrNumber,
- ACL_KIND_OPCLASS
+ ACL_KIND_OPCLASS,
+ true
},
{
OperatorRelationId,
Anum_pg_operator_oprnamespace,
Anum_pg_operator_oprowner,
InvalidAttrNumber,
- ACL_KIND_OPER
+ ACL_KIND_OPER,
+ false
},
{
OperatorFamilyRelationId,
Anum_pg_opfamily_opfnamespace,
Anum_pg_opfamily_opfowner,
InvalidAttrNumber,
- ACL_KIND_OPFAMILY
+ ACL_KIND_OPFAMILY,
+ true
},
{
AuthIdRelationId,
InvalidAttrNumber,
InvalidAttrNumber,
InvalidAttrNumber,
- -1
+ -1,
+ true
},
{
RewriteRelationId,
InvalidAttrNumber,
InvalidAttrNumber,
InvalidAttrNumber,
- -1
+ -1,
+ false
},
{
NamespaceRelationId,
InvalidAttrNumber,
Anum_pg_namespace_nspowner,
Anum_pg_namespace_nspacl,
- ACL_KIND_NAMESPACE
+ ACL_KIND_NAMESPACE,
+ true
},
{
RelationRelationId,
Anum_pg_class_relnamespace,
Anum_pg_class_relowner,
Anum_pg_class_relacl,
- ACL_KIND_CLASS
+ ACL_KIND_CLASS,
+ true
},
{
TableSpaceRelationId,
InvalidAttrNumber,
Anum_pg_tablespace_spcowner,
Anum_pg_tablespace_spcacl,
- ACL_KIND_TABLESPACE
+ ACL_KIND_TABLESPACE,
+ true
},
{
TriggerRelationId,
InvalidAttrNumber,
InvalidAttrNumber,
-1,
+ false
},
{
EventTriggerRelationId,
Anum_pg_event_trigger_evtowner,
InvalidAttrNumber,
ACL_KIND_EVENT_TRIGGER,
+ true
},
{
TSConfigRelationId,
Anum_pg_ts_config_cfgnamespace,
Anum_pg_ts_config_cfgowner,
InvalidAttrNumber,
- ACL_KIND_TSCONFIGURATION
+ ACL_KIND_TSCONFIGURATION,
+ true
},
{
TSDictionaryRelationId,
Anum_pg_ts_dict_dictnamespace,
Anum_pg_ts_dict_dictowner,
InvalidAttrNumber,
- ACL_KIND_TSDICTIONARY
+ ACL_KIND_TSDICTIONARY,
+ true
},
{
TSParserRelationId,
InvalidAttrNumber,
InvalidAttrNumber,
-1,
+ true
},
{
TSTemplateRelationId,
InvalidAttrNumber,
InvalidAttrNumber,
-1,
+ true,
},
{
TypeRelationId,
Anum_pg_type_typnamespace,
Anum_pg_type_typowner,
Anum_pg_type_typacl,
- ACL_KIND_TYPE
+ ACL_KIND_TYPE,
+ true
}
};
List *objargs, bool missing_ok);
static ObjectPropertyType *get_object_property_data(Oid class_id);
+static void getRelationDescription(StringInfo buffer, Oid relid);
+static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
+static void getRelationTypeDescription(StringInfo buffer, Oid relid,
+ int32 objectSubId);
+static void getProcedureTypeDescription(StringInfo buffer, Oid procid);
+static void getConstraintTypeDescription(StringInfo buffer, Oid constroid);
+static void getOpFamilyIdentity(StringInfo buffer, Oid opfid);
+static void getRelationIdentity(StringInfo buffer, Oid relid);
+
/*
* Translate an object name and arguments (as passed by the parser) to an
* ObjectAddress.
return prop->acl_kind;
}
+bool
+get_object_namensp_unique(Oid class_id)
+{
+ ObjectPropertyType *prop = get_object_property_data(class_id);
+
+ return prop->is_nsp_name_unique;
+}
+
+/*
+ * Return whether we have useful data for the given object class in the
+ * ObjectProperty table.
+ */
+bool
+is_objectclass_supported(Oid class_id)
+{
+ int index;
+
+ for (index = 0; index < lengthof(ObjectProperty); index++)
+ {
+ if (ObjectProperty[index].class_oid == class_id)
+ return true;
+ }
+
+ return false;
+}
+
/*
* Find ObjectProperty structure by class_id.
*/
return NULL; /* keep MSC compiler happy */
}
+
+/*
+ * Return a copy of the tuple for the object with the given object OID, from
+ * the given catalog (which must have been opened by the caller and suitably
+ * locked). NULL is returned if the OID is not found.
+ *
+ * We try a syscache first, if available.
+ */
+HeapTuple
+get_catalog_object_by_oid(Relation catalog, Oid objectId)
+{
+ HeapTuple tuple;
+ Oid classId = RelationGetRelid(catalog);
+ int oidCacheId = get_object_catcache_oid(classId);
+
+ if (oidCacheId > 0)
+ {
+ tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
+ if (!HeapTupleIsValid(tuple)) /* should not happen */
+ return NULL;
+ }
+ else
+ {
+ Oid oidIndexId = get_object_oid_index(classId);
+ SysScanDesc scan;
+ ScanKeyData skey;
+
+ Assert(OidIsValid(oidIndexId));
+
+ ScanKeyInit(&skey,
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(objectId));
+
+ scan = systable_beginscan(catalog, oidIndexId, true,
+ SnapshotNow, 1, &skey);
+ tuple = systable_getnext(scan);
+ if (!HeapTupleIsValid(tuple))
+ {
+ systable_endscan(scan);
+ return NULL;
+ }
+ tuple = heap_copytuple(tuple);
+
+ systable_endscan(scan);
+ }
+
+ return tuple;
+}
+
+/*
+ * getObjectDescription: build an object description for messages
+ *
+ * The result is a palloc'd string.
+ */
+char *
+getObjectDescription(const ObjectAddress *object)
+{
+ StringInfoData buffer;
+
+ initStringInfo(&buffer);
+
+ switch (getObjectClass(object))
+ {
+ case OCLASS_CLASS:
+ getRelationDescription(&buffer, object->objectId);
+ if (object->objectSubId != 0)
+ appendStringInfo(&buffer, _(" column %s"),
+ get_relid_attribute_name(object->objectId,
+ object->objectSubId));
+ break;
+
+ case OCLASS_PROC:
+ appendStringInfo(&buffer, _("function %s"),
+ format_procedure(object->objectId));
+ break;
+
+ case OCLASS_TYPE:
+ appendStringInfo(&buffer, _("type %s"),
+ format_type_be(object->objectId));
+ break;
+
+ case OCLASS_CAST:
+ {
+ Relation castDesc;
+ ScanKeyData skey[1];
+ SysScanDesc rcscan;
+ HeapTuple tup;
+ Form_pg_cast castForm;
+
+ castDesc = heap_open(CastRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ tup = systable_getnext(rcscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for cast %u",
+ object->objectId);
+
+ castForm = (Form_pg_cast) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, _("cast from %s to %s"),
+ format_type_be(castForm->castsource),
+ format_type_be(castForm->casttarget));
+
+ systable_endscan(rcscan);
+ heap_close(castDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_COLLATION:
+ {
+ HeapTuple collTup;
+ Form_pg_collation coll;
+
+ collTup = SearchSysCache1(COLLOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(collTup))
+ elog(ERROR, "cache lookup failed for collation %u",
+ object->objectId);
+ coll = (Form_pg_collation) GETSTRUCT(collTup);
+ appendStringInfo(&buffer, _("collation %s"),
+ NameStr(coll->collname));
+ ReleaseSysCache(collTup);
+ break;
+ }
+
+ case OCLASS_CONSTRAINT:
+ {
+ HeapTuple conTup;
+ Form_pg_constraint con;
+
+ conTup = SearchSysCache1(CONSTROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(conTup))
+ elog(ERROR, "cache lookup failed for constraint %u",
+ object->objectId);
+ con = (Form_pg_constraint) GETSTRUCT(conTup);
+
+ if (OidIsValid(con->conrelid))
+ {
+ StringInfoData rel;
+
+ initStringInfo(&rel);
+ getRelationDescription(&rel, con->conrelid);
+ appendStringInfo(&buffer, _("constraint %s on %s"),
+ NameStr(con->conname), rel.data);
+ pfree(rel.data);
+ }
+ else
+ {
+ appendStringInfo(&buffer, _("constraint %s"),
+ NameStr(con->conname));
+ }
+
+ ReleaseSysCache(conTup);
+ break;
+ }
+
+ case OCLASS_CONVERSION:
+ {
+ HeapTuple conTup;
+
+ conTup = SearchSysCache1(CONVOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(conTup))
+ elog(ERROR, "cache lookup failed for conversion %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("conversion %s"),
+ NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
+ ReleaseSysCache(conTup);
+ break;
+ }
+
+ case OCLASS_DEFAULT:
+ {
+ Relation attrdefDesc;
+ ScanKeyData skey[1];
+ SysScanDesc adscan;
+ HeapTuple tup;
+ Form_pg_attrdef attrdef;
+ ObjectAddress colobject;
+
+ attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
+ true, SnapshotNow, 1, skey);
+
+ tup = systable_getnext(adscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for attrdef %u",
+ object->objectId);
+
+ attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
+
+ colobject.classId = RelationRelationId;
+ colobject.objectId = attrdef->adrelid;
+ colobject.objectSubId = attrdef->adnum;
+
+ appendStringInfo(&buffer, _("default for %s"),
+ getObjectDescription(&colobject));
+
+ systable_endscan(adscan);
+ heap_close(attrdefDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_LANGUAGE:
+ {
+ HeapTuple langTup;
+
+ langTup = SearchSysCache1(LANGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(langTup))
+ elog(ERROR, "cache lookup failed for language %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("language %s"),
+ NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
+ ReleaseSysCache(langTup);
+ break;
+ }
+ case OCLASS_LARGEOBJECT:
+ appendStringInfo(&buffer, _("large object %u"),
+ object->objectId);
+ break;
+
+ case OCLASS_OPERATOR:
+ appendStringInfo(&buffer, _("operator %s"),
+ format_operator(object->objectId));
+ break;
+
+ case OCLASS_OPCLASS:
+ {
+ HeapTuple opcTup;
+ Form_pg_opclass opcForm;
+ HeapTuple amTup;
+ Form_pg_am amForm;
+ char *nspname;
+
+ opcTup = SearchSysCache1(CLAOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(opcTup))
+ elog(ERROR, "cache lookup failed for opclass %u",
+ object->objectId);
+ opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
+
+ amTup = SearchSysCache1(AMOID,
+ ObjectIdGetDatum(opcForm->opcmethod));
+ if (!HeapTupleIsValid(amTup))
+ elog(ERROR, "cache lookup failed for access method %u",
+ opcForm->opcmethod);
+ amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+ /* Qualify the name if not visible in search path */
+ if (OpclassIsVisible(object->objectId))
+ nspname = NULL;
+ else
+ nspname = get_namespace_name(opcForm->opcnamespace);
+
+ appendStringInfo(&buffer, _("operator class %s for access method %s"),
+ quote_qualified_identifier(nspname,
+ NameStr(opcForm->opcname)),
+ NameStr(amForm->amname));
+
+ ReleaseSysCache(amTup);
+ ReleaseSysCache(opcTup);
+ break;
+ }
+
+ case OCLASS_OPFAMILY:
+ getOpFamilyDescription(&buffer, object->objectId);
+ break;
+
+ case OCLASS_AMOP:
+ {
+ Relation amopDesc;
+ HeapTuple tup;
+ ScanKeyData skey[1];
+ SysScanDesc amscan;
+ Form_pg_amop amopForm;
+ StringInfoData opfam;
+
+ amopDesc = heap_open(AccessMethodOperatorRelationId,
+ AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ tup = systable_getnext(amscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for amop entry %u",
+ object->objectId);
+
+ amopForm = (Form_pg_amop) GETSTRUCT(tup);
+
+ initStringInfo(&opfam);
+ getOpFamilyDescription(&opfam, amopForm->amopfamily);
+
+ /*------
+ translator: %d is the operator strategy (a number), the
+ first two %s's are data type names, the third %s is the
+ description of the operator family, and the last %s is the
+ textual form of the operator with arguments. */
+ appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
+ amopForm->amopstrategy,
+ format_type_be(amopForm->amoplefttype),
+ format_type_be(amopForm->amoprighttype),
+ opfam.data,
+ format_operator(amopForm->amopopr));
+
+ pfree(opfam.data);
+
+ systable_endscan(amscan);
+ heap_close(amopDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_AMPROC:
+ {
+ Relation amprocDesc;
+ ScanKeyData skey[1];
+ SysScanDesc amscan;
+ HeapTuple tup;
+ Form_pg_amproc amprocForm;
+ StringInfoData opfam;
+
+ amprocDesc = heap_open(AccessMethodProcedureRelationId,
+ AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ tup = systable_getnext(amscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for amproc entry %u",
+ object->objectId);
+
+ amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
+
+ initStringInfo(&opfam);
+ getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
+
+ /*------
+ translator: %d is the function number, the first two %s's
+ are data type names, the third %s is the description of the
+ operator family, and the last %s is the textual form of the
+ function with arguments. */
+ appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
+ amprocForm->amprocnum,
+ format_type_be(amprocForm->amproclefttype),
+ format_type_be(amprocForm->amprocrighttype),
+ opfam.data,
+ format_procedure(amprocForm->amproc));
+
+ pfree(opfam.data);
+
+ systable_endscan(amscan);
+ heap_close(amprocDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_REWRITE:
+ {
+ Relation ruleDesc;
+ ScanKeyData skey[1];
+ SysScanDesc rcscan;
+ HeapTuple tup;
+ Form_pg_rewrite rule;
+
+ ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ tup = systable_getnext(rcscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for rule %u",
+ object->objectId);
+
+ rule = (Form_pg_rewrite) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, _("rule %s on "),
+ NameStr(rule->rulename));
+ getRelationDescription(&buffer, rule->ev_class);
+
+ systable_endscan(rcscan);
+ heap_close(ruleDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_TRIGGER:
+ {
+ Relation trigDesc;
+ ScanKeyData skey[1];
+ SysScanDesc tgscan;
+ HeapTuple tup;
+ Form_pg_trigger trig;
+
+ trigDesc = heap_open(TriggerRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ tup = systable_getnext(tgscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for trigger %u",
+ object->objectId);
+
+ trig = (Form_pg_trigger) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, _("trigger %s on "),
+ NameStr(trig->tgname));
+ getRelationDescription(&buffer, trig->tgrelid);
+
+ systable_endscan(tgscan);
+ heap_close(trigDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_SCHEMA:
+ {
+ char *nspname;
+
+ nspname = get_namespace_name(object->objectId);
+ if (!nspname)
+ elog(ERROR, "cache lookup failed for namespace %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("schema %s"), nspname);
+ break;
+ }
+
+ case OCLASS_TSPARSER:
+ {
+ HeapTuple tup;
+
+ tup = SearchSysCache1(TSPARSEROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search parser %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("text search parser %s"),
+ NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSDICT:
+ {
+ HeapTuple tup;
+
+ tup = SearchSysCache1(TSDICTOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search dictionary %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("text search dictionary %s"),
+ NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSTEMPLATE:
+ {
+ HeapTuple tup;
+
+ tup = SearchSysCache1(TSTEMPLATEOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search template %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("text search template %s"),
+ NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSCONFIG:
+ {
+ HeapTuple tup;
+
+ tup = SearchSysCache1(TSCONFIGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search configuration %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("text search configuration %s"),
+ NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_ROLE:
+ {
+ appendStringInfo(&buffer, _("role %s"),
+ GetUserNameFromId(object->objectId));
+ break;
+ }
+
+ case OCLASS_DATABASE:
+ {
+ char *datname;
+
+ datname = get_database_name(object->objectId);
+ if (!datname)
+ elog(ERROR, "cache lookup failed for database %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("database %s"), datname);
+ break;
+ }
+
+ case OCLASS_TBLSPACE:
+ {
+ char *tblspace;
+
+ tblspace = get_tablespace_name(object->objectId);
+ if (!tblspace)
+ elog(ERROR, "cache lookup failed for tablespace %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("tablespace %s"), tblspace);
+ break;
+ }
+
+ case OCLASS_FDW:
+ {
+ ForeignDataWrapper *fdw;
+
+ fdw = GetForeignDataWrapper(object->objectId);
+ appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
+ break;
+ }
+
+ case OCLASS_FOREIGN_SERVER:
+ {
+ ForeignServer *srv;
+
+ srv = GetForeignServer(object->objectId);
+ appendStringInfo(&buffer, _("server %s"), srv->servername);
+ break;
+ }
+
+ case OCLASS_USER_MAPPING:
+ {
+ HeapTuple tup;
+ Oid useid;
+ char *usename;
+
+ tup = SearchSysCache1(USERMAPPINGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for user mapping %u",
+ object->objectId);
+
+ useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
+
+ ReleaseSysCache(tup);
+
+ if (OidIsValid(useid))
+ usename = GetUserNameFromId(useid);
+ else
+ usename = "public";
+
+ appendStringInfo(&buffer, _("user mapping for %s"), usename);
+ break;
+ }
+
+ case OCLASS_DEFACL:
+ {
+ Relation defaclrel;
+ ScanKeyData skey[1];
+ SysScanDesc rcscan;
+ HeapTuple tup;
+ Form_pg_default_acl defacl;
+
+ defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
+ true, SnapshotNow, 1, skey);
+
+ tup = systable_getnext(rcscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for default ACL %u",
+ object->objectId);
+
+ defacl = (Form_pg_default_acl) GETSTRUCT(tup);
+
+ switch (defacl->defaclobjtype)
+ {
+ case DEFACLOBJ_RELATION:
+ appendStringInfo(&buffer,
+ _("default privileges on new relations belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole));
+ break;
+ case DEFACLOBJ_SEQUENCE:
+ appendStringInfo(&buffer,
+ _("default privileges on new sequences belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole));
+ break;
+ case DEFACLOBJ_FUNCTION:
+ appendStringInfo(&buffer,
+ _("default privileges on new functions belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole));
+ break;
+ case DEFACLOBJ_TYPE:
+ appendStringInfo(&buffer,
+ _("default privileges on new types belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole));
+ break;
+ default:
+ /* shouldn't get here */
+ appendStringInfo(&buffer,
+ _("default privileges belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole));
+ break;
+ }
+
+ if (OidIsValid(defacl->defaclnamespace))
+ {
+ appendStringInfo(&buffer,
+ _(" in schema %s"),
+ get_namespace_name(defacl->defaclnamespace));
+ }
+
+ systable_endscan(rcscan);
+ heap_close(defaclrel, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_EXTENSION:
+ {
+ char *extname;
+
+ extname = get_extension_name(object->objectId);
+ if (!extname)
+ elog(ERROR, "cache lookup failed for extension %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("extension %s"), extname);
+ break;
+ }
+
+ case OCLASS_EVENT_TRIGGER:
+ {
+ HeapTuple tup;
+
+ tup = SearchSysCache1(EVENTTRIGGEROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for event trigger %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("event trigger %s"),
+ NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ default:
+ appendStringInfo(&buffer, "unrecognized object %u %u %d",
+ object->classId,
+ object->objectId,
+ object->objectSubId);
+ break;
+ }
+
+ return buffer.data;
+}
+
+/*
+ * getObjectDescriptionOids: as above, except the object is specified by Oids
+ */
+char *
+getObjectDescriptionOids(Oid classid, Oid objid)
+{
+ ObjectAddress address;
+
+ address.classId = classid;
+ address.objectId = objid;
+ address.objectSubId = 0;
+
+ return getObjectDescription(&address);
+}
+
+/*
+ * subroutine for getObjectDescription: describe a relation
+ */
+static void
+getRelationDescription(StringInfo buffer, Oid relid)
+{
+ HeapTuple relTup;
+ Form_pg_class relForm;
+ char *nspname;
+ char *relname;
+
+ relTup = SearchSysCache1(RELOID,
+ ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(relTup))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+ /* Qualify the name if not visible in search path */
+ if (RelationIsVisible(relid))
+ nspname = NULL;
+ else
+ nspname = get_namespace_name(relForm->relnamespace);
+
+ relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
+
+ switch (relForm->relkind)
+ {
+ case RELKIND_RELATION:
+ appendStringInfo(buffer, _("table %s"),
+ relname);
+ break;
+ case RELKIND_INDEX:
+ appendStringInfo(buffer, _("index %s"),
+ relname);
+ break;
+ case RELKIND_SEQUENCE:
+ appendStringInfo(buffer, _("sequence %s"),
+ relname);
+ break;
+ case RELKIND_TOASTVALUE:
+ appendStringInfo(buffer, _("toast table %s"),
+ relname);
+ break;
+ case RELKIND_VIEW:
+ appendStringInfo(buffer, _("view %s"),
+ relname);
+ break;
+ case RELKIND_MATVIEW:
+ appendStringInfo(buffer, _("materialized view %s"),
+ relname);
+ break;
+ case RELKIND_COMPOSITE_TYPE:
+ appendStringInfo(buffer, _("composite type %s"),
+ relname);
+ break;
+ case RELKIND_FOREIGN_TABLE:
+ appendStringInfo(buffer, _("foreign table %s"),
+ relname);
+ break;
+ default:
+ /* shouldn't get here */
+ appendStringInfo(buffer, _("relation %s"),
+ relname);
+ break;
+ }
+
+ ReleaseSysCache(relTup);
+}
+
+/*
+ * subroutine for getObjectDescription: describe an operator family
+ */
+static void
+getOpFamilyDescription(StringInfo buffer, Oid opfid)
+{
+ HeapTuple opfTup;
+ Form_pg_opfamily opfForm;
+ HeapTuple amTup;
+ Form_pg_am amForm;
+ char *nspname;
+
+ opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
+ if (!HeapTupleIsValid(opfTup))
+ elog(ERROR, "cache lookup failed for opfamily %u", opfid);
+ opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
+
+ amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
+ if (!HeapTupleIsValid(amTup))
+ elog(ERROR, "cache lookup failed for access method %u",
+ opfForm->opfmethod);
+ amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+ /* Qualify the name if not visible in search path */
+ if (OpfamilyIsVisible(opfid))
+ nspname = NULL;
+ else
+ nspname = get_namespace_name(opfForm->opfnamespace);
+
+ appendStringInfo(buffer, _("operator family %s for access method %s"),
+ quote_qualified_identifier(nspname,
+ NameStr(opfForm->opfname)),
+ NameStr(amForm->amname));
+
+ ReleaseSysCache(amTup);
+ ReleaseSysCache(opfTup);
+}
+
+/*
+ * SQL-level callable version of getObjectDescription
+ */
+Datum
+pg_describe_object(PG_FUNCTION_ARGS)
+{
+ Oid classid = PG_GETARG_OID(0);
+ Oid objid = PG_GETARG_OID(1);
+ int32 subobjid = PG_GETARG_INT32(2);
+ char *description;
+ ObjectAddress address;
+
+ /* for "pinned" items in pg_depend, return null */
+ if (!OidIsValid(classid) && !OidIsValid(objid))
+ PG_RETURN_NULL();
+
+ address.classId = classid;
+ address.objectId = objid;
+ address.objectSubId = subobjid;
+
+ description = getObjectDescription(&address);
+ PG_RETURN_TEXT_P(cstring_to_text(description));
+}
+
+/*
+ * SQL-level callable function to obtain object type + identity
+ */
+Datum
+pg_identify_object(PG_FUNCTION_ARGS)
+{
+ Oid classid = PG_GETARG_OID(0);
+ Oid objid = PG_GETARG_OID(1);
+ int32 subobjid = PG_GETARG_INT32(2);
+ Oid schema_oid = InvalidOid;
+ const char *objname = NULL;
+ ObjectAddress address;
+ Datum values[4];
+ bool nulls[4];
+ TupleDesc tupdesc;
+ HeapTuple htup;
+
+ address.classId = classid;
+ address.objectId = objid;
+ address.objectSubId = subobjid;
+
+ /*
+ * Construct a tuple descriptor for the result row. This must match this
+ * function's pg_proc entry!
+ */
+ tupdesc = CreateTemplateTupleDesc(4, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
+ TEXTOID, -1, 0);
+
+ tupdesc = BlessTupleDesc(tupdesc);
+
+ if (is_objectclass_supported(address.classId))
+ {
+ HeapTuple objtup;
+ Relation catalog = heap_open(address.classId, AccessShareLock);
+
+ objtup = get_catalog_object_by_oid(catalog, address.objectId);
+ if (objtup != NULL)
+ {
+ bool isnull;
+ AttrNumber nspAttnum;
+ AttrNumber nameAttnum;
+
+ nspAttnum = get_object_attnum_namespace(address.classId);
+ if (nspAttnum != InvalidAttrNumber)
+ {
+ schema_oid = heap_getattr(objtup, nspAttnum,
+ RelationGetDescr(catalog), &isnull);
+ if (isnull)
+ elog(ERROR, "invalid null namespace in object %u/%u/%d",
+ address.classId, address.objectId, address.objectSubId);
+ }
+
+ /*
+ * We only return the object name if it can be used (together
+ * with the schema name, if any) as an unique identifier.
+ */
+ if (get_object_namensp_unique(address.classId))
+ {
+ nameAttnum = get_object_attnum_name(address.classId);
+ if (nameAttnum != InvalidAttrNumber)
+ {
+ Datum nameDatum;
+
+ nameDatum = heap_getattr(objtup, nameAttnum,
+ RelationGetDescr(catalog), &isnull);
+ if (isnull)
+ elog(ERROR, "invalid null name in object %u/%u/%d",
+ address.classId, address.objectId, address.objectSubId);
+ objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
+ }
+ }
+ }
+
+ heap_close(catalog, AccessShareLock);
+ }
+
+ /* object type */
+ values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
+ nulls[0] = false;
+
+ /* schema name */
+ if (OidIsValid(schema_oid))
+ {
+ const char *schema = quote_identifier(get_namespace_name(schema_oid));
+
+ values[1] = CStringGetTextDatum(schema);
+ nulls[1] = false;
+ }
+ else
+ nulls[1] = true;
+
+ /* object name */
+ if (objname)
+ {
+ values[2] = CStringGetTextDatum(objname);
+ nulls[2] = false;
+ }
+ else
+ nulls[2] = true;
+
+ /* object identity */
+ values[3] = CStringGetTextDatum(getObjectIdentity(&address));
+ nulls[3] = false;
+
+ htup = heap_form_tuple(tupdesc, values, nulls);
+
+ PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+}
+
+/*
+ * Return a palloc'ed string that describes the type of object that the
+ * passed address is for.
+ */
+char *
+getObjectTypeDescription(const ObjectAddress *object)
+{
+ StringInfoData buffer;
+
+ initStringInfo(&buffer);
+
+ switch (getObjectClass(object))
+ {
+ case OCLASS_CLASS:
+ getRelationTypeDescription(&buffer, object->objectId,
+ object->objectSubId);
+ break;
+
+ case OCLASS_PROC:
+ getProcedureTypeDescription(&buffer, object->objectId);
+ break;
+
+ case OCLASS_TYPE:
+ appendStringInfo(&buffer, "type");
+ break;
+
+ case OCLASS_CAST:
+ appendStringInfo(&buffer, "cast");
+ break;
+
+ case OCLASS_COLLATION:
+ appendStringInfo(&buffer, "collation");
+ break;
+
+ case OCLASS_CONSTRAINT:
+ getConstraintTypeDescription(&buffer, object->objectId);
+ break;
+
+ case OCLASS_CONVERSION:
+ appendStringInfo(&buffer, "conversion");
+ break;
+
+ case OCLASS_DEFAULT:
+ appendStringInfo(&buffer, "default value");
+ break;
+
+ case OCLASS_LANGUAGE:
+ appendStringInfo(&buffer, "language");
+ break;
+
+ case OCLASS_LARGEOBJECT:
+ appendStringInfo(&buffer, "large object");
+ break;
+
+ case OCLASS_OPERATOR:
+ appendStringInfo(&buffer, "operator");
+ break;
+
+ case OCLASS_OPCLASS:
+ appendStringInfo(&buffer, "operator class");
+ break;
+
+ case OCLASS_OPFAMILY:
+ appendStringInfo(&buffer, "operator family");
+ break;
+
+ case OCLASS_AMOP:
+ appendStringInfo(&buffer, "operator of access method");
+ break;
+
+ case OCLASS_AMPROC:
+ appendStringInfo(&buffer, "function of access method");
+ break;
+
+ case OCLASS_REWRITE:
+ appendStringInfo(&buffer, "rule");
+ break;
+
+ case OCLASS_TRIGGER:
+ appendStringInfo(&buffer, "trigger");
+ break;
+
+ case OCLASS_SCHEMA:
+ appendStringInfo(&buffer, "schema");
+ break;
+
+ case OCLASS_TSPARSER:
+ appendStringInfo(&buffer, "text search parser");
+ break;
+
+ case OCLASS_TSDICT:
+ appendStringInfo(&buffer, "text search dictionary");
+ break;
+
+ case OCLASS_TSTEMPLATE:
+ appendStringInfo(&buffer, "text search template");
+ break;
+
+ case OCLASS_TSCONFIG:
+ appendStringInfo(&buffer, "text search configuration");
+ break;
+
+ case OCLASS_ROLE:
+ appendStringInfo(&buffer, "role");
+ break;
+
+ case OCLASS_DATABASE:
+ appendStringInfo(&buffer, "database");
+ break;
+
+ case OCLASS_TBLSPACE:
+ appendStringInfo(&buffer, "tablespace");
+ break;
+
+ case OCLASS_FDW:
+ appendStringInfo(&buffer, "foreign-data wrapper");
+ break;
+
+ case OCLASS_FOREIGN_SERVER:
+ appendStringInfo(&buffer, "server");
+ break;
+
+ case OCLASS_USER_MAPPING:
+ appendStringInfo(&buffer, "user mapping");
+ break;
+
+ case OCLASS_DEFACL:
+ appendStringInfo(&buffer, "default acl");
+ break;
+
+ case OCLASS_EXTENSION:
+ appendStringInfo(&buffer, "extension");
+ break;
+
+ case OCLASS_EVENT_TRIGGER:
+ appendStringInfo(&buffer, "event trigger");
+ break;
+
+ default:
+ appendStringInfo(&buffer, "unrecognized %u", object->classId);
+ break;
+ }
+
+ return buffer.data;
+}
+
+/*
+ * subroutine for getObjectTypeDescription: describe a relation type
+ */
+static void
+getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
+{
+ HeapTuple relTup;
+ Form_pg_class relForm;
+
+ relTup = SearchSysCache1(RELOID,
+ ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(relTup))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+ switch (relForm->relkind)
+ {
+ case RELKIND_RELATION:
+ appendStringInfo(buffer, "table");
+ break;
+ case RELKIND_INDEX:
+ appendStringInfo(buffer, "index");
+ break;
+ case RELKIND_SEQUENCE:
+ appendStringInfo(buffer, "sequence");
+ break;
+ case RELKIND_TOASTVALUE:
+ appendStringInfo(buffer, "toast table");
+ break;
+ case RELKIND_VIEW:
+ appendStringInfo(buffer, "view");
+ break;
+ case RELKIND_MATVIEW:
+ appendStringInfo(buffer, "materialized view");
+ break;
+ case RELKIND_COMPOSITE_TYPE:
+ appendStringInfo(buffer, "composite type");
+ break;
+ case RELKIND_FOREIGN_TABLE:
+ appendStringInfo(buffer, "foreign table");
+ break;
+ default:
+ /* shouldn't get here */
+ appendStringInfo(buffer, "relation");
+ break;
+ }
+
+ if (objectSubId != 0)
+ appendStringInfo(buffer, " column");
+
+ ReleaseSysCache(relTup);
+}
+
+/*
+ * subroutine for getObjectTypeDescription: describe a constraint type
+ */
+static void
+getConstraintTypeDescription(StringInfo buffer, Oid constroid)
+{
+ Relation constrRel;
+ HeapTuple constrTup;
+ Form_pg_constraint constrForm;
+
+ constrRel = heap_open(ConstraintRelationId, AccessShareLock);
+ constrTup = get_catalog_object_by_oid(constrRel, constroid);
+ if (!HeapTupleIsValid(constrTup))
+ elog(ERROR, "cache lookup failed for constraint %u", constroid);
+
+ constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
+
+ if (OidIsValid(constrForm->conrelid))
+ appendStringInfoString(buffer, "table constraint");
+ else if (OidIsValid(constrForm->contypid))
+ appendStringInfoString(buffer, "domain constraint");
+ else
+ elog(ERROR, "invalid constraint %u", HeapTupleGetOid(constrTup));
+
+ heap_close(constrRel, AccessShareLock);
+}
+
+/*
+ * subroutine for getObjectTypeDescription: describe a procedure type
+ */
+static void
+getProcedureTypeDescription(StringInfo buffer, Oid procid)
+{
+ HeapTuple procTup;
+ Form_pg_proc procForm;
+
+ procTup = SearchSysCache1(PROCOID,
+ ObjectIdGetDatum(procid));
+ if (!HeapTupleIsValid(procTup))
+ elog(ERROR, "cache lookup failed for procedure %u", procid);
+ procForm = (Form_pg_proc) GETSTRUCT(procTup);
+
+ if (procForm->proisagg)
+ appendStringInfo(buffer, "aggregate");
+ else
+ appendStringInfo(buffer, "function");
+
+ ReleaseSysCache(procTup);
+}
+
+/*
+ * Return a palloc'ed string that identifies an object.
+ *
+ * This is for machine consumption, so it's not translated. All elements are
+ * schema-qualified when appropriate.
+ */
+char *
+getObjectIdentity(const ObjectAddress *object)
+{
+ StringInfoData buffer;
+
+ initStringInfo(&buffer);
+
+ switch (getObjectClass(object))
+ {
+ case OCLASS_CLASS:
+ getRelationIdentity(&buffer, object->objectId);
+ if (object->objectSubId != 0)
+ {
+ char *attr;
+
+ attr = get_relid_attribute_name(object->objectId,
+ object->objectSubId);
+ appendStringInfo(&buffer, ".%s", quote_identifier(attr));
+ }
+ break;
+
+ case OCLASS_PROC:
+ appendStringInfo(&buffer, "%s",
+ format_procedure_qualified(object->objectId));
+ break;
+
+ case OCLASS_TYPE:
+ appendStringInfo(&buffer, "%s",
+ format_type_be_qualified(object->objectId));
+ break;
+
+ case OCLASS_CAST:
+ {
+ Relation castRel;
+ HeapTuple tup;
+ Form_pg_cast castForm;
+
+ castRel = heap_open(CastRelationId, AccessShareLock);
+
+ tup = get_catalog_object_by_oid(castRel, object->objectId);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for cast %u",
+ object->objectId);
+
+ castForm = (Form_pg_cast) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, "(%s AS %s)",
+ format_type_be_qualified(castForm->castsource),
+ format_type_be_qualified(castForm->casttarget));
+
+ heap_close(castRel, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_COLLATION:
+ {
+ HeapTuple collTup;
+ Form_pg_collation coll;
+ char *schema;
+
+ collTup = SearchSysCache1(COLLOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(collTup))
+ elog(ERROR, "cache lookup failed for collation %u",
+ object->objectId);
+ coll = (Form_pg_collation) GETSTRUCT(collTup);
+ schema = get_namespace_name(coll->collnamespace);
+ appendStringInfoString(&buffer,
+ quote_qualified_identifier(schema,
+ NameStr(coll->collname)));
+ ReleaseSysCache(collTup);
+ break;
+ }
+
+ case OCLASS_CONSTRAINT:
+ {
+ HeapTuple conTup;
+ Form_pg_constraint con;
+
+ conTup = SearchSysCache1(CONSTROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(conTup))
+ elog(ERROR, "cache lookup failed for constraint %u",
+ object->objectId);
+ con = (Form_pg_constraint) GETSTRUCT(conTup);
+
+ if (OidIsValid(con->conrelid))
+ {
+ appendStringInfo(&buffer, "%s on ",
+ quote_identifier(NameStr(con->conname)));
+ getRelationIdentity(&buffer, con->conrelid);
+ }
+ else
+ {
+ ObjectAddress domain;
+
+ domain.classId = TypeRelationId;
+ domain.objectId = con->contypid;
+ domain.objectSubId = 0;
+
+ appendStringInfo(&buffer, "%s on %s",
+ quote_identifier(NameStr(con->conname)),
+ getObjectIdentity(&domain));
+ }
+
+ ReleaseSysCache(conTup);
+ break;
+ }
+
+ case OCLASS_CONVERSION:
+ {
+ HeapTuple conTup;
+ Form_pg_conversion conForm;
+
+ conTup = SearchSysCache1(CONVOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(conTup))
+ elog(ERROR, "cache lookup failed for conversion %u",
+ object->objectId);
+ conForm = (Form_pg_conversion) GETSTRUCT(conTup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(conForm->conname)));
+ ReleaseSysCache(conTup);
+ break;
+ }
+
+ case OCLASS_DEFAULT:
+ {
+ Relation attrdefDesc;
+ ScanKeyData skey[1];
+ SysScanDesc adscan;
+
+ HeapTuple tup;
+ Form_pg_attrdef attrdef;
+ ObjectAddress colobject;
+
+ attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
+ true, SnapshotNow, 1, skey);
+
+ tup = systable_getnext(adscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for attrdef %u",
+ object->objectId);
+
+ attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
+
+ colobject.classId = RelationRelationId;
+ colobject.objectId = attrdef->adrelid;
+ colobject.objectSubId = attrdef->adnum;
+
+ appendStringInfo(&buffer, "for %s",
+ getObjectIdentity(&colobject));
+
+ systable_endscan(adscan);
+ heap_close(attrdefDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_LANGUAGE:
+ {
+ HeapTuple langTup;
+ Form_pg_language langForm;
+
+ langTup = SearchSysCache1(LANGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(langTup))
+ elog(ERROR, "cache lookup failed for language %u",
+ object->objectId);
+ langForm = (Form_pg_language) GETSTRUCT(langTup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(langForm->lanname)));
+ ReleaseSysCache(langTup);
+ break;
+ }
+ case OCLASS_LARGEOBJECT:
+ appendStringInfo(&buffer, "%u",
+ object->objectId);
+ break;
+
+ case OCLASS_OPERATOR:
+ appendStringInfo(&buffer, "%s",
+ format_operator_qualified(object->objectId));
+ break;
+
+ case OCLASS_OPCLASS:
+ {
+ HeapTuple opcTup;
+ Form_pg_opclass opcForm;
+ HeapTuple amTup;
+ Form_pg_am amForm;
+ char *schema;
+
+ opcTup = SearchSysCache1(CLAOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(opcTup))
+ elog(ERROR, "cache lookup failed for opclass %u",
+ object->objectId);
+ opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
+ schema = get_namespace_name(opcForm->opcnamespace);
+
+ amTup = SearchSysCache1(AMOID,
+ ObjectIdGetDatum(opcForm->opcmethod));
+ if (!HeapTupleIsValid(amTup))
+ elog(ERROR, "cache lookup failed for access method %u",
+ opcForm->opcmethod);
+ amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+ appendStringInfo(&buffer,
+ "%s",
+ quote_qualified_identifier(schema,
+ NameStr(opcForm->opcname)));
+ appendStringInfo(&buffer, " for %s",
+ quote_identifier(NameStr(amForm->amname)));
+
+ ReleaseSysCache(amTup);
+ ReleaseSysCache(opcTup);
+ break;
+ }
+
+ case OCLASS_OPFAMILY:
+ getOpFamilyIdentity(&buffer, object->objectId);
+ break;
+
+ case OCLASS_AMOP:
+ {
+ Relation amopDesc;
+ HeapTuple tup;
+ ScanKeyData skey[1];
+ SysScanDesc amscan;
+ Form_pg_amop amopForm;
+ StringInfoData opfam;
+
+ amopDesc = heap_open(AccessMethodOperatorRelationId,
+ AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ tup = systable_getnext(amscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for amop entry %u",
+ object->objectId);
+
+ amopForm = (Form_pg_amop) GETSTRUCT(tup);
+
+ initStringInfo(&opfam);
+ getOpFamilyIdentity(&opfam, amopForm->amopfamily);
+
+ appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
+ amopForm->amopstrategy,
+ format_type_be_qualified(amopForm->amoplefttype),
+ format_type_be_qualified(amopForm->amoprighttype),
+ opfam.data);
+
+ pfree(opfam.data);
+
+ systable_endscan(amscan);
+ heap_close(amopDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_AMPROC:
+ {
+ Relation amprocDesc;
+ ScanKeyData skey[1];
+ SysScanDesc amscan;
+ HeapTuple tup;
+ Form_pg_amproc amprocForm;
+ StringInfoData opfam;
+
+ amprocDesc = heap_open(AccessMethodProcedureRelationId,
+ AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ tup = systable_getnext(amscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for amproc entry %u",
+ object->objectId);
+
+ amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
+
+ initStringInfo(&opfam);
+ getOpFamilyIdentity(&opfam, amprocForm->amprocfamily);
+
+ appendStringInfo(&buffer, "function %d (%s, %s) of %s",
+ amprocForm->amprocnum,
+ format_type_be_qualified(amprocForm->amproclefttype),
+ format_type_be_qualified(amprocForm->amprocrighttype),
+ opfam.data);
+
+ pfree(opfam.data);
+
+ systable_endscan(amscan);
+ heap_close(amprocDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_REWRITE:
+ {
+ Relation ruleDesc;
+ HeapTuple tup;
+ Form_pg_rewrite rule;
+
+ ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
+
+ tup = get_catalog_object_by_oid(ruleDesc, object->objectId);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for rule %u",
+ object->objectId);
+
+ rule = (Form_pg_rewrite) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, "%s on ",
+ quote_identifier(NameStr(rule->rulename)));
+ getRelationIdentity(&buffer, rule->ev_class);
+
+ heap_close(ruleDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_TRIGGER:
+ {
+ Relation trigDesc;
+ HeapTuple tup;
+ Form_pg_trigger trig;
+
+ trigDesc = heap_open(TriggerRelationId, AccessShareLock);
+
+ tup = get_catalog_object_by_oid(trigDesc, object->objectId);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for trigger %u",
+ object->objectId);
+
+ trig = (Form_pg_trigger) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer, "%s on ",
+ quote_identifier(NameStr(trig->tgname)));
+ getRelationIdentity(&buffer, trig->tgrelid);
+
+ heap_close(trigDesc, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_SCHEMA:
+ {
+ char *nspname;
+
+ nspname = get_namespace_name(object->objectId);
+ if (!nspname)
+ elog(ERROR, "cache lookup failed for namespace %u",
+ object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(nspname));
+ break;
+ }
+
+ case OCLASS_TSPARSER:
+ {
+ HeapTuple tup;
+ Form_pg_ts_parser formParser;
+
+ tup = SearchSysCache1(TSPARSEROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search parser %u",
+ object->objectId);
+ formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(formParser->prsname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSDICT:
+ {
+ HeapTuple tup;
+ Form_pg_ts_dict formDict;
+
+ tup = SearchSysCache1(TSDICTOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search dictionary %u",
+ object->objectId);
+ formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(formDict->dictname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSTEMPLATE:
+ {
+ HeapTuple tup;
+ Form_pg_ts_template formTmpl;
+
+ tup = SearchSysCache1(TSTEMPLATEOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search template %u",
+ object->objectId);
+ formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(formTmpl->tmplname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_TSCONFIG:
+ {
+ HeapTuple tup;
+ Form_pg_ts_config formCfg;
+
+ tup = SearchSysCache1(TSCONFIGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for text search configuration %u",
+ object->objectId);
+ formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(formCfg->cfgname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ case OCLASS_ROLE:
+ {
+ char *username;
+
+ username = GetUserNameFromId(object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(username));
+ break;
+ }
+
+ case OCLASS_DATABASE:
+ {
+ char *datname;
+
+ datname = get_database_name(object->objectId);
+ if (!datname)
+ elog(ERROR, "cache lookup failed for database %u",
+ object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(datname));
+ break;
+ }
+
+ case OCLASS_TBLSPACE:
+ {
+ char *tblspace;
+
+ tblspace = get_tablespace_name(object->objectId);
+ if (!tblspace)
+ elog(ERROR, "cache lookup failed for tablespace %u",
+ object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(tblspace));
+ break;
+ }
+
+ case OCLASS_FDW:
+ {
+ ForeignDataWrapper *fdw;
+
+ fdw = GetForeignDataWrapper(object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(fdw->fdwname));
+ break;
+ }
+
+ case OCLASS_FOREIGN_SERVER:
+ {
+ ForeignServer *srv;
+
+ srv = GetForeignServer(object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(srv->servername));
+ break;
+ }
+
+ case OCLASS_USER_MAPPING:
+ {
+ HeapTuple tup;
+ Oid useid;
+ const char *usename;
+
+ tup = SearchSysCache1(USERMAPPINGOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for user mapping %u",
+ object->objectId);
+
+ useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
+
+ ReleaseSysCache(tup);
+
+ if (OidIsValid(useid))
+ usename = quote_identifier(GetUserNameFromId(useid));
+ else
+ usename = "public";
+
+ appendStringInfo(&buffer, "%s", usename);
+ break;
+ }
+
+ case OCLASS_DEFACL:
+ {
+ Relation defaclrel;
+ ScanKeyData skey[1];
+ SysScanDesc rcscan;
+
+ HeapTuple tup;
+ Form_pg_default_acl defacl;
+
+ defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(object->objectId));
+
+ rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
+ true, SnapshotNow, 1, skey);
+
+ tup = systable_getnext(rcscan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for default ACL %u",
+ object->objectId);
+
+ defacl = (Form_pg_default_acl) GETSTRUCT(tup);
+
+ appendStringInfo(&buffer,
+ "for role %s",
+ quote_identifier(GetUserNameFromId(defacl->defaclrole)));
+
+ if (OidIsValid(defacl->defaclnamespace))
+ {
+ char *schema;
+
+ schema = get_namespace_name(defacl->defaclnamespace);
+ appendStringInfo(&buffer,
+ " in schema %s",
+ quote_identifier(schema));
+ }
+
+ switch (defacl->defaclobjtype)
+ {
+ case DEFACLOBJ_RELATION:
+ appendStringInfoString(&buffer,
+ " on tables");
+ break;
+ case DEFACLOBJ_SEQUENCE:
+ appendStringInfoString(&buffer,
+ " on sequences");
+ break;
+ case DEFACLOBJ_FUNCTION:
+ appendStringInfoString(&buffer,
+ " on functions");
+ break;
+ case DEFACLOBJ_TYPE:
+ appendStringInfoString(&buffer,
+ " on types");
+ break;
+ }
+
+ systable_endscan(rcscan);
+ heap_close(defaclrel, AccessShareLock);
+ break;
+ }
+
+ case OCLASS_EXTENSION:
+ {
+ char *extname;
+
+ extname = get_extension_name(object->objectId);
+ if (!extname)
+ elog(ERROR, "cache lookup failed for extension %u",
+ object->objectId);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(extname));
+ break;
+ }
+
+ case OCLASS_EVENT_TRIGGER:
+ {
+ HeapTuple tup;
+ Form_pg_event_trigger trigForm;
+
+ tup = SearchSysCache1(EVENTTRIGGEROID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for event trigger %u",
+ object->objectId);
+ trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
+ appendStringInfo(&buffer, "%s",
+ quote_identifier(NameStr(trigForm->evtname)));
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ default:
+ appendStringInfo(&buffer, "unrecognized object %u %u %d",
+ object->classId,
+ object->objectId,
+ object->objectSubId);
+ break;
+ }
+
+ return buffer.data;
+}
+
+static void
+getOpFamilyIdentity(StringInfo buffer, Oid opfid)
+{
+ HeapTuple opfTup;
+ Form_pg_opfamily opfForm;
+ HeapTuple amTup;
+ Form_pg_am amForm;
+ char *schema;
+
+ opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
+ if (!HeapTupleIsValid(opfTup))
+ elog(ERROR, "cache lookup failed for opfamily %u", opfid);
+ opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
+
+ amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
+ if (!HeapTupleIsValid(amTup))
+ elog(ERROR, "cache lookup failed for access method %u",
+ opfForm->opfmethod);
+ amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+ schema = get_namespace_name(opfForm->opfnamespace);
+ appendStringInfo(buffer, "%s for %s",
+ quote_qualified_identifier(schema,
+ NameStr(opfForm->opfname)),
+ NameStr(amForm->amname));
+
+ ReleaseSysCache(amTup);
+ ReleaseSysCache(opfTup);
+}
+
+/*
+ * Append the relation identity (quoted qualified name) to the given
+ * StringInfo.
+ */
+static void
+getRelationIdentity(StringInfo buffer, Oid relid)
+{
+ HeapTuple relTup;
+ Form_pg_class relForm;
+ char *schema;
+
+ relTup = SearchSysCache1(RELOID,
+ ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(relTup))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+ schema = get_namespace_name(relForm->relnamespace);
+ appendStringInfo(buffer, "%s",
+ quote_qualified_identifier(schema,
+ NameStr(relForm->relname)));
+
+ ReleaseSysCache(relTup);
+}