Ejemplo n.º 1
0
def _compile_shape(ir_set: irast.Set, shape: typing.List[irast.Set], *,
                   ctx: context.CompilerContextLevel) -> pgast.TupleVar:

    result = shapecomp.compile_shape(ir_set, shape, ctx=ctx)

    for element in result.elements:
        # The ref might have already been added by the nested shape
        # processing, so add it conditionally.
        pathctx.put_path_serialized_var_if_not_exists(ctx.rel,
                                                      element.path_id,
                                                      element.val,
                                                      env=ctx.env)

    ser_elements = []
    for el in result.elements:
        ser_val = pathctx.get_path_serialized_or_value_var(ctx.rel,
                                                           el.path_id,
                                                           env=ctx.env)
        ser_elements.append(
            pgast.TupleElement(path_id=el.path_id, name=el.name, val=ser_val))

    ser_result = pgast.TupleVar(elements=ser_elements, named=True)
    sval = output.serialize_expr(ser_result,
                                 path_id=ir_set.path_id,
                                 env=ctx.env)
    pathctx.put_path_serialized_var(ctx.rel,
                                    ir_set.path_id,
                                    sval,
                                    force=True,
                                    env=ctx.env)

    return result
Ejemplo n.º 2
0
def strip_output_var(
        var: pgast.OutputVar,
        *,
        optional: typing.Optional[bool] = None,
        nullable: typing.Optional[bool] = None) -> pgast.OutputVar:

    if isinstance(var, pgast.TupleVarBase):
        elements = []

        for el in var.elements:
            if isinstance(el.name, str):
                val = pgast.ColumnRef(name=[el.name])
            else:
                val = strip_output_var(el.name)

            elements.append(
                pgast.TupleElement(path_id=el.path_id, name=el.name, val=val))

        result = pgast.TupleVar(elements, named=var.named)
    else:
        result = pgast.ColumnRef(
            name=[var.name[-1]],
            optional=optional if optional is not None else var.optional,
            nullable=nullable if nullable is not None else var.nullable,
        )

    return result
Ejemplo n.º 3
0
def get_rvar_var(
        rvar: pgast.BaseRangeVar,
        var: pgast.OutputVar) -> pgast.OutputVar:

    fieldref: pgast.OutputVar

    if isinstance(var, pgast.TupleVarBase):
        elements = []

        for el in var.elements:
            assert isinstance(el.name, pgast.OutputVar)
            val = get_rvar_var(rvar, el.name)
            elements.append(
                pgast.TupleElement(
                    path_id=el.path_id, name=el.name, val=val))

        fieldref = pgast.TupleVar(elements, named=var.named)

    elif isinstance(var, pgast.ColumnRef):
        fieldref = get_column(rvar, var)

    else:
        raise AssertionError(f'unexpected OutputVar subclass: {var!r}')

    return fieldref
Ejemplo n.º 4
0
def fix_tuple(
        rel: pgast.Query, ref: pgast.BaseExpr, *,
        aspect: str, env: context.Environment) -> pgast.BaseExpr:

    if (
        isinstance(ref, pgast.TupleVarBase)
        and not isinstance(ref, pgast.TupleVar)
    ):
        elements = []

        for el in ref.elements:
            assert el.path_id is not None
            val = get_path_var_and_fix_tuple(
                rel, el.path_id, aspect=aspect, env=env)
            elements.append(
                pgast.TupleElement(
                    path_id=el.path_id, name=el.name, val=val))

        ref = pgast.TupleVar(
            elements,
            named=ref.named,
            typeref=ref.typeref,
        )

    return ref
Ejemplo n.º 5
0
def tuple_element_for_shape_el(
        shape_el: irast.Set,
        value: Optional[pgast.BaseExpr] = None,
        *,
        ctx: context.CompilerContextLevel) -> pgast.TupleElementBase:
    if shape_el.path_id.is_type_intersection_path():
        assert shape_el.rptr is not None
        rptr = shape_el.rptr.source.rptr
    else:
        rptr = shape_el.rptr
    assert rptr is not None
    ptrref = rptr.ptrref
    ptrname = ptrref.shortname

    if value is not None:
        return pgast.TupleElement(
            path_id=shape_el.path_id,
            name=ptrname.name,
            val=value,
        )
    else:
        return pgast.TupleElementBase(
            path_id=shape_el.path_id,
            name=ptrname.name,
        )
Ejemplo n.º 6
0
def tuple_element_for_shape_el(shape_el, value, *, ctx):
    if shape_el.path_id.is_type_indirection_path():
        rptr = shape_el.rptr.source.rptr
    else:
        rptr = shape_el.rptr
    ptrref = rptr.ptrref
    ptrname = ptrref.shortname

    return pgast.TupleElement(
        path_id=shape_el.path_id,
        name=ptrname,
        val=value,
    )
Ejemplo n.º 7
0
def get_path_serialized_output(
        rel: pgast.Query, path_id: irast.PathId, *,
        env: context.Environment) -> pgast.OutputVar:
    # Serialized output is a special case, we don't
    # want this behaviour to be recursive, so it
    # must be kept outside of get_path_output() generic.
    aspect = 'serialized'

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

    ref = get_path_serialized_or_value_var(rel, path_id, env=env)

    if (
        isinstance(ref, pgast.TupleVarBase)
        and not isinstance(ref, pgast.TupleVar)
    ):
        elements = []

        for el in ref.elements:
            assert el.path_id is not None
            val = get_path_serialized_or_value_var(rel, el.path_id, env=env)
            elements.append(
                pgast.TupleElement(
                    path_id=el.path_id, name=el.name, val=val))

        ref = pgast.TupleVar(
            elements,
            named=ref.named,
            typeref=ref.typeref,
        )

    refexpr = output.serialize_expr(ref, path_id=path_id, env=env)
    alias = get_path_output_alias(path_id, aspect, env=env)

    restarget = pgast.ResTarget(name=alias, val=refexpr, ser_safe=True)
    rel.target_list.append(restarget)

    result = pgast.ColumnRef(
        name=[alias], nullable=refexpr.nullable, ser_safe=True)

    _put_path_output_var(rel, path_id, aspect, result, env=env)

    return result
Ejemplo n.º 8
0
def get_rvar_var(rvar: pgast.BaseRangeVar,
                 var: pgast.OutputVar) -> pgast.OutputVar:

    assert isinstance(var, pgast.OutputVar)

    if isinstance(var, pgast.TupleVarBase):
        elements = []

        for el in var.elements:
            val = get_rvar_var(rvar, el.name)
            elements.append(
                pgast.TupleElement(path_id=el.path_id, name=el.name, val=val))

        fieldref = pgast.TupleVar(elements, named=var.named)
    else:
        fieldref = get_column(rvar, var)

    return fieldref
Ejemplo n.º 9
0
def _compile_shape(ir_set: irast.Set, shape: Sequence[Tuple[irast.Set,
                                                            qlast.ShapeOp]], *,
                   ctx: context.CompilerContextLevel) -> pgast.TupleVar:

    result = shapecomp.compile_shape(ir_set, shape, ctx=ctx)

    for element in result.elements:
        # We want to force, because the path id might already exist
        # serialized with a different shape, and we need ours to be
        # visible. (Anything needing the old one needs to have pulled
        # it already: see the "unfortunate hack" in
        # process_set_as_tuple.)
        pathctx.put_path_serialized_var(ctx.rel,
                                        element.path_id,
                                        element.val,
                                        force=True,
                                        env=ctx.env)

    # When we compile a shape during materialization, stash the
    # set away so we can consume it in unpack_rvar.
    if (ctx.materializing
            and ir_set.typeref.id not in ctx.env.materialized_views):
        ctx.env.materialized_views[ir_set.typeref.id] = ir_set

    ser_elements = []
    for el in result.elements:
        ser_val = pathctx.get_path_serialized_or_value_var(ctx.rel,
                                                           el.path_id,
                                                           env=ctx.env)
        ser_elements.append(
            pgast.TupleElement(path_id=el.path_id, name=el.name, val=ser_val))

    ser_result = pgast.TupleVar(elements=ser_elements, named=True)
    sval = output.serialize_expr(ser_result,
                                 path_id=ir_set.path_id,
                                 env=ctx.env)
    pathctx.put_path_serialized_var(ctx.rel,
                                    ir_set.path_id,
                                    sval,
                                    force=True,
                                    env=ctx.env)

    return result
Ejemplo n.º 10
0
def strip_output_var(var: pgast.OutputVar,
                     *,
                     optional: Optional[bool] = None,
                     nullable: Optional[bool] = None) -> pgast.OutputVar:

    result: pgast.OutputVar

    if isinstance(var, pgast.TupleVarBase):
        elements = []

        for el in var.elements:
            val: pgast.OutputVar
            el_name = el.name

            if isinstance(el_name, str):
                val = pgast.ColumnRef(name=[el_name])
            elif isinstance(el_name, pgast.OutputVar):
                val = strip_output_var(el_name)
            else:
                raise AssertionError(
                    f'unexpected tuple element class: {el_name!r}')

            elements.append(
                pgast.TupleElement(path_id=el.path_id, name=el_name, val=val))

        result = pgast.TupleVar(
            elements,
            named=var.named,
            typeref=var.typeref,
        )

    elif isinstance(var, pgast.ColumnRef):
        result = pgast.ColumnRef(
            name=[var.name[-1]],
            optional=optional if optional is not None else var.optional,
            nullable=nullable if nullable is not None else var.nullable,
        )

    else:
        raise AssertionError(f'unexpected OutputVar subclass: {var!r}')

    return result
Ejemplo n.º 11
0
def compile_Tuple(expr: irast.Tuple, *,
                  ctx: context.CompilerContextLevel) -> pgast.BaseExpr:
    ttype = expr.typeref
    ttypes = {}
    for i, st in enumerate(ttype.subtypes):
        if st.element_name:
            ttypes[st.element_name] = st
        else:
            ttypes[str(i)] = st
    telems = list(ttypes)

    elements = []

    for i, e in enumerate(expr.elements):
        telem = telems[i]
        ttype = ttypes[telem]
        val = dispatch.compile(e.val, ctx=ctx)
        elements.append(pgast.TupleElement(path_id=e.path_id, val=val))

    result = pgast.TupleVar(elements=elements)

    return output.output_as_value(result, env=ctx.env)
Ejemplo n.º 12
0
def _compile_shape(ir_set: irast.Set, shape: List[Tuple[irast.Set,
                                                        qlast.ShapeOp]], *,
                   ctx: context.CompilerContextLevel) -> pgast.TupleVar:

    result = shapecomp.compile_shape(ir_set, shape, ctx=ctx)

    for element in result.elements:
        # We want to force, because the path id might already exist
        # serialized with a different shape, and we need ours to be
        # visible. (Anything needing the old one needs to have pulled
        # it already: see the "unfortunate hack" in
        # process_set_as_tuple.)
        pathctx.put_path_serialized_var(ctx.rel,
                                        element.path_id,
                                        element.val,
                                        force=True,
                                        env=ctx.env)

    ser_elements = []
    for el in result.elements:
        ser_val = pathctx.get_path_serialized_or_value_var(ctx.rel,
                                                           el.path_id,
                                                           env=ctx.env)
        ser_elements.append(
            pgast.TupleElement(path_id=el.path_id, name=el.name, val=ser_val))

    ser_result = pgast.TupleVar(elements=ser_elements, named=True)
    sval = output.serialize_expr(ser_result,
                                 path_id=ir_set.path_id,
                                 env=ctx.env)
    pathctx.put_path_serialized_var(ctx.rel,
                                    ir_set.path_id,
                                    sval,
                                    force=True,
                                    env=ctx.env)

    return result
Ejemplo n.º 13
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

    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)
    elif 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.TupleVar):
        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.TupleElement(path_id=el_path_id, name=element))

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

    else:
        if astutils.is_set_op_query(rel):
            result = dbobj.strip_output_var(ref)
        else:
            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))
            if hasattr(rel, 'returning_list'):
                rel.returning_list.append(restarget)
            else:
                rel.target_list.append(restarget)

            nullable = is_nullable(ref, env=env)

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

            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 (aspect == 'identity' and path_id.is_objtype_path()
            and (path_id, 'value') not in rel.path_outputs):
        _put_path_output_var(rel, path_id, 'value', result, env=env)

    return result