Fix register reuse when called inside a coroutine

- On each interaction we assume that the value is NULL, so we need to
  set it like so for every interaction in the list. So we force to not
  emit this NULL as constant;
- Forces a copy so IN expressions works inside an aggregation
  expression. Not ideal but it works, we should work more on the query
  planner for sure.
This commit is contained in:
Diego Reis
2025-10-07 16:54:50 -03:00
parent da323fa0c4
commit 625403cc2a
2 changed files with 36 additions and 10 deletions

View File

@@ -43,6 +43,13 @@ pub struct ReturningValueRegisters {
pub num_columns: usize,
}
/// Emit an instruction that is guaranteed not to be in any constant span.
/// This ensures the instruction won't be hoisted when emit_constant_insns is called.
fn emit_no_constant_insn(program: &mut ProgramBuilder, insn: Insn) {
program.constant_span_end_all();
program.emit_insn(insn);
}
#[instrument(skip_all, level = Level::DEBUG)]
fn emit_cond_jump(program: &mut ProgramBuilder, cond_meta: ConditionMetadata, reg: usize) {
if cond_meta.jump_if_condition_is_true {
@@ -2073,16 +2080,28 @@ pub fn translate_expr(
// but wrap it with appropriate expression context handling
let result_reg = target_register;
program.emit_insn(Insn::Null {
dest: result_reg,
dest_end: None,
});
let dest_if_false = program.allocate_label();
let dest_if_null = program.allocate_label();
// won't use this label :/
let dest_if_true = program.allocate_label();
let tmp = program.alloc_register();
emit_no_constant_insn(
program,
Insn::Null {
dest: tmp,
dest_end: None,
},
);
translate_expr_no_constant_opt(
program,
referenced_tables,
&ast::Expr::Literal(ast::Literal::Null),
tmp,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
// Call the core InList logic with expression-appropriate condition metadata
translate_in_list(
program,
@@ -2101,22 +2120,27 @@ pub fn translate_expr(
// condition true: set result to 1
program.emit_insn(Insn::Integer {
value: 1,
dest: result_reg,
dest: tmp,
});
// False path: set result to 0
program.resolve_label(dest_if_false, program.offset());
// Force integer conversion with AddImm 0
program.emit_insn(Insn::AddImm {
register: result_reg,
register: tmp,
value: 0,
});
if *not {
program.emit_insn(Insn::Not {
reg: result_reg,
dest: result_reg,
reg: tmp,
dest: tmp,
});
}
program.resolve_label(dest_if_null, program.offset());
program.emit_insn(Insn::Copy {
src_reg: tmp,
dst_reg: result_reg,
extra_amount: 0,
});
Ok(result_reg)
}
ast::Expr::InSelect { .. } => {

View File

@@ -853,10 +853,12 @@ pub enum Insn {
db: usize,
},
/// Make a copy of register src..src+extra_amount into dst..dst+extra_amount.
Copy {
src_reg: usize,
dst_reg: usize,
extra_amount: usize, // 0 extra_amount means we include src_reg, dst_reg..=dst_reg+amount = src_reg..=src_reg+amount
/// 0 extra_amount means we include src_reg, dst_reg..=dst_reg+amount = src_reg..=src_reg+amount
extra_amount: usize,
},
/// Allocate a new b-tree.