Beispiel #1
0
def compile_OperatorCall(expr: irast.OperatorCall, *,
                         ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    if (str(expr.func_shortname) == 'std::IF'
            and expr.args[0].cardinality.is_single()
            and expr.args[2].cardinality.is_single()):
        if_expr, condition, else_expr = (a.expr for a in expr.args)
        return pgast.CaseExpr(args=[
            pgast.CaseWhen(expr=dispatch.compile(condition, ctx=ctx),
                           result=dispatch.compile(if_expr, ctx=ctx))
        ],
                              defresult=dispatch.compile(else_expr, ctx=ctx))
    elif (str(expr.func_shortname) == 'std::??'
          and expr.args[0].cardinality.is_single()
          and expr.args[1].cardinality.is_single()):
        l_expr, r_expr = (a.expr for a in expr.args)
        return pgast.CoalesceExpr(args=[
            dispatch.compile(l_expr, ctx=ctx),
            dispatch.compile(r_expr, ctx=ctx),
        ], )
    elif expr.typemod is ql_ft.TypeModifier.SetOfType:
        raise errors.UnsupportedFeatureError(
            f'set returning operator {expr.func_shortname!r} is not supported '
            f'in simple expressions')

    args = _compile_call_args(expr, ctx=ctx)
    return compile_operator(expr, args, ctx=ctx)
Beispiel #2
0
def compile_OperatorCall(expr: irast.OperatorCall, *,
                         ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    if (expr.func_shortname == 'std::IF'
            and expr.args[0].cardinality.is_single()
            and expr.args[2].cardinality.is_single()):
        if_expr, condition, else_expr = (a.expr for a in expr.args)
        return pgast.CaseExpr(args=[
            pgast.CaseWhen(expr=dispatch.compile(condition, ctx=ctx),
                           result=dispatch.compile(if_expr, ctx=ctx))
        ],
                              defresult=dispatch.compile(else_expr, ctx=ctx))

    if expr.typemod is ql_ft.TypeModifier.SET_OF:
        raise RuntimeError(
            f'set returning operator {expr.func_shortname!r} is not supported '
            f'in simple expressions')

    args = [dispatch.compile(a.expr, ctx=ctx) for a in expr.args]
    return compile_operator(expr, args, ctx=ctx)
Beispiel #3
0
def compile_OperatorCall(expr: irast.OperatorCall, *,
                         ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    if (expr.func_shortname == 'std::IF'
            and expr.args[0].cardinality is ql_ft.Cardinality.ONE
            and expr.args[2].cardinality is ql_ft.Cardinality.ONE):
        if_expr, condition, else_expr = (a.expr for a in expr.args)
        return pgast.CaseExpr(args=[
            pgast.CaseWhen(expr=dispatch.compile(condition, ctx=ctx),
                           result=dispatch.compile(if_expr, ctx=ctx))
        ],
                              defresult=dispatch.compile(else_expr, ctx=ctx))

    if expr.typemod is ql_ft.TypeModifier.SET_OF:
        raise RuntimeError(
            f'set returning operator {expr.func_shortname!r} is not supported '
            f'in simple expressions')

    args = [dispatch.compile(a.expr, ctx=ctx) for a in expr.args]
    lexpr = rexpr = None
    if expr.operator_kind is ql_ft.OperatorKind.INFIX:
        lexpr, rexpr = args
    elif expr.operator_kind is ql_ft.OperatorKind.PREFIX:
        rexpr = args[0]
    elif expr.operator_kind is ql_ft.OperatorKind.POSTFIX:
        lexpr = args[0]
    else:
        raise RuntimeError(f'unexpected operator kind: {expr.operator_kind!r}')

    if (expr.func_shortname == 'std::='
            and expr.args[0].expr.typeref is not None
            and irtyputils.is_object(expr.args[0].expr.typeref)
            and expr.args[1].expr.typeref is not None
            and irtyputils.is_object(expr.args[1].expr.typeref)):
        sql_oper = '='

    elif expr.sql_operator:
        sql_oper = expr.sql_operator[0]
        if len(expr.sql_operator) > 1:
            # Explicit operand types given in FROM SQL OPERATOR
            if lexpr is not None:
                lexpr = pgast.TypeCast(
                    arg=lexpr,
                    type_name=pgast.TypeName(name=(expr.sql_operator[1], )))

            if rexpr is not None:
                rexpr = pgast.TypeCast(
                    arg=rexpr,
                    type_name=pgast.TypeName(name=(expr.sql_operator[2], )))
    else:
        sql_oper = common.get_operator_backend_name(expr.func_shortname,
                                                    expr.func_module_id)[1]

    result: pgast.BaseExpr = pgast.Expr(
        kind=pgast.ExprKind.OP,
        name=sql_oper,
        lexpr=lexpr,
        rexpr=rexpr,
    )

    if expr.force_return_cast:
        # The underlying operator has a return value type
        # different from that of the EdgeQL operator declaration,
        # so we need to make an explicit cast here.
        result = pgast.TypeCast(
            arg=result,
            type_name=pgast.TypeName(
                name=pg_types.pg_type_from_ir_typeref(expr.typeref)))

    return result
Beispiel #4
0
def _compile_grouping_value(
        stmt: irast.GroupStmt, used_args: AbstractSet[str], *,
        ctx: context.CompilerContextLevel) -> pgast.BaseExpr:
    '''Produce the value for the grouping binding saying what is grouped on'''
    assert stmt.grouping_binding
    grouprel = ctx.rel

    # If there is only one thing grouped on, just output the hardcoded
    if len(used_args) == 1:
        return pgast.ArrayExpr(elements=[
            pgast.StringConstant(
                val=desugar_group.key_name(list(used_args)[0]))
        ])

    using = {k: stmt.using[k] for k in used_args}

    args = [
        pathctx.get_path_var(grouprel,
                             alias_set.path_id,
                             aspect='value',
                             env=ctx.env) for alias_set, _ in using.values()
    ]

    # Call grouping on each element we group on to produce a bitmask
    grouping_alias = ctx.env.aliases.get('g')
    grouping_call = pgast.FuncCall(name=('grouping', ), args=args)
    subq = pgast.SelectStmt(target_list=[
        pgast.ResTarget(name=grouping_alias, val=grouping_call),
    ])
    q = pgast.SelectStmt(from_clause=[
        pgast.RangeSubselect(
            subquery=subq, alias=pgast.Alias(aliasname=ctx.env.aliases.get()))
    ])

    grouping_ref = pgast.ColumnRef(name=(grouping_alias, ))

    # Generate a call to ARRAY[...] with a case for each grouping
    # element, then array_remove out the NULLs.
    els: List[pgast.BaseExpr] = []
    for i, name in enumerate(using):
        name = desugar_group.key_name(name)
        mask = 1 << (len(using) - i - 1)
        # (CASE (e & <mask>) WHEN 0 THEN '<name>' ELSE NULL END)

        els.append(
            pgast.CaseExpr(
                arg=pgast.Expr(kind=pgast.ExprKind.OP,
                               name='&',
                               lexpr=grouping_ref,
                               rexpr=pgast.LiteralExpr(expr=str(mask))),
                args=[
                    pgast.CaseWhen(expr=pgast.LiteralExpr(expr='0'),
                                   result=pgast.StringConstant(val=name))
                ],
                defresult=pgast.NullConstant()))

    val = pgast.FuncCall(
        name=('array_remove', ),
        args=[pgast.ArrayExpr(elements=els),
              pgast.NullConstant()])

    q.target_list.append(pgast.ResTarget(val=val))

    return q