Ejemplo n.º 1
0
def range_for_typeref(typeref: irast.TypeRef,
                      path_id: irast.PathId,
                      *,
                      include_overlays: bool = True,
                      include_descendants: bool = True,
                      dml_source: Optional[irast.MutatingStmt] = None,
                      common_parent: bool = False,
                      ctx: context.CompilerContextLevel) -> pgast.PathRangeVar:

    if typeref.common_parent is not None and common_parent:
        rvar = range_for_material_objtype(
            typeref.common_parent,
            path_id,
            include_overlays=include_overlays,
            include_descendants=include_descendants,
            dml_source=dml_source,
            ctx=ctx,
        )

    elif typeref.union:
        # Union object types are represented as a UNION of selects
        # from their children, which is, for most purposes, equivalent
        # to SELECTing from a parent table.
        set_ops = []

        for child in typeref.union:
            c_rvar = range_for_typeref(
                child,
                path_id=path_id,
                include_overlays=include_overlays,
                include_descendants=not typeref.union_is_concrete,
                dml_source=dml_source,
                ctx=ctx,
            )

            qry = pgast.SelectStmt(from_clause=[c_rvar], )

            pathctx.put_path_value_rvar(qry, path_id, c_rvar, env=ctx.env)
            if path_id.is_objtype_path():
                pathctx.put_path_source_rvar(qry, path_id, c_rvar, env=ctx.env)

            pathctx.put_path_bond(qry, path_id)

            set_ops.append(('union', qry))

        rvar = range_from_queryset(set_ops, typeref.name_hint, ctx=ctx)

    else:
        rvar = range_for_material_objtype(
            typeref,
            path_id,
            include_overlays=include_overlays,
            include_descendants=include_descendants,
            dml_source=dml_source,
            ctx=ctx,
        )

    rvar.query.path_id = path_id

    return rvar
Ejemplo n.º 2
0
def get_less_specific_aspect(path_id: irast.PathId, aspect: str):
    if path_id.is_objtype_path():
        mapping = OBJECT_ASPECT_SPECIFICITY_MAP
    else:
        mapping = PRIMITIVE_ASPECT_SPECIFICITY_MAP

    return mapping.get(PathAspect(aspect))
Ejemplo n.º 3
0
def get_less_specific_aspect(
    path_id: irast.PathId,
    aspect: str,
) -> Optional[str]:
    if path_id.is_objtype_path():
        mapping = OBJECT_ASPECT_SPECIFICITY_MAP
    else:
        mapping = PRIMITIVE_ASPECT_SPECIFICITY_MAP

    less_specific_aspect = mapping.get(PathAspect(aspect))
    if less_specific_aspect is not None:
        return str(less_specific_aspect)
    else:
        return None
Ejemplo n.º 4
0
def _find_rel_rvar(
    rel: pgast.Query, path_id: irast.PathId, src_path_id: irast.PathId, *,
    aspect: str, env: context.Environment,
) -> Tuple[str, Optional[pgast.PathRangeVar], Optional[pgast.BaseExpr]]:
    """Rummage around rel looking for an appropriate rvar for path_id.

    Somewhat unfortunately, some checks to find the actual path var
    (in a particular tuple case) need to occur in the middle of the
    rvar rel search, so we can also find the actual path var in passing.
    """
    src_aspect = aspect
    rel_rvar = maybe_get_path_rvar(rel, path_id, aspect=aspect, env=env)

    if rel_rvar is None:
        alt_aspect = get_less_specific_aspect(path_id, aspect)
        if alt_aspect is not None:
            rel_rvar = maybe_get_path_rvar(
                rel, path_id, aspect=alt_aspect, env=env)
    else:
        alt_aspect = None

    if rel_rvar is None:
        if src_path_id.is_objtype_path():
            src_aspect = 'source'
        else:
            src_aspect = aspect

        if src_path_id.is_tuple_path():
            if (var := _find_in_output_tuple(rel, path_id, aspect, env=env)):
                return src_aspect, None, var

            rel_rvar = maybe_get_path_rvar(
                rel, src_path_id, aspect=src_aspect, env=env)

            if rel_rvar is None:
                _src_path_id_prefix = src_path_id.src_path()
                if _src_path_id_prefix is not None:
                    rel_rvar = maybe_get_path_rvar(
                        rel, _src_path_id_prefix, aspect=src_aspect, env=env)
        else:
            rel_rvar = maybe_get_path_rvar(
                rel, src_path_id, aspect=src_aspect, env=env)

        if (rel_rvar is None
                and src_aspect != 'source' and path_id != src_path_id):
            rel_rvar = maybe_get_path_rvar(
                rel, src_path_id, aspect='source', env=env)
Ejemplo n.º 5
0
def range_for_typeref(typeref: irast.TypeRef,
                      path_id: irast.PathId,
                      *,
                      include_overlays: bool = True,
                      common_parent: bool = False,
                      env: context.Environment) -> pgast.BaseRangeVar:
    from . import pathctx  # XXX: fix cycle

    if not typeref.children:
        rvar = range_for_material_objtype(typeref,
                                          path_id,
                                          include_overlays=include_overlays,
                                          env=env)
    elif common_parent:
        rvar = range_for_material_objtype(typeref.common_parent,
                                          path_id,
                                          include_overlays=include_overlays,
                                          env=env)
    else:
        # Union object types are represented as a UNION of selects
        # from their children, which is, for most purposes, equivalent
        # to SELECTing from a parent table.
        set_ops = []

        for child in typeref.children:
            c_rvar = range_for_typeref(child,
                                       path_id=path_id,
                                       include_overlays=include_overlays,
                                       env=env)

            qry = pgast.SelectStmt(from_clause=[c_rvar], )

            pathctx.put_path_value_rvar(qry, path_id, c_rvar, env=env)
            if path_id.is_objtype_path():
                pathctx.put_path_source_rvar(qry, path_id, c_rvar, env=env)

            pathctx.put_path_bond(qry, path_id)

            set_ops.append(('union', qry))

        rvar = range_from_queryset(set_ops, typeref.name_hint, env=env)

    rvar.query.path_id = path_id

    return rvar
Ejemplo n.º 6
0
def include_rvar(stmt: pgast.SelectStmt,
                 rvar: pgast.PathRangeVar,
                 path_id: irast.PathId,
                 *,
                 overwrite_path_rvar: bool = False,
                 pull_namespace: bool = True,
                 aspects: Optional[Iterable[str]] = None,
                 ctx: context.CompilerContextLevel) -> pgast.PathRangeVar:
    """Ensure that *rvar* is visible in *stmt* as a value/source aspect.

    :param stmt:
        The statement to include *rel* in.

    :param rvar:
        The range var node to join.

    :param join_type:
        JOIN type to use when including *rel*.

    :param aspect:
        The reference aspect of the range var.

    :param ctx:
        Compiler context.
    """
    if aspects is None:
        if path_id.is_objtype_path():
            aspects = ('source', 'value')
        else:
            aspects = ('value', )

    return include_specific_rvar(stmt,
                                 rvar=rvar,
                                 path_id=path_id,
                                 overwrite_path_rvar=overwrite_path_rvar,
                                 pull_namespace=pull_namespace,
                                 aspects=aspects,
                                 ctx=ctx)
Ejemplo n.º 7
0
def range_for_material_objtype(
        typeref: irast.TypeRef,
        path_id: irast.PathId,
        *,
        include_overlays: bool = True,
        include_descendants: bool = True,
        dml_source: Optional[irast.MutatingStmt] = None,
        ctx: context.CompilerContextLevel) -> pgast.PathRangeVar:

    env = ctx.env

    if typeref.material_type is not None:
        typeref = typeref.material_type

    table_schema_name, table_name = common.get_objtype_backend_name(
        typeref.id, typeref.module_id, catenate=False)

    if typeref.name_hint.module in {'cfg', 'sys'}:
        # Redirect all queries to schema tables to edgedbss
        table_schema_name = 'edgedbss'

    relation = pgast.Relation(
        schemaname=table_schema_name,
        name=table_name,
        path_id=path_id,
    )

    rvar: pgast.PathRangeVar = pgast.RelRangeVar(
        relation=relation,
        typeref=typeref,
        include_inherited=include_descendants,
        alias=pgast.Alias(aliasname=env.aliases.get(typeref.name_hint.name)))

    overlays = get_type_rel_overlays(typeref, dml_source=dml_source, ctx=ctx)
    if overlays and include_overlays:
        set_ops = []

        qry = pgast.SelectStmt()
        qry.from_clause.append(rvar)
        pathctx.put_path_value_rvar(qry, path_id, rvar, env=env)
        if path_id.is_objtype_path():
            pathctx.put_path_source_rvar(qry, path_id, rvar, env=env)
        pathctx.put_path_bond(qry, path_id)

        set_ops.append(('union', qry))

        for op, cte, cte_path_id in overlays:
            rvar = pgast.RelRangeVar(
                relation=cte,
                typeref=typeref,
                alias=pgast.Alias(aliasname=env.aliases.get(hint=cte.name)))

            qry = pgast.SelectStmt(from_clause=[rvar], )

            pathctx.put_path_value_rvar(qry, cte_path_id, rvar, env=env)
            if path_id.is_objtype_path():
                pathctx.put_path_source_rvar(qry, cte_path_id, rvar, env=env)
            pathctx.put_path_bond(qry, cte_path_id)

            qry.view_path_id_map[path_id] = cte_path_id

            qry_rvar = pgast.RangeSubselect(
                subquery=qry,
                alias=pgast.Alias(aliasname=env.aliases.get(hint=cte.name)))

            qry2 = pgast.SelectStmt(from_clause=[qry_rvar])
            pathctx.put_path_value_rvar(qry2, path_id, qry_rvar, env=env)
            if path_id.is_objtype_path():
                pathctx.put_path_source_rvar(qry2, path_id, qry_rvar, env=env)
            pathctx.put_path_bond(qry2, path_id)

            if op == 'replace':
                op = 'union'
                set_ops = []
            set_ops.append((op, qry2))

        rvar = range_from_queryset(set_ops, typeref.name_hint, ctx=ctx)

    return rvar
Ejemplo n.º 8
0
def _get_path_output(rel: pgast.BaseRelation,
                     path_id: irast.PathId,
                     *,
                     aspect: str,
                     allow_nullable: bool = True,
                     ptr_info: typing.Optional[
                         pg_types.PointerStorageInfo] = None,
                     env: context.Environment) -> pgast.OutputVar:

    result = rel.path_outputs.get((path_id, aspect))
    if result is not None:
        return result

    ref: pgast.BaseExpr
    alias = None
    rptr = path_id.rptr()
    if rptr is not None and irtyputils.is_id_ptrref(rptr):
        # A value reference to Object.id is the same as a value
        # reference to the Object itself.
        src_path_id = path_id.src_path()
        id_output = rel.path_outputs.get((src_path_id, 'value'))
        if id_output is not None:
            _put_path_output_var(rel, path_id, aspect, id_output, env=env)
            return id_output

    if is_terminal_relation(rel):
        return _get_rel_path_output(rel,
                                    path_id,
                                    aspect=aspect,
                                    ptr_info=ptr_info,
                                    env=env)

    assert isinstance(rel, pgast.Query)
    if is_values_relation(rel):
        # The VALUES() construct seems to always expose its
        # value as "column1".
        alias = 'column1'
        ref = pgast.ColumnRef(name=[alias])
    else:
        ref = get_path_var(rel, path_id, aspect=aspect, env=env)

    other_output = find_path_output(rel, path_id, ref, env=env)
    if other_output is not None:
        _put_path_output_var(rel, path_id, aspect, other_output, env=env)
        return other_output

    if isinstance(ref, pgast.TupleVarBase):
        elements = []
        for el in ref.elements:
            el_path_id = reverse_map_path_id(el.path_id, rel.view_path_id_map)

            try:
                # Similarly to get_path_var(), check for outer path_id
                # first for tuple serialized var disambiguation.
                element = _get_path_output(rel,
                                           el_path_id,
                                           aspect=aspect,
                                           allow_nullable=False,
                                           env=env)
            except LookupError:
                element = get_path_output(rel,
                                          el_path_id,
                                          aspect=aspect,
                                          allow_nullable=False,
                                          env=env)

            elements.append(
                pgast.TupleElementBase(path_id=el_path_id, name=element))

        result = pgast.TupleVarBase(elements=elements, named=ref.named)

    else:
        if astutils.is_set_op_query(rel):
            assert isinstance(ref, pgast.OutputVar)
            result = astutils.strip_output_var(ref)
        else:
            assert isinstance(rel, pgast.ReturningQuery), \
                "expected ReturningQuery"

            if alias is None:
                alias = get_path_output_alias(path_id, aspect, env=env)

            restarget = pgast.ResTarget(name=alias,
                                        val=ref,
                                        ser_safe=getattr(
                                            ref, 'ser_safe', False))
            rel.target_list.append(restarget)

            nullable = is_nullable(ref, env=env)

            optional = None
            if isinstance(ref, pgast.ColumnRef):
                optional = ref.optional

            if nullable and not allow_nullable:
                var = get_path_var(rel, path_id, aspect=aspect, env=env)
                rel.where_clause = astutils.extend_binop(
                    rel.where_clause, pgast.NullTest(arg=var, negated=True))
                nullable = False

            result = pgast.ColumnRef(name=[alias],
                                     nullable=nullable,
                                     optional=optional)

    _put_path_output_var(rel, path_id, aspect, result, env=env)
    if (path_id.is_objtype_path()
            and not isinstance(result, pgast.TupleVarBase)):
        equiv_aspect = None
        if aspect == 'identity':
            equiv_aspect = 'value'
        elif aspect == 'value':
            equiv_aspect = 'identity'

        if (equiv_aspect is not None
                and (path_id, equiv_aspect) not in rel.path_outputs):
            _put_path_output_var(rel, path_id, equiv_aspect, result, env=env)

    return result
Ejemplo n.º 9
0
def _get_rel_path_output(rel: pgast.BaseRelation,
                         path_id: irast.PathId,
                         *,
                         aspect: str,
                         ptr_info: typing.Optional[
                             pg_types.PointerStorageInfo] = None,
                         env: context.Environment) -> pgast.OutputVar:

    if path_id.is_objtype_path():
        if aspect == 'identity':
            aspect = 'value'

        if aspect != 'value':
            raise LookupError(
                f'invalid request for non-scalar path {path_id} {aspect}')

        if (path_id == rel.path_id or (rel.path_id.is_type_indirection_path()
                                       and path_id == rel.path_id.src_path())):

            return _get_rel_object_id_output(rel,
                                             path_id,
                                             aspect=aspect,
                                             env=env)
    else:
        if aspect == 'identity':
            raise LookupError(
                f'invalid request for scalar path {path_id} {aspect}')

        elif aspect == 'serialized':
            aspect = 'value'

    var = rel.path_outputs.get((path_id, aspect))
    if var is not None:
        return var

    ptrref = path_id.rptr()
    rptr_dir = path_id.rptr_dir()

    if (rptr_dir is not None
            and rptr_dir != s_pointers.PointerDirection.Outbound):
        raise LookupError(
            f'{path_id} is an inbound pointer and cannot be resolved '
            f'on a base relation')

    if isinstance(rel, pgast.NullRelation):
        if ptrref is not None:
            target = ptrref.out_target
        else:
            target = path_id.target

        pg_type = pg_types.pg_type_from_ir_typeref(target)

        if ptr_info is not None:
            name = env.aliases.get(ptr_info.column_name)
        else:
            name = env.aliases.get('v')

        val = pgast.TypeCast(arg=pgast.NullConstant(),
                             type_name=pgast.TypeName(name=pg_type, ))

        rel.target_list.append(pgast.ResTarget(name=name, val=val))
        result = pgast.ColumnRef(name=[name], nullable=True)
    else:
        if ptrref is None:
            raise ValueError(
                f'could not resolve trailing pointer class for {path_id}')

        if ptr_info is None:
            ptr_info = pg_types.get_ptrref_storage_info(ptrref,
                                                        resolve_type=False,
                                                        link_bias=False)

        result = pgast.ColumnRef(name=[ptr_info.column_name],
                                 nullable=not ptrref.required)
    _put_path_output_var(rel, path_id, aspect, result, env=env)
    return result
Ejemplo n.º 10
0
def get_path_var(rel: pgast.Query, path_id: irast.PathId, *, aspect: str,
                 env: context.Environment) -> pgast.BaseExpr:
    """Return a value expression for a given *path_id* in a given *rel*."""
    if isinstance(rel, pgast.CommonTableExpr):
        rel = rel.query

    # Check if we already have a var, before remapping the path_id.
    # This is useful for serialized aspect disambiguation in tuples,
    # since process_set_as_tuple() records serialized vars with
    # original path_id.
    if (path_id, aspect) in rel.path_namespace:
        return rel.path_namespace[path_id, aspect]

    if rel.view_path_id_map:
        path_id = map_path_id(path_id, rel.view_path_id_map)

    if (path_id, aspect) in rel.path_namespace:
        return rel.path_namespace[path_id, aspect]

    ptrref = path_id.rptr()
    is_type_intersection = path_id.is_type_intersection_path()

    src_path_id: Optional[irast.PathId] = None
    if ptrref is not None and not is_type_intersection:
        ptr_info = pg_types.get_ptrref_storage_info(ptrref,
                                                    resolve_type=False,
                                                    link_bias=False)
        ptr_dir = path_id.rptr_dir()
        is_inbound = ptr_dir == s_pointers.PointerDirection.Inbound
        if is_inbound:
            src_path_id = path_id
        else:
            src_path_id = path_id.src_path()
            assert src_path_id is not None
            src_rptr = src_path_id.rptr()
            if (irtyputils.is_id_ptrref(ptrref)
                    and (src_rptr is None
                         or not irtyputils.is_inbound_ptrref(src_rptr))):
                # When there is a reference to the id property of
                # an object which is linked to by a link stored
                # inline, we want to route the reference to the
                # inline attribute.  For example,
                # Foo.__type__.id gets resolved to the Foo.__type__
                # column.  This can only be done if Foo is visible
                # in scope, and Foo.__type__ is not a computable.
                pid = src_path_id
                while pid.is_type_intersection_path():
                    # Skip type intersection step(s).
                    src_pid = pid.src_path()
                    if src_pid is not None:
                        src_rptr = src_pid.rptr()
                        pid = src_pid
                    else:
                        break

                if (src_rptr is not None
                        and not irtyputils.is_computable_ptrref(src_rptr)
                        and env.ptrref_source_visibility.get(src_rptr)):
                    src_ptr_info = pg_types.get_ptrref_storage_info(
                        src_rptr, resolve_type=False, link_bias=False)
                    if src_ptr_info.table_type == 'ObjectType':
                        src_path_id = src_path_id.src_path()
                        ptr_info = src_ptr_info

    else:
        ptr_info = None
        ptr_dir = None

    var: Optional[pgast.BaseExpr]

    if astutils.is_set_op_query(rel):
        # We disable the find_path_output optimizaiton when doing
        # UNIONs to avoid situations where they have different numbers
        # of columns.
        cb = functools.partial(get_path_output_or_null,
                               env=env,
                               disable_output_fusion=True,
                               path_id=path_id,
                               aspect=aspect)

        outputs = astutils.for_each_query_in_set(rel, cb)

        first: Optional[pgast.OutputVar] = None
        optional = False
        all_null = True
        nullable = False

        for colref, is_null in outputs:
            if colref.nullable:
                nullable = True
            if first is None:
                first = colref
            if is_null:
                optional = True
            else:
                all_null = False

        if all_null:
            raise LookupError(f'cannot find refs for '
                              f'path {path_id} {aspect} in {rel}')

        if first is None:
            raise AssertionError(f'union did not produce any outputs')

        # Path vars produced by UNION expressions can be "optional",
        # i.e the record is accepted as-is when such var is NULL.
        # This is necessary to correctly join heterogeneous UNIONs.
        var = astutils.strip_output_var(first,
                                        optional=optional,
                                        nullable=optional or nullable)
        put_path_var(rel, path_id, var, aspect=aspect, env=env)
        return var

    if ptrref is None:
        if len(path_id) == 1:
            # This is an scalar set derived from an expression.
            src_path_id = path_id

    elif ptrref.source_ptr is not None:
        if ptr_info.table_type != 'link' and not is_inbound:
            # This is a link prop that is stored in source rel,
            # step back to link source rvar.
            _prefix_pid = path_id.src_path()
            assert _prefix_pid is not None
            src_path_id = _prefix_pid.src_path()

    elif (ptr_info is not None and ptr_info.table_type != 'ObjectType'
          and not is_inbound):
        # Ref is in the mapping rvar.
        src_path_id = path_id.ptr_path()
    elif is_type_intersection:
        src_path_id = path_id

    rel_rvar = maybe_get_path_rvar(rel, path_id, aspect=aspect, env=env)

    if rel_rvar is None:
        alt_aspect = get_less_specific_aspect(path_id, aspect)
        if alt_aspect is not None:
            rel_rvar = maybe_get_path_rvar(rel,
                                           path_id,
                                           aspect=alt_aspect,
                                           env=env)
    else:
        alt_aspect = None

    assert src_path_id is not None

    if rel_rvar is None:
        if src_path_id.is_objtype_path():
            src_aspect = 'source'
        else:
            src_aspect = aspect

        if src_path_id.is_tuple_path():
            rel_rvar = maybe_get_path_rvar(rel,
                                           src_path_id,
                                           aspect=src_aspect,
                                           env=env)

            if rel_rvar is None:
                _src_path_id_prefix = src_path_id.src_path()
                if _src_path_id_prefix is not None:
                    rel_rvar = maybe_get_path_rvar(rel,
                                                   _src_path_id_prefix,
                                                   aspect=src_aspect,
                                                   env=env)
        else:
            rel_rvar = maybe_get_path_rvar(rel,
                                           src_path_id,
                                           aspect=src_aspect,
                                           env=env)

        if (rel_rvar is None and src_aspect != 'source'
                and path_id != src_path_id):
            rel_rvar = maybe_get_path_rvar(rel,
                                           src_path_id,
                                           aspect='source',
                                           env=env)

    if rel_rvar is None and alt_aspect is not None:
        # There is no source range var for the requested aspect,
        # check if there is a cached var with less specificity.
        var = rel.path_namespace.get((path_id, alt_aspect))
        if var is not None:
            put_path_var(rel, path_id, var, aspect=aspect, env=env)
            return var

    if rel_rvar is None:
        raise LookupError(f'there is no range var for '
                          f'{src_path_id} {src_aspect} in {rel}')

    if isinstance(rel_rvar, pgast.IntersectionRangeVar):
        if ((path_id.is_objtype_path() and src_path_id == path_id)
                or (ptrref is not None and irtyputils.is_id_ptrref(ptrref))):
            rel_rvar = rel_rvar.component_rvars[-1]
        else:
            # Intersection rvars are basically JOINs of the relevant
            # parts of the type intersection, and so we need to make
            # sure we pick the correct component relation of that JOIN.
            rel_rvar = _find_rvar_in_intersection_by_typeref(
                path_id,
                rel_rvar.component_rvars,
            )

    source_rel = rel_rvar.query

    if isinstance(ptrref, irast.PointerRef) and rel_rvar.typeref is not None:
        actual_ptrref = irtyputils.maybe_find_actual_ptrref(
            rel_rvar.typeref, ptrref)

        if actual_ptrref is not None:
            ptr_info = pg_types.get_ptrref_storage_info(actual_ptrref,
                                                        resolve_type=False,
                                                        link_bias=False)

    outvar = get_path_output(source_rel,
                             path_id,
                             ptr_info=ptr_info,
                             aspect=aspect,
                             env=env)

    var = astutils.get_rvar_var(rel_rvar, outvar)
    put_path_var(rel, path_id, var, aspect=aspect, env=env)

    if isinstance(var, pgast.TupleVar):
        for element in var.elements:
            put_path_var_if_not_exists(rel,
                                       element.path_id,
                                       element.val,
                                       aspect=aspect,
                                       env=env)

    return var
Ejemplo n.º 11
0
def get_path_var(
        rel: pgast.Query, path_id: irast.PathId, *,
        aspect: str, env: context.Environment) -> pgast.BaseExpr:
    """Return a value expression for a given *path_id* in a given *rel*."""
    if isinstance(rel, pgast.CommonTableExpr):
        rel = rel.query

    # Check if we already have a var, before remapping the path_id.
    # This is useful for serialized aspect disambiguation in tuples,
    # since process_set_as_tuple() records serialized vars with
    # original path_id.
    if (path_id, aspect) in rel.path_namespace:
        return rel.path_namespace[path_id, aspect]

    if rel.view_path_id_map:
        path_id = map_path_id(path_id, rel.view_path_id_map)

    if (path_id, aspect) in rel.path_namespace:
        return rel.path_namespace[path_id, aspect]

    if astutils.is_set_op_query(rel):
        return _get_path_var_in_setop(rel, path_id, aspect=aspect, env=env)

    ptrref = path_id.rptr()
    is_type_intersection = path_id.is_type_intersection_path()

    src_path_id: Optional[irast.PathId] = None
    if ptrref is not None and not is_type_intersection:
        ptr_info = pg_types.get_ptrref_storage_info(
            ptrref, resolve_type=False, link_bias=False, allow_missing=True)
        ptr_dir = path_id.rptr_dir()
        is_inbound = ptr_dir == s_pointers.PointerDirection.Inbound
        if is_inbound:
            src_path_id = path_id
        else:
            src_path_id = path_id.src_path()
            assert src_path_id is not None
            src_rptr = src_path_id.rptr()
            if (irtyputils.is_id_ptrref(ptrref)
                    and (src_rptr is None
                         or not irtyputils.is_inbound_ptrref(src_rptr))):
                # When there is a reference to the id property of
                # an object which is linked to by a link stored
                # inline, we want to route the reference to the
                # inline attribute.  For example,
                # Foo.__type__.id gets resolved to the Foo.__type__
                # column.  This can only be done if Foo is visible
                # in scope, and Foo.__type__ is not a computable.
                pid = src_path_id
                while pid.is_type_intersection_path():
                    # Skip type intersection step(s).
                    src_pid = pid.src_path()
                    if src_pid is not None:
                        src_rptr = src_pid.rptr()
                        pid = src_pid
                    else:
                        break

                if (src_rptr is not None
                        and not irtyputils.is_computable_ptrref(src_rptr)
                        and env.ptrref_source_visibility.get(src_rptr)):
                    src_ptr_info = pg_types.get_ptrref_storage_info(
                        src_rptr, resolve_type=False, link_bias=False,
                        allow_missing=True)
                    if (src_ptr_info
                            and src_ptr_info.table_type == 'ObjectType'):
                        src_path_id = src_path_id.src_path()
                        ptr_info = src_ptr_info

    else:
        ptr_info = None
        ptr_dir = None

    var: Optional[pgast.BaseExpr]

    if ptrref is None:
        if len(path_id) == 1:
            # This is an scalar set derived from an expression.
            src_path_id = path_id

    elif ptrref.source_ptr is not None:
        if ptr_info and ptr_info.table_type != 'link' and not is_inbound:
            # This is a link prop that is stored in source rel,
            # step back to link source rvar.
            _prefix_pid = path_id.src_path()
            assert _prefix_pid is not None
            src_path_id = _prefix_pid.src_path()

    elif is_type_intersection:
        src_path_id = path_id

    assert src_path_id is not None

    # Find which rvar will have path_id as an output
    src_aspect, rel_rvar, found_path_var = _find_rel_rvar(
        rel, path_id, src_path_id, aspect=aspect, env=env)

    if found_path_var:
        return found_path_var

    if rel_rvar is None:
        raise LookupError(
            f'there is no range var for '
            f'{src_path_id} {src_aspect} in {rel}')

    if isinstance(rel_rvar, pgast.IntersectionRangeVar):
        if (
            (path_id.is_objtype_path() and src_path_id == path_id)
            or (ptrref is not None and irtyputils.is_id_ptrref(ptrref))
        ):
            rel_rvar = rel_rvar.component_rvars[-1]
        else:
            # Intersection rvars are basically JOINs of the relevant
            # parts of the type intersection, and so we need to make
            # sure we pick the correct component relation of that JOIN.
            rel_rvar = _find_rvar_in_intersection_by_typeref(
                path_id,
                rel_rvar.component_rvars,
            )

    source_rel = rel_rvar.query

    if isinstance(ptrref, irast.PointerRef) and rel_rvar.typeref is not None:
        actual_ptrref = irtyputils.maybe_find_actual_ptrref(
            rel_rvar.typeref, ptrref)

        if actual_ptrref is not None:
            ptr_info = pg_types.get_ptrref_storage_info(
                actual_ptrref, resolve_type=False, link_bias=False)

    outvar = get_path_output(
        source_rel, path_id, ptr_info=ptr_info,
        aspect=aspect, env=env)

    var = astutils.get_rvar_var(rel_rvar, outvar)
    put_path_var(rel, path_id, var, aspect=aspect, env=env)

    if isinstance(var, pgast.TupleVar):
        for element in var.elements:
            put_path_var_if_not_exists(rel, element.path_id, element.val,
                                       aspect=aspect, env=env)

    return var