Exemple #1
0
def tuple_indirection_set(path_tip: irast.Set, *, source: s_sources.Source,
                          ptr_name: str, source_context: parsing.ParserContext,
                          ctx: context.ContextLevel) -> irast.Set:

    el_name = ptr_name
    el_norm_name = source.normalize_index(ctx.env.schema, el_name)
    el_type = source.get_subtype(ctx.env.schema, el_name)

    path_id = pathctx.get_tuple_indirection_path_id(path_tip.path_id,
                                                    el_norm_name,
                                                    el_type,
                                                    ctx=ctx)
    expr = irast.TupleIndirection(expr=path_tip,
                                  name=el_norm_name,
                                  path_id=path_id,
                                  context=source_context)

    return expression_set(expr, ctx=ctx)
Exemple #2
0
def _cast_tuple(ir_set: irast.Base, orig_stype: s_types.Type,
                new_stype: s_types.Type, *, srcctx: parsing.ParserContext,
                ctx: context.ContextLevel) -> irast.Base:

    # Make sure the source tuple expression is pinned in the scope,
    # so that we don't generate a cross-product of it by evaluating
    # the tuple indirections.
    pathctx.register_set_in_scope(ir_set, ctx=ctx)

    direct_cast = _find_cast(orig_stype, new_stype, srcctx=srcctx, ctx=ctx)
    orig_subtypes = dict(orig_stype.iter_subtypes(ctx.env.schema))

    if direct_cast is not None:
        # Direct casting to non-tuple involves casting each tuple
        # element and also keeping the cast around the whole tuple.
        # This is to trigger the downstream logic of casting
        # objects (in elements of the tuple).
        elements = []
        for i, (n, st) in enumerate(orig_subtypes.items()):
            path_id = pathctx.get_tuple_indirection_path_id(ir_set.path_id,
                                                            n,
                                                            st,
                                                            ctx=ctx)

            val = setgen.ensure_set(irast.TupleIndirection(expr=ir_set,
                                                           name=n),
                                    path_id=path_id,
                                    ctx=ctx)
            val_type = inference.infer_type(val, ctx.env)
            # Element cast
            val = compile_cast(val, new_stype, ctx=ctx, srcctx=srcctx)

            elements.append(irast.TupleElement(name=n, val=val))

        new_tuple = setgen.new_tuple_set(elements,
                                         named=orig_stype.named,
                                         ctx=ctx)

        return _cast_to_ir(new_tuple,
                           direct_cast,
                           orig_stype,
                           new_stype,
                           ctx=ctx)

    if not new_stype.is_tuple():
        raise errors.QueryError(
            f'cannot cast {orig_stype.get_displayname(ctx.env.schema)!r} '
            f'to {new_stype.get_displayname(ctx.env.schema)!r}',
            context=srcctx)

    new_subtypes = list(new_stype.iter_subtypes(ctx.env.schema))
    if len(orig_subtypes) != len(new_subtypes):
        raise errors.QueryError(
            f'cannot cast {orig_stype.get_displayname(ctx.env.schema)!r} '
            f'to {new_stype.get_displayname(ctx.env.schema)!r}: ',
            f'the number of elements is not the same',
            context=srcctx)

    # For tuple-to-tuple casts we generate a new tuple
    # to simplify things on sqlgen side.
    elements = []
    for i, (n, orig_st) in enumerate(orig_subtypes.items()):
        path_id = pathctx.get_tuple_indirection_path_id(ir_set.path_id,
                                                        n,
                                                        orig_st,
                                                        ctx=ctx)

        val = setgen.ensure_set(irast.TupleIndirection(expr=ir_set, name=n),
                                path_id=path_id,
                                ctx=ctx)
        val_type = inference.infer_type(val, ctx.env)
        new_el_name, new_st = new_subtypes[i]
        if val_type != new_st:
            # Element cast
            val = compile_cast(val, new_st, ctx=ctx, srcctx=srcctx)

        elements.append(irast.TupleElement(name=new_el_name, val=val))

    return setgen.new_tuple_set(elements, named=new_stype.named, ctx=ctx)