mirror of https://github.com/postgres/postgres
Review by Alvaro Herrera, KaiGai Kohei, and Tom Lane.pull/1/head
parent
73b3bd5574
commit
c10575ff00
@ -0,0 +1,654 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* objectaddress.c |
||||
* functions for working with ObjectAddresses |
||||
* |
||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* $PostgreSQL: pgsql/src/backend/catalog/objectaddress.c,v 1.1 2010/08/27 11:47:41 rhaas Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#include "access/heapam.h" |
||||
#include "access/sysattr.h" |
||||
#include "catalog/catalog.h" |
||||
#include "catalog/dependency.h" |
||||
#include "catalog/indexing.h" |
||||
#include "catalog/namespace.h" |
||||
#include "catalog/objectaddress.h" |
||||
#include "catalog/pg_authid.h" |
||||
#include "catalog/pg_cast.h" |
||||
#include "catalog/pg_class.h" |
||||
#include "catalog/pg_constraint.h" |
||||
#include "catalog/pg_conversion.h" |
||||
#include "catalog/pg_database.h" |
||||
#include "catalog/pg_language.h" |
||||
#include "catalog/pg_largeobject.h" |
||||
#include "catalog/pg_largeobject_metadata.h" |
||||
#include "catalog/pg_namespace.h" |
||||
#include "catalog/pg_opclass.h" |
||||
#include "catalog/pg_opfamily.h" |
||||
#include "catalog/pg_operator.h" |
||||
#include "catalog/pg_proc.h" |
||||
#include "catalog/pg_rewrite.h" |
||||
#include "catalog/pg_tablespace.h" |
||||
#include "catalog/pg_trigger.h" |
||||
#include "catalog/pg_ts_config.h" |
||||
#include "catalog/pg_ts_dict.h" |
||||
#include "catalog/pg_ts_parser.h" |
||||
#include "catalog/pg_ts_template.h" |
||||
#include "catalog/pg_type.h" |
||||
#include "commands/dbcommands.h" |
||||
#include "commands/defrem.h" |
||||
#include "commands/proclang.h" |
||||
#include "commands/tablespace.h" |
||||
#include "commands/trigger.h" |
||||
#include "nodes/makefuncs.h" |
||||
#include "parser/parse_func.h" |
||||
#include "parser/parse_oper.h" |
||||
#include "parser/parse_type.h" |
||||
#include "rewrite/rewriteSupport.h" |
||||
#include "storage/lmgr.h" |
||||
#include "utils/acl.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/fmgroids.h" |
||||
#include "utils/lsyscache.h" |
||||
#include "utils/syscache.h" |
||||
#include "utils/rel.h" |
||||
#include "utils/tqual.h" |
||||
|
||||
static ObjectAddress get_object_address_unqualified(ObjectType objtype, |
||||
List *qualname); |
||||
static Relation get_relation_by_qualified_name(ObjectType objtype, |
||||
List *objname, LOCKMODE lockmode); |
||||
static ObjectAddress get_object_address_relobject(ObjectType objtype, |
||||
List *objname, Relation *relp); |
||||
static ObjectAddress get_object_address_attribute(ObjectType objtype, |
||||
List *objname, Relation *relp, LOCKMODE lockmode); |
||||
static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname, |
||||
List *objargs); |
||||
static bool object_exists(ObjectAddress address); |
||||
|
||||
/*
|
||||
* Translate an object name and arguments (as passed by the parser) to an |
||||
* ObjectAddress. |
||||
* |
||||
* The returned object will be locked using the specified lockmode. If a |
||||
* sub-object is looked up, the parent object will be locked instead. |
||||
* |
||||
* If the object is a relation or a child object of a relation (e.g. an |
||||
* attribute or contraint), the relation is also opened and *relp receives |
||||
* the open relcache entry pointer; otherwise, *relp is set to NULL. This |
||||
* is a bit grotty but it makes life simpler, since the caller will |
||||
* typically need the relcache entry too. Caller must close the relcache |
||||
* entry when done with it. The relation is locked with the specified lockmode |
||||
* if the target object is the relation itself or an attribute, but for other |
||||
* child objects, only AccessShareLock is acquired on the relation. |
||||
* |
||||
* We don't currently provide a function to release the locks acquired here; |
||||
* typically, the lock must be held until commit to guard against a concurrent |
||||
* drop operation. |
||||
*/ |
||||
ObjectAddress |
||||
get_object_address(ObjectType objtype, List *objname, List *objargs, |
||||
Relation *relp, LOCKMODE lockmode) |
||||
{ |
||||
ObjectAddress address; |
||||
Relation relation = NULL; |
||||
|
||||
/* Some kind of lock must be taken. */ |
||||
Assert(lockmode != NoLock); |
||||
|
||||
switch (objtype) |
||||
{ |
||||
case OBJECT_INDEX: |
||||
case OBJECT_SEQUENCE: |
||||
case OBJECT_TABLE: |
||||
case OBJECT_VIEW: |
||||
relation = |
||||
get_relation_by_qualified_name(objtype, objname, lockmode); |
||||
address.classId = RelationRelationId; |
||||
address.objectId = RelationGetRelid(relation); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_COLUMN: |
||||
address = |
||||
get_object_address_attribute(objtype, objname, &relation, |
||||
lockmode); |
||||
break; |
||||
case OBJECT_RULE: |
||||
case OBJECT_TRIGGER: |
||||
case OBJECT_CONSTRAINT: |
||||
address = get_object_address_relobject(objtype, objname, &relation); |
||||
break; |
||||
case OBJECT_DATABASE: |
||||
case OBJECT_TABLESPACE: |
||||
case OBJECT_ROLE: |
||||
case OBJECT_SCHEMA: |
||||
case OBJECT_LANGUAGE: |
||||
address = get_object_address_unqualified(objtype, objname); |
||||
break; |
||||
case OBJECT_TYPE: |
||||
address.classId = TypeRelationId; |
||||
address.objectId = |
||||
typenameTypeId(NULL, makeTypeNameFromNameList(objname), NULL); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_AGGREGATE: |
||||
address.classId = ProcedureRelationId; |
||||
address.objectId = LookupAggNameTypeNames(objname, objargs, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_FUNCTION: |
||||
address.classId = ProcedureRelationId; |
||||
address.objectId = LookupFuncNameTypeNames(objname, objargs, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_OPERATOR: |
||||
Assert(list_length(objargs) == 2); |
||||
address.classId = OperatorRelationId; |
||||
address.objectId = |
||||
LookupOperNameTypeNames(NULL, objname, |
||||
(TypeName *) linitial(objargs), |
||||
(TypeName *) lsecond(objargs), |
||||
false, -1); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_CONVERSION: |
||||
address.classId = ConversionRelationId; |
||||
address.objectId = get_conversion_oid(objname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_OPCLASS: |
||||
case OBJECT_OPFAMILY: |
||||
address = get_object_address_opcf(objtype, objname, objargs); |
||||
break; |
||||
case OBJECT_LARGEOBJECT: |
||||
Assert(list_length(objname) == 1); |
||||
address.classId = LargeObjectRelationId; |
||||
address.objectId = oidparse(linitial(objname)); |
||||
address.objectSubId = 0; |
||||
if (!LargeObjectExists(address.objectId)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_UNDEFINED_OBJECT), |
||||
errmsg("large object %u does not exist", |
||||
address.objectId))); |
||||
break; |
||||
case OBJECT_CAST: |
||||
{ |
||||
TypeName *sourcetype = (TypeName *) linitial(objname); |
||||
TypeName *targettype = (TypeName *) linitial(objargs); |
||||
Oid sourcetypeid = typenameTypeId(NULL, sourcetype, NULL); |
||||
Oid targettypeid = typenameTypeId(NULL, targettype, NULL); |
||||
|
||||
address.classId = CastRelationId; |
||||
address.objectId = |
||||
get_cast_oid(sourcetypeid, targettypeid, false); |
||||
address.objectSubId = 0; |
||||
} |
||||
break; |
||||
case OBJECT_TSPARSER: |
||||
address.classId = TSParserRelationId; |
||||
address.objectId = get_ts_parser_oid(objname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_TSDICTIONARY: |
||||
address.classId = TSDictionaryRelationId; |
||||
address.objectId = get_ts_dict_oid(objname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_TSTEMPLATE: |
||||
address.classId = TSTemplateRelationId; |
||||
address.objectId = get_ts_template_oid(objname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_TSCONFIGURATION: |
||||
address.classId = TSConfigRelationId; |
||||
address.objectId = get_ts_config_oid(objname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
default: |
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype); |
||||
} |
||||
|
||||
/*
|
||||
* If we're dealing with a relation or attribute, then the relation is |
||||
* already locked. If we're dealing with any other type of object, we need |
||||
* to lock it and then verify that it still exists. |
||||
*/ |
||||
if (address.classId != RelationRelationId) |
||||
{ |
||||
if (IsSharedRelation(address.classId)) |
||||
LockSharedObject(address.classId, address.objectId, 0, lockmode); |
||||
else |
||||
LockDatabaseObject(address.classId, address.objectId, 0, lockmode); |
||||
/* Did it go away while we were waiting for the lock? */ |
||||
if (!object_exists(address)) |
||||
elog(ERROR, "cache lookup failed for class %u object %u subobj %d", |
||||
address.classId, address.objectId, address.objectSubId); |
||||
} |
||||
|
||||
/* Return the object address and the relation. */ |
||||
*relp = relation; |
||||
return address; |
||||
} |
||||
|
||||
/*
|
||||
* Find an ObjectAddress for a type of object that is identified by an |
||||
* unqualified name. |
||||
*/ |
||||
static ObjectAddress |
||||
get_object_address_unqualified(ObjectType objtype, List *qualname) |
||||
{ |
||||
const char *name; |
||||
ObjectAddress address; |
||||
|
||||
/*
|
||||
* The types of names handled by this function are not permitted to be |
||||
* schema-qualified or catalog-qualified. |
||||
*/ |
||||
if (list_length(qualname) != 1) |
||||
{ |
||||
const char *msg; |
||||
|
||||
switch (objtype) |
||||
{ |
||||
case OBJECT_DATABASE: |
||||
msg = gettext_noop("database name cannot be qualified"); |
||||
break; |
||||
case OBJECT_TABLESPACE: |
||||
msg = gettext_noop("tablespace name cannot be qualified"); |
||||
break; |
||||
case OBJECT_ROLE: |
||||
msg = gettext_noop("role name cannot be qualified"); |
||||
break; |
||||
case OBJECT_SCHEMA: |
||||
msg = gettext_noop("schema name cannot be qualified"); |
||||
break; |
||||
case OBJECT_LANGUAGE: |
||||
msg = gettext_noop("language name cannot be qualified"); |
||||
break; |
||||
default: |
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype); |
||||
msg = NULL; /* placate compiler */ |
||||
} |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_SYNTAX_ERROR), |
||||
errmsg("%s", _(msg)))); |
||||
} |
||||
|
||||
/* Format is valid, extract the actual name. */ |
||||
name = strVal(linitial(qualname)); |
||||
|
||||
/* Translate name to OID. */ |
||||
switch (objtype) |
||||
{ |
||||
case OBJECT_DATABASE: |
||||
address.classId = DatabaseRelationId; |
||||
address.objectId = get_database_oid(name, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_TABLESPACE: |
||||
address.classId = TableSpaceRelationId; |
||||
address.objectId = get_tablespace_oid(name, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_ROLE: |
||||
address.classId = AuthIdRelationId; |
||||
address.objectId = get_role_oid(name, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_SCHEMA: |
||||
address.classId = NamespaceRelationId; |
||||
address.objectId = get_namespace_oid(name, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_LANGUAGE: |
||||
address.classId = LanguageRelationId; |
||||
address.objectId = get_language_oid(name, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
default: |
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype); |
||||
/* placate compiler, which doesn't know elog won't return */ |
||||
address.classId = InvalidOid; |
||||
address.objectId = InvalidOid; |
||||
address.objectSubId = 0; |
||||
} |
||||
|
||||
return address; |
||||
} |
||||
|
||||
/*
|
||||
* Locate a relation by qualified name. |
||||
*/ |
||||
static Relation |
||||
get_relation_by_qualified_name(ObjectType objtype, List *objname, |
||||
LOCKMODE lockmode) |
||||
{ |
||||
Relation relation; |
||||
|
||||
relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode); |
||||
switch (objtype) |
||||
{ |
||||
case OBJECT_INDEX: |
||||
if (relation->rd_rel->relkind != RELKIND_INDEX) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||
errmsg("\"%s\" is not an index", |
||||
RelationGetRelationName(relation)))); |
||||
break; |
||||
case OBJECT_SEQUENCE: |
||||
if (relation->rd_rel->relkind != RELKIND_SEQUENCE) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||
errmsg("\"%s\" is not a sequence", |
||||
RelationGetRelationName(relation)))); |
||||
break; |
||||
case OBJECT_TABLE: |
||||
if (relation->rd_rel->relkind != RELKIND_RELATION) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||
errmsg("\"%s\" is not a table", |
||||
RelationGetRelationName(relation)))); |
||||
break; |
||||
case OBJECT_VIEW: |
||||
if (relation->rd_rel->relkind != RELKIND_VIEW) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||
errmsg("\"%s\" is not a view", |
||||
RelationGetRelationName(relation)))); |
||||
break; |
||||
default: |
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype); |
||||
break; |
||||
} |
||||
|
||||
return relation; |
||||
} |
||||
|
||||
/*
|
||||
* Find object address for an object that is attached to a relation. |
||||
* |
||||
* Note that we take only an AccessShareLock on the relation. We need not |
||||
* pass down the LOCKMODE from get_object_address(), because that is the lock |
||||
* mode for the object itself, not the relation to which it is attached. |
||||
*/ |
||||
static ObjectAddress |
||||
get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp) |
||||
{ |
||||
ObjectAddress address; |
||||
Relation relation = NULL; |
||||
int nnames; |
||||
const char *depname; |
||||
|
||||
/* Extract name of dependent object. */ |
||||
depname = strVal(lfirst(list_tail(objname))); |
||||
|
||||
/* Separate relation name from dependent object name. */ |
||||
nnames = list_length(objname); |
||||
if (nnames < 2) |
||||
{ |
||||
Oid reloid; |
||||
|
||||
/*
|
||||
* For compatibility with very old releases, we sometimes allow users |
||||
* to attempt to specify a rule without mentioning the relation name. |
||||
* If there's only rule by that name in the entire database, this will |
||||
* work. But objects other than rules don't get this special |
||||
* treatment. |
||||
*/ |
||||
if (objtype != OBJECT_RULE) |
||||
elog(ERROR, "must specify relation and object name"); |
||||
address.classId = RewriteRelationId; |
||||
address.objectId = get_rewrite_oid_without_relid(depname, &reloid); |
||||
address.objectSubId = 0; |
||||
relation = heap_open(reloid, AccessShareLock); |
||||
} |
||||
else |
||||
{ |
||||
List *relname; |
||||
Oid reloid; |
||||
|
||||
/* Extract relation name and open relation. */ |
||||
relname = list_truncate(list_copy(objname), nnames - 1); |
||||
relation = heap_openrv(makeRangeVarFromNameList(relname), |
||||
AccessShareLock); |
||||
reloid = RelationGetRelid(relation); |
||||
|
||||
switch (objtype) |
||||
{ |
||||
case OBJECT_RULE: |
||||
address.classId = RewriteRelationId; |
||||
address.objectId = get_rewrite_oid(reloid, depname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_TRIGGER: |
||||
address.classId = TriggerRelationId; |
||||
address.objectId = get_trigger_oid(reloid, depname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_CONSTRAINT: |
||||
address.classId = ConstraintRelationId; |
||||
address.objectId = get_constraint_oid(reloid, depname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
default: |
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype); |
||||
/* placate compiler, which doesn't know elog won't return */ |
||||
address.classId = InvalidOid; |
||||
address.objectId = InvalidOid; |
||||
address.objectSubId = 0; |
||||
} |
||||
} |
||||
|
||||
/* Done. */ |
||||
*relp = relation; |
||||
return address; |
||||
} |
||||
|
||||
/*
|
||||
* Find the ObjectAddress for an attribute. |
||||
*/ |
||||
static ObjectAddress |
||||
get_object_address_attribute(ObjectType objtype, List *objname, |
||||
Relation *relp, LOCKMODE lockmode) |
||||
{ |
||||
ObjectAddress address; |
||||
List *relname; |
||||
Oid reloid; |
||||
Relation relation; |
||||
const char *attname; |
||||
|
||||
/* Extract relation name and open relation. */ |
||||
attname = strVal(lfirst(list_tail(objname))); |
||||
relname = list_truncate(list_copy(objname), list_length(objname) - 1); |
||||
relation = heap_openrv(makeRangeVarFromNameList(relname), lockmode); |
||||
reloid = RelationGetRelid(relation); |
||||
|
||||
/* Look up attribute and construct return value. */ |
||||
address.classId = RelationRelationId; |
||||
address.objectId = reloid; |
||||
address.objectSubId = get_attnum(reloid, attname); |
||||
if (address.objectSubId == InvalidAttrNumber) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_UNDEFINED_COLUMN), |
||||
errmsg("column \"%s\" of relation \"%s\" does not exist", |
||||
attname, RelationGetRelationName(relation)))); |
||||
|
||||
*relp = relation; |
||||
return address; |
||||
} |
||||
|
||||
/*
|
||||
* Find the ObjectAddress for an opclass or opfamily. |
||||
*/ |
||||
static ObjectAddress |
||||
get_object_address_opcf(ObjectType objtype, List *objname, List *objargs) |
||||
{ |
||||
Oid amoid; |
||||
ObjectAddress address; |
||||
|
||||
Assert(list_length(objargs) == 1); |
||||
amoid = get_am_oid(strVal(linitial(objargs)), false); |
||||
|
||||
switch (objtype) |
||||
{ |
||||
case OBJECT_OPCLASS: |
||||
address.classId = OperatorClassRelationId; |
||||
address.objectId = get_opclass_oid(amoid, objname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
case OBJECT_OPFAMILY: |
||||
address.classId = OperatorFamilyRelationId; |
||||
address.objectId = get_opfamily_oid(amoid, objname, false); |
||||
address.objectSubId = 0; |
||||
break; |
||||
default: |
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype); |
||||
/* placate compiler, which doesn't know elog won't return */ |
||||
address.classId = InvalidOid; |
||||
address.objectId = InvalidOid; |
||||
address.objectSubId = 0; |
||||
} |
||||
|
||||
return address; |
||||
} |
||||
|
||||
/*
|
||||
* Test whether an object exists. |
||||
*/ |
||||
static bool |
||||
object_exists(ObjectAddress address) |
||||
{ |
||||
int cache = -1; |
||||
Oid indexoid = InvalidOid; |
||||
Relation rel; |
||||
ScanKeyData skey[1]; |
||||
SysScanDesc sd; |
||||
bool found; |
||||
|
||||
/* Sub-objects require special treatment. */ |
||||
if (address.objectSubId != 0) |
||||
{ |
||||
HeapTuple atttup; |
||||
|
||||
/* Currently, attributes are the only sub-objects. */ |
||||
Assert(address.classId == RelationRelationId); |
||||
atttup = SearchSysCache2(ATTNUM, ObjectIdGetDatum(address.objectId), |
||||
Int16GetDatum(address.objectSubId)); |
||||
if (!HeapTupleIsValid(atttup)) |
||||
found = false; |
||||
else |
||||
{ |
||||
found = ((Form_pg_attribute) GETSTRUCT(atttup))->attisdropped; |
||||
ReleaseSysCache(atttup);
|
||||
} |
||||
return found; |
||||
} |
||||
|
||||
/*
|
||||
* For object types that have a relevant syscache, we use it; for |
||||
* everything else, we'll have to do an index-scan. This switch |
||||
* sets either the cache to be used for the syscache lookup, or the |
||||
* index to be used for the index scan. |
||||
*/ |
||||
switch (address.classId) |
||||
{ |
||||
case RelationRelationId: |
||||
cache = RELOID; |
||||
break; |
||||
case RewriteRelationId: |
||||
indexoid = RewriteOidIndexId; |
||||
break; |
||||
case TriggerRelationId: |
||||
indexoid = TriggerOidIndexId; |
||||
break; |
||||
case ConstraintRelationId: |
||||
cache = CONSTROID; |
||||
break; |
||||
case DatabaseRelationId: |
||||
cache = DATABASEOID; |
||||
break; |
||||
case TableSpaceRelationId: |
||||
cache = TABLESPACEOID; |
||||
break; |
||||
case AuthIdRelationId: |
||||
cache = AUTHOID; |
||||
break; |
||||
case NamespaceRelationId: |
||||
cache = NAMESPACEOID; |
||||
break; |
||||
case LanguageRelationId: |
||||
cache = LANGOID; |
||||
break; |
||||
case TypeRelationId: |
||||
cache = TYPEOID; |
||||
break; |
||||
case ProcedureRelationId: |
||||
cache = PROCOID; |
||||
break; |
||||
case OperatorRelationId: |
||||
cache = OPEROID; |
||||
break; |
||||
case ConversionRelationId: |
||||
cache = CONVOID; |
||||
break; |
||||
case OperatorClassRelationId: |
||||
cache = CLAOID; |
||||
break; |
||||
case OperatorFamilyRelationId: |
||||
cache = OPFAMILYOID; |
||||
break; |
||||
case LargeObjectRelationId: |
||||
/*
|
||||
* Weird backward compatibility hack: ObjectAddress notation uses |
||||
* LargeObjectRelationId for large objects, but since PostgreSQL |
||||
* 9.0, the relevant catalog is actually |
||||
* LargeObjectMetadataRelationId. |
||||
*/ |
||||
address.classId = LargeObjectMetadataRelationId; |
||||
indexoid = LargeObjectMetadataOidIndexId; |
||||
break; |
||||
case CastRelationId: |
||||
indexoid = CastOidIndexId; |
||||
break; |
||||
case TSParserRelationId: |
||||
cache = TSPARSEROID; |
||||
break; |
||||
case TSDictionaryRelationId: |
||||
cache = TSDICTOID; |
||||
break; |
||||
case TSTemplateRelationId: |
||||
cache = TSTEMPLATEOID; |
||||
break; |
||||
case TSConfigRelationId: |
||||
cache = TSCONFIGOID; |
||||
break; |
||||
default: |
||||
elog(ERROR, "unrecognized classid: %u", address.classId); |
||||
} |
||||
|
||||
/* Found a syscache? */ |
||||
if (cache != -1) |
||||
return SearchSysCacheExists1(cache, ObjectIdGetDatum(address.objectId)); |
||||
|
||||
/* No syscache, so examine the table directly. */ |
||||
Assert(OidIsValid(indexoid)); |
||||
ScanKeyInit(&skey[0], |
||||
ObjectIdAttributeNumber, |
||||
BTEqualStrategyNumber, F_OIDEQ, |
||||
ObjectIdGetDatum(address.objectId)); |
||||
rel = heap_open(address.classId, AccessShareLock); |
||||
sd = systable_beginscan(rel, indexoid, true, SnapshotNow, 1, skey); |
||||
found = HeapTupleIsValid(systable_getnext(sd)); |
||||
systable_endscan(sd); |
||||
heap_close(rel, AccessShareLock); |
||||
return found;
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,33 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* objectaddress.h |
||||
* functions for working with object addresses |
||||
* |
||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* $PostgreSQL: pgsql/src/include/catalog/objectaddress.h,v 1.1 2010/08/27 11:47:41 rhaas Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef OBJECTADDRESS_H |
||||
#define OBJECTADDRESS_H |
||||
|
||||
#include "nodes/parsenodes.h" |
||||
#include "storage/lock.h" |
||||
#include "utils/rel.h" |
||||
|
||||
/*
|
||||
* An ObjectAddress represents a database object of any type. |
||||
*/ |
||||
typedef struct ObjectAddress |
||||
{ |
||||
Oid classId; /* Class Id from pg_class */ |
||||
Oid objectId; /* OID of the object */ |
||||
int32 objectSubId; /* Subitem within object (eg column), or 0 */ |
||||
} ObjectAddress; |
||||
|
||||
ObjectAddress get_object_address(ObjectType objtype, List *objname, |
||||
List *objargs, Relation *relp, LOCKMODE lockmode); |
||||
|
||||
#endif /* PARSE_OBJECT_H */ |
Loading…
Reference in new issue