Exemple #1
0
/*
 * 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 ACCESS_SHR_LOCK 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.
 */
struct objaddr
get_object_address(
	objtype_e objtype,
	struct list* objname,
	struct list* objargs,
	struct relation** relp,
	lockmode_t lockmode)
{
	struct objaddr address;
	struct relation* relation = NULL;

	/* Some kind of lock must be taken. */
	ASSERT(lockmode != NO_LOCK);

	switch (objtype) {
	case OBJECT_INDEX:
	case OBJECT_SEQUENCE:
	case OBJECT_TABLE:
	case OBJECT_VIEW:
	case OBJECT_FOREIGN_TABLE:
		relation = get_rel_by_qualified_name(objtype, objname, lockmode);
		address.classId = RelationRelationId;
		address.objectId = REL_ID(relation);
		address.objectSubId = 0;
		break;

	case OBJECT_COLUMN:
		address = get_objaddr_attr(objtype, objname, &relation, lockmode);
		break;

	case OBJECT_RULE:
	case OBJECT_TRIGGER:
	case OBJECT_CONSTRAINT:
		address = get_objaddr_relobj(objtype, objname, &relation);
		break;

	case OBJECT_DATABASE:
	case OBJECT_EXTENSION:
	case OBJECT_TABLESPACE:
	case OBJECT_ROLE:
	case OBJECT_SCHEMA:
	case OBJECT_LANGUAGE:
	case OBJECT_FDW:
	case OBJECT_FOREIGN_SERVER:
		address = get_objaddr_unqualified(objtype, objname);
		break;

	case OBJECT_TYPE:
	case OBJECT_DOMAIN:
		address.classId = TypeRelationId;
		address.objectId = typename_to_oid(NULL, makeTypeNameFromNameList(objname));
		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 = lookup_opr_name_type_names(
			NULL,
			objname,
			(type_name_n*) linitial(objargs),
			(type_name_n*) lsecond(objargs),
			false,
			-1);
		address.objectSubId = 0;
		break;

	case OBJECT_COLLATION:
		address.classId = CollationRelationId;
		address.objectId = get_collation_oid(objname, false);
		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_objaddr_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 (!large_obj_exists(address.objectId)) {
			ereport(ERROR, (
			errcode(E_UNDEFINED_OBJECT),
			errmsg("large object %u does not exist",
				address.objectId)));
		}
		break;

	case OBJECT_CAST: {
		type_name_n* sourcetype;
		type_name_n* targettype;
		oid_t sourcetypeid;
		oid_t targettypeid;

		sourcetype = (type_name_n*) linitial(objname);
		targettype = (type_name_n*) linitial(objargs);
		sourcetypeid = typename_to_oid(NULL, sourcetype);
		targettypeid = typename_to_oid(NULL, targettype);
		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);
		/* placate compiler, in case it thinks elog might return */
		address.classId = INVALID_OID;
		address.objectId = INVALID_OID;
		address.objectSubId = 0;
	}

	/*
	 * 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 (is_shared_rel(address.classId))
			lock_sobj(address.classId, address.objectId, 0, lockmode);
		else
			lock_db_obj(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;
}
/*
 * 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:
		case OBJECT_FOREIGN_TABLE:
			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_EXTENSION:
		case OBJECT_TABLESPACE:
		case OBJECT_ROLE:
		case OBJECT_SCHEMA:
		case OBJECT_LANGUAGE:
		case OBJECT_FDW:
		case OBJECT_FOREIGN_SERVER:
			address = get_object_address_unqualified(objtype, objname);
			break;
		case OBJECT_TYPE:
		case OBJECT_DOMAIN:
			address.classId = TypeRelationId;
			address.objectId =
				typenameTypeId(NULL, makeTypeNameFromNameList(objname));
			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_COLLATION:
			address.classId = CollationRelationId;
			address.objectId = get_collation_oid(objname, false);
			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);
				Oid targettypeid = typenameTypeId(NULL, targettype);

				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);
			/* placate compiler, in case it thinks elog might return */
			address.classId = InvalidOid;
			address.objectId = InvalidOid;
			address.objectSubId = 0;
	}

	/*
	 * 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;
}