def join_condition(lref: pgast.ColumnRef, rref: pgast.ColumnRef) -> pgast.Base: if lref.nullable or rref.nullable: op = 'IS NOT DISTINCT FROM' else: op = '=' path_cond = new_binop(lref, rref, op=op) if lref.optional: opt_cond = pgast.NullTest(arg=lref) path_cond = extend_binop(path_cond, opt_cond, op='OR') if rref.optional: opt_cond = pgast.NullTest(arg=rref) path_cond = extend_binop(path_cond, opt_cond, op='OR') return path_cond
def compile_SelectStmt(stmt: irast.SelectStmt, *, ctx: context.CompilerContextLevel) -> pgast.Query: if ctx.env.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 iterator_set = stmt.iterator_stmt if (iterator_set is not None and not isinstance(stmt.result.expr, irast.MutatingStmt)): # 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. query.where_clause = astutils.extend_binop( query.where_clause, clauses.compile_filter_clause(stmt.where, ctx=ctx)) if outvar.nullable and query is ctx.toplevel_stmt: # A nullable var has bubbled up to the top, # filter out NULLs. valvar = 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 _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 if is_terminal_relation(rel): return _get_rel_path_output(rel, path_id, aspect=aspect, ptr_info=ptr_info, env=env) 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: rel.path_outputs[path_id, aspect] = other_output 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): assert isinstance(ref, pgast.ColumnRef) result = dbobj.get_column(None, ref) else: alias = get_path_output_alias(path_id, aspect, env=env) restarget = pgast.ResTarget(name=alias, val=ref) 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) rel.path_outputs[path_id, aspect] = result return result