in src/backend/catalog/objectaddress.c [979:1348]
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
Value *strval, bool missing_ok);
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
List *object, Relation *relp,
LOCKMODE lockmode, bool missing_ok);
static ObjectAddress get_object_address_relobject(ObjectType objtype,
List *object, Relation *relp, bool missing_ok);
static ObjectAddress get_object_address_attribute(ObjectType objtype,
List *object, Relation *relp,
LOCKMODE lockmode, bool missing_ok);
static ObjectAddress get_object_address_attrdef(ObjectType objtype,
List *object, Relation *relp, LOCKMODE lockmode,
bool missing_ok);
static ObjectAddress get_object_address_type(ObjectType objtype,
TypeName *typename, bool missing_ok);
static ObjectAddress get_object_address_opcf(ObjectType objtype, List *object,
bool missing_ok);
static ObjectAddress get_object_address_opf_member(ObjectType objtype,
List *object, bool missing_ok);
static ObjectAddress get_object_address_usermapping(List *object,
bool missing_ok);
static ObjectAddress get_object_address_publication_rel(List *object,
Relation *relp,
bool missing_ok);
static ObjectAddress get_object_address_defacl(List *object,
bool missing_ok);
static const ObjectPropertyType *get_object_property_data(Oid class_id);
static void getRelationDescription(StringInfo buffer, Oid relid,
bool missing_ok);
static void getOpFamilyDescription(StringInfo buffer, Oid opfid,
bool missing_ok);
static void getRelationTypeDescription(StringInfo buffer, Oid relid,
int32 objectSubId, bool missing_ok);
static void getProcedureTypeDescription(StringInfo buffer, Oid procid,
bool missing_ok);
static void getConstraintTypeDescription(StringInfo buffer, Oid constroid,
bool missing_ok);
static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
bool missing_ok);
static void getRelationIdentity(StringInfo buffer, Oid relid, List **object,
bool missing_ok);
/*
* 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 constraint), 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.
*
* If the object is not found, an error is thrown, unless missing_ok is
* true. In this case, no lock is acquired, relp is set to NULL, and the
* returned address has objectId set to InvalidOid.
*
* 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.
*
* Note: If the object is not found, we don't give any indication of the
* reason. (It might have been a missing schema if the name was qualified, or
* a nonexistent type name in case of a cast, function or operator; etc).
* Currently there is only one caller that might be interested in such info, so
* we don't spend much effort here. If more callers start to care, it might be
* better to add some support for that in this function.
*/
ObjectAddress
get_object_address(ObjectType objtype, Node *object,
Relation *relp, LOCKMODE lockmode, bool missing_ok)
{
ObjectAddress address;
ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
Relation relation = NULL;
uint64 inval_count;
/* Some kind of lock must be taken. */
Assert(lockmode != NoLock);
for (;;)
{
/*
* Remember this value, so that, after looking up the object name and
* locking it, we can check whether any invalidation messages have
* been processed that might require a do-over.
*/
inval_count = SharedInvalidMessageCounter;
/* Look up object address. */
switch (objtype)
{
case OBJECT_INDEX:
case OBJECT_SEQUENCE:
case OBJECT_TABLE:
case OBJECT_VIEW:
case OBJECT_MATVIEW:
case OBJECT_FOREIGN_TABLE:
case OBJECT_DIRECTORY_TABLE:
address =
get_relation_by_qualified_name(objtype, castNode(List, object),
&relation, lockmode,
missing_ok);
break;
case OBJECT_COLUMN:
address =
get_object_address_attribute(objtype, castNode(List, object),
&relation, lockmode,
missing_ok);
break;
case OBJECT_DEFAULT:
address =
get_object_address_attrdef(objtype, castNode(List, object),
&relation, lockmode,
missing_ok);
break;
case OBJECT_RULE:
case OBJECT_TRIGGER:
case OBJECT_TABCONSTRAINT:
case OBJECT_POLICY:
address = get_object_address_relobject(objtype, castNode(List, object),
&relation, missing_ok);
break;
case OBJECT_DOMCONSTRAINT:
{
List *objlist;
ObjectAddress domaddr;
char *constrname;
objlist = castNode(List, object);
domaddr = get_object_address_type(OBJECT_DOMAIN,
linitial_node(TypeName, objlist),
missing_ok);
constrname = strVal(lsecond(objlist));
address.classId = ConstraintRelationId;
address.objectId = get_domain_constraint_oid(domaddr.objectId,
constrname, missing_ok);
address.objectSubId = 0;
}
break;
case OBJECT_DATABASE:
case OBJECT_EXTENSION:
case OBJECT_TABLESPACE:
case OBJECT_TAG:
case OBJECT_ROLE:
case OBJECT_SCHEMA:
case OBJECT_LANGUAGE:
case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER:
case OBJECT_EVENT_TRIGGER:
case OBJECT_EXTPROTOCOL:
case OBJECT_ACCESS_METHOD:
case OBJECT_PUBLICATION:
case OBJECT_SUBSCRIPTION:
case OBJECT_RESQUEUE:
case OBJECT_RESGROUP:
case OBJECT_PROFILE:
case OBJECT_STORAGE_SERVER:
case OBJECT_STORAGE_USER_MAPPING:
address = get_object_address_unqualified(objtype,
(Value *) object, missing_ok);
break;
case OBJECT_TYPE:
case OBJECT_DOMAIN:
address = get_object_address_type(objtype, castNode(TypeName, object), missing_ok);
break;
case OBJECT_AGGREGATE:
case OBJECT_FUNCTION:
case OBJECT_PROCEDURE:
case OBJECT_ROUTINE:
address.classId = ProcedureRelationId;
address.objectId = LookupFuncWithArgs(objtype, castNode(ObjectWithArgs, object), missing_ok);
address.objectSubId = 0;
break;
case OBJECT_OPERATOR:
address.classId = OperatorRelationId;
address.objectId = LookupOperWithArgs(castNode(ObjectWithArgs, object), missing_ok);
address.objectSubId = 0;
break;
case OBJECT_COLLATION:
address.classId = CollationRelationId;
address.objectId = get_collation_oid(castNode(List, object), missing_ok);
address.objectSubId = 0;
break;
case OBJECT_CONVERSION:
address.classId = ConversionRelationId;
address.objectId = get_conversion_oid(castNode(List, object), missing_ok);
address.objectSubId = 0;
break;
case OBJECT_OPCLASS:
case OBJECT_OPFAMILY:
address = get_object_address_opcf(objtype, castNode(List, object), missing_ok);
break;
case OBJECT_AMOP:
case OBJECT_AMPROC:
address = get_object_address_opf_member(objtype, castNode(List, object), missing_ok);
break;
case OBJECT_LARGEOBJECT:
address.classId = LargeObjectRelationId;
address.objectId = oidparse(object);
address.objectSubId = 0;
if (!LargeObjectExists(address.objectId))
{
if (!missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("large object %u does not exist",
address.objectId)));
}
break;
case OBJECT_CAST:
{
TypeName *sourcetype = linitial_node(TypeName, castNode(List, object));
TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
Oid sourcetypeid;
Oid targettypeid;
sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
address.classId = CastRelationId;
address.objectId =
get_cast_oid(sourcetypeid, targettypeid, missing_ok);
address.objectSubId = 0;
}
break;
case OBJECT_TRANSFORM:
{
TypeName *typename = linitial_node(TypeName, castNode(List, object));
char *langname = strVal(lsecond(castNode(List, object)));
Oid type_id = LookupTypeNameOid(NULL, typename, missing_ok);
Oid lang_id = get_language_oid(langname, missing_ok);
address.classId = TransformRelationId;
address.objectId =
get_transform_oid(type_id, lang_id, missing_ok);
address.objectSubId = 0;
}
break;
case OBJECT_TSPARSER:
address.classId = TSParserRelationId;
address.objectId = get_ts_parser_oid(castNode(List, object), missing_ok);
address.objectSubId = 0;
break;
case OBJECT_TSDICTIONARY:
address.classId = TSDictionaryRelationId;
address.objectId = get_ts_dict_oid(castNode(List, object), missing_ok);
address.objectSubId = 0;
break;
case OBJECT_TSTEMPLATE:
address.classId = TSTemplateRelationId;
address.objectId = get_ts_template_oid(castNode(List, object), missing_ok);
address.objectSubId = 0;
break;
case OBJECT_TSCONFIGURATION:
address.classId = TSConfigRelationId;
address.objectId = get_ts_config_oid(castNode(List, object), missing_ok);
address.objectSubId = 0;
break;
case OBJECT_USER_MAPPING:
address = get_object_address_usermapping(castNode(List, object),
missing_ok);
break;
case OBJECT_PUBLICATION_REL:
address = get_object_address_publication_rel(castNode(List, object),
&relation,
missing_ok);
break;
case OBJECT_DEFACL:
address = get_object_address_defacl(castNode(List, object),
missing_ok);
break;
case OBJECT_STATISTIC_EXT:
address.classId = StatisticExtRelationId;
address.objectId = get_statistics_object_oid(castNode(List, object),
missing_ok);
address.objectSubId = 0;
break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
/* placate compiler, in case it thinks elog might return */
address.classId = InvalidOid;
address.objectId = InvalidOid;
address.objectSubId = 0;
}
/*
* If we could not find the supplied object, return without locking.
*/
if (!OidIsValid(address.objectId))
{
Assert(missing_ok);
return address;
}
/*
* If we're retrying, see if we got the same answer as last time. If
* so, we're done; if not, we locked the wrong thing, so give up our
* lock.
*/
if (OidIsValid(old_address.classId))
{
if (old_address.classId == address.classId
&& old_address.objectId == address.objectId
&& old_address.objectSubId == address.objectSubId)
break;
if (old_address.classId != RelationRelationId)
{
if (IsSharedRelation(old_address.classId))
UnlockSharedObject(old_address.classId,
old_address.objectId,
0, lockmode);
else
UnlockDatabaseObject(old_address.classId,
old_address.objectId,
0, lockmode);
}
}
/*
* If we're dealing with a relation or attribute, then the relation is
* already locked. Otherwise, we lock it now.
*/
if (address.classId != RelationRelationId)
{
if (IsSharedRelation(address.classId))
LockSharedObject(address.classId, address.objectId, 0,
lockmode);
else
LockDatabaseObject(address.classId, address.objectId, 0,
lockmode);
}
/*
* At this point, we've resolved the name to an OID and locked the
* corresponding database object. However, it's possible that by the
* time we acquire the lock on the object, concurrent DDL has modified
* the database in such a way that the name we originally looked up no
* longer resolves to that OID.
*
* We can be certain that this isn't an issue if (a) no shared
* invalidation messages have been processed or (b) we've locked a
* relation somewhere along the line. All the relation name lookups
* in this module ultimately use RangeVarGetRelid() to acquire a
* relation lock, and that function protects against the same kinds of
* races we're worried about here. Even when operating on a
* constraint, rule, or trigger, we still acquire AccessShareLock on
* the relation, which is enough to freeze out any concurrent DDL.
*
* In all other cases, however, it's possible that the name we looked
* up no longer refers to the object we locked, so we retry the lookup
* and see whether we get the same answer.
*/
if (inval_count == SharedInvalidMessageCounter || relation != NULL)
break;
old_address = address;
}
/* Return the object address and the relation. */
*relp = relation;
return address;
}