Exemplo n.º 1
0
def update_scope(ir_set: irast.Set, stmt: pgast.SelectStmt, *,
                 ctx: context.CompilerContextLevel) -> None:

    scope_tree = get_scope(ir_set, ctx=ctx)
    if scope_tree is None:
        return

    ctx.scope_tree = scope_tree
    ctx.path_scope = ctx.path_scope.new_child()

    for p in scope_tree.path_children:
        assert p.path_id is not None
        ctx.path_scope[p.path_id] = stmt

    if isinstance(ir_set.expr, irast.Stmt):
        iterators = irutils.get_iterator_sets(ir_set.expr)
        iter_paths = {it.path_id for it in iterators}
    else:
        iter_paths = set()

    for child_path in scope_tree.get_all_paths():
        parent_scope = scope_tree.parent
        if ((parent_scope is None or not parent_scope.is_visible(child_path))
                and child_path not in iter_paths):
            stmt.path_id_mask.add(child_path)
Exemplo n.º 2
0
def compile_SelectStmt(
        stmt: irast.SelectStmt, *,
        ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    if ctx.singleton_mode:
        return dispatch.compile(stmt.result, ctx=ctx)

    parent_ctx = ctx
    with parent_ctx.substmt() as ctx:
        # Common setup.
        clauses.init_stmt(stmt, ctx=ctx, parent_ctx=parent_ctx)

        query = ctx.stmt

        if not isinstance(stmt.result.expr, irast.MutatingStmt):
            iterators = irutils.get_iterator_sets(stmt)
            for iterator_set in iterators:
                # Process FOR clause.
                clauses.compile_iterator_expr(query, iterator_set, ctx=ctx)

        # Process the result expression;
        outvar = clauses.compile_output(stmt.result, ctx=ctx)

        # The FILTER clause.
        if stmt.where is not None:
            query.where_clause = astutils.extend_binop(
                query.where_clause,
                clauses.compile_filter_clause(
                    stmt.where, stmt.where_card, ctx=ctx))

        if outvar.nullable and query is ctx.toplevel_stmt:
            # A nullable var has bubbled up to the top,
            # filter out NULLs.
            valvar: pgast.BaseExpr = pathctx.get_path_value_var(
                query, stmt.result.path_id, env=ctx.env)
            if isinstance(valvar, pgast.TupleVar):
                valvar = pgast.ImplicitRowExpr(
                    args=[e.val for e in valvar.elements])

            query.where_clause = astutils.extend_binop(
                query.where_clause,
                pgast.NullTest(arg=valvar, negated=True)
            )

        # The ORDER BY clause
        query.sort_clause = clauses.compile_orderby_clause(
            stmt.orderby, ctx=ctx)

        # The OFFSET clause
        query.limit_offset = clauses.compile_limit_offset_clause(
            stmt.offset, ctx=ctx)

        # The LIMIT clause
        query.limit_count = clauses.compile_limit_offset_clause(
            stmt.limit, ctx=ctx)

        clauses.fini_stmt(query, ctx, parent_ctx)

    return query
Exemplo n.º 3
0
def compile_shape(
        ir_set: irast.Set, shape: List[irast.Set], *,
        ctx: context.CompilerContextLevel) -> pgast.TupleVar:
    elements = []

    with ctx.newscope() as shapectx:
        shapectx.disable_semi_join.add(ir_set.path_id)

        if isinstance(ir_set.expr, irast.Stmt):
            iterators = irutils.get_iterator_sets(ir_set.expr)
            # The source set for this shape is a FOR statement,
            # which is special in that besides set path_id it
            # should also expose the path_id of the FOR iterator
            # so that shape element expressions that might contain
            # an iterator reference find it properly.
            #
            # So, for:
            #    SELECT Bar {
            #        foo := (FOR x := ... UNION Foo { spam := x })
            #    }
            #
            # the path scope when processing the shape of Bar.foo
            # should be {'Bar.foo', 'x'}.
            if iterators:
                for iterator in iterators:
                    shapectx.path_scope[iterator.path_id] = ctx.rel

        for el in shape:
            rptr = el.rptr
            assert rptr is not None
            ptrref = rptr.ptrref
            is_singleton = ptrref.dir_cardinality.is_single()
            value: pgast.BaseExpr

            if (irutils.is_subquery_set(el) or
                    el.path_id.is_objtype_path() or
                    not is_singleton or
                    not ptrref.required):
                wrapper = relgen.set_as_subquery(
                    el, as_value=True, ctx=shapectx)
                if not is_singleton:
                    value = relgen.set_to_array(
                        ir_set=el, query=wrapper, ctx=shapectx)
                else:
                    value = wrapper
            else:
                value = dispatch.compile(el, ctx=shapectx)

            tuple_el = astutils.tuple_element_for_shape_el(
                el, value, ctx=shapectx)

            assert isinstance(tuple_el, pgast.TupleElement)
            elements.append(tuple_el)

    return pgast.TupleVar(elements=elements, named=True)
Exemplo n.º 4
0
def compile_SelectStmt(stmt: irast.SelectStmt, *,
                       ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    if ctx.singleton_mode:
        return dispatch.compile(stmt.result, ctx=ctx)

    parent_ctx = ctx
    with parent_ctx.substmt() as ctx:
        # Common setup.
        clauses.init_stmt(stmt, ctx=ctx, parent_ctx=parent_ctx)

        query = ctx.stmt

        iterators = irutils.get_iterator_sets(stmt)
        if iterators and irutils.contains_dml(stmt):
            # If we have iterators and we contain nested DML
            # statements, we need to hoist the iterators into CTEs and
            # then explicitly join them back into the query.
            iterator = dml.compile_iterator_ctes(iterators, ctx=ctx)
            ctx.path_scope = ctx.path_scope.new_child()
            dml.merge_iterator(iterator, ctx.rel, ctx=ctx)

            ctx.enclosing_cte_iterator = iterator

        else:
            iterator = None
            for iterator_set in iterators:
                # Process FOR clause.
                iterator_rvar = clauses.compile_iterator_expr(query,
                                                              iterator_set,
                                                              ctx=ctx)
                for aspect in {'identity', 'value'}:
                    pathctx.put_path_rvar(
                        query,
                        path_id=iterator_set.path_id,
                        rvar=iterator_rvar,
                        aspect=aspect,
                        env=ctx.env,
                    )

        # Process the result expression;
        outvar = clauses.compile_output(stmt.result, ctx=ctx)

        # The FILTER clause.
        if stmt.where is not None:
            query.where_clause = astutils.extend_binop(
                query.where_clause,
                clauses.compile_filter_clause(stmt.where,
                                              stmt.where_card,
                                              ctx=ctx))

        if outvar.nullable and query is ctx.toplevel_stmt:
            # A nullable var has bubbled up to the top,
            # filter out NULLs.
            valvar: pgast.BaseExpr = pathctx.get_path_value_var(
                query, stmt.result.path_id, env=ctx.env)
            if isinstance(valvar, pgast.TupleVar):
                valvar = pgast.ImplicitRowExpr(
                    args=[e.val for e in valvar.elements])

            query.where_clause = astutils.extend_binop(
                query.where_clause, pgast.NullTest(arg=valvar, negated=True))

        # The ORDER BY clause
        query.sort_clause = clauses.compile_orderby_clause(stmt.orderby,
                                                           ctx=ctx)

        # The OFFSET clause
        query.limit_offset = clauses.compile_limit_offset_clause(stmt.offset,
                                                                 ctx=ctx)

        # The LIMIT clause
        query.limit_count = clauses.compile_limit_offset_clause(stmt.limit,
                                                                ctx=ctx)

        clauses.fini_stmt(query, ctx, parent_ctx)

    return query
Exemplo n.º 5
0
def compile_SelectStmt(
        stmt: irast.SelectStmt, *,
        ctx: context.CompilerContextLevel) -> pgast.BaseExpr:

    if ctx.singleton_mode:
        return dispatch.compile(stmt.result, ctx=ctx)

    parent_ctx = ctx
    with parent_ctx.substmt() as ctx:
        # Common setup.
        clauses.init_stmt(stmt, ctx=ctx, parent_ctx=parent_ctx)

        for binding in stmt.bindings:
            # If something we are WITH binding contains DML, we want to
            # compile it *now*, in the context of its initial appearance
            # and not where the variable is used. This will populate
            # dml_stmts with the CTEs, which will be picked up when the
            # variable is referenced.
            if irutils.contains_dml(binding):
                with ctx.substmt() as bctx:
                    dispatch.compile(binding, ctx=bctx)

        query = ctx.stmt

        iterators = irutils.get_iterator_sets(stmt)
        last_iterator: Optional[irast.Set] = None
        if iterators and irutils.contains_dml(stmt):
            # If we have iterators and we contain nested DML
            # statements, we need to hoist the iterators into CTEs and
            # then explicitly join them back into the query.
            iterator = dml.compile_iterator_ctes(iterators, ctx=ctx)
            ctx.path_scope = ctx.path_scope.new_child()
            dml.merge_iterator(iterator, ctx.rel, ctx=ctx)

            ctx.enclosing_cte_iterator = iterator
            last_iterator = iterators[-1]

        else:
            for iterator_set in iterators:
                # Process FOR clause.
                with ctx.new() as ictx:
                    clauses.setup_iterator_volatility(last_iterator, ctx=ictx)
                    iterator_rvar = clauses.compile_iterator_expr(
                        query, iterator_set, ctx=ictx)
                for aspect in {'identity', 'value'}:
                    pathctx.put_path_rvar(
                        query,
                        path_id=iterator_set.path_id,
                        rvar=iterator_rvar,
                        aspect=aspect,
                        env=ctx.env,
                    )
                last_iterator = iterator_set

        # Process the result expression.
        with ctx.new() as ictx:
            clauses.setup_iterator_volatility(last_iterator, ctx=ictx)
            outvar = clauses.compile_output(stmt.result, ctx=ictx)

        with ctx.new() as ictx:
            # FILTER and ORDER BY need to have the base result as a
            # volatility ref.
            clauses.setup_iterator_volatility(stmt.result, ctx=ictx)

            # The FILTER clause.
            if stmt.where is not None:
                query.where_clause = astutils.extend_binop(
                    query.where_clause,
                    clauses.compile_filter_clause(
                        stmt.where, stmt.where_card, ctx=ctx))

            # The ORDER BY clause
            with ctx.new() as ictx:
                query.sort_clause = clauses.compile_orderby_clause(
                    stmt.orderby, ctx=ictx)

        if outvar.nullable and query is ctx.toplevel_stmt:
            # A nullable var has bubbled up to the top,
            # filter out NULLs.
            valvar: pgast.BaseExpr = pathctx.get_path_value_var(
                query, stmt.result.path_id, env=ctx.env)
            if isinstance(valvar, pgast.TupleVar):
                valvar = pgast.ImplicitRowExpr(
                    args=[e.val for e in valvar.elements])

            query.where_clause = astutils.extend_binop(
                query.where_clause,
                pgast.NullTest(arg=valvar, negated=True)
            )

        # The OFFSET clause
        query.limit_offset = clauses.compile_limit_offset_clause(
            stmt.offset, ctx=ctx)

        # The LIMIT clause
        query.limit_count = clauses.compile_limit_offset_clause(
            stmt.limit, ctx=ctx)

        clauses.fini_stmt(query, ctx, parent_ctx)

    return query