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)
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
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)
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
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