Merge 'Small VDBE insn tweaks' from Jussi Saurio

1. allow calling op_null with Insn::BeginSubrtn
    - BeginSubrtn is identical to Null, but named differently so that
its use in context is clearer
2. Insn::Return: add possibility to fallthrough on non-integer values as
per sqlite spec

Closes #1588
This commit is contained in:
Jussi Saurio
2025-05-27 20:19:31 +03:00
4 changed files with 33 additions and 14 deletions

View File

@@ -760,6 +760,7 @@ pub fn group_by_emit_row_phase<'a>(
});
program.emit_insn(Insn::Return {
return_reg: registers.reg_subrtn_acc_output_return_offset,
can_fallthrough: false,
});
program.resolve_label(labels.label_subrtn_acc_output, program.offset());
@@ -784,6 +785,7 @@ pub fn group_by_emit_row_phase<'a>(
}
program.emit_insn(Insn::Return {
return_reg: registers.reg_subrtn_acc_output_return_offset,
can_fallthrough: false,
});
// Finalize aggregate values for output
@@ -916,6 +918,7 @@ pub fn group_by_emit_row_phase<'a>(
program.emit_insn(Insn::Return {
return_reg: registers.reg_subrtn_acc_output_return_offset,
can_fallthrough: false,
});
// Subroutine to clear accumulators for a new group
@@ -955,6 +958,7 @@ pub fn group_by_emit_row_phase<'a>(
});
program.emit_insn(Insn::Return {
return_reg: registers.reg_subrtn_acc_clear_return_offset,
can_fallthrough: false,
});
program.preassign_label_to_next_insn(labels.label_group_by_end);
Ok(())

View File

@@ -322,15 +322,17 @@ pub fn op_null(
pager: &Rc<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
let Insn::Null { dest, dest_end } = insn else {
unreachable!("unexpected Insn {:?}", insn)
};
if let Some(dest_end) = dest_end {
for i in *dest..=*dest_end {
state.registers[i] = Register::Value(Value::Null);
match insn {
Insn::Null { dest, dest_end } | Insn::BeginSubrtn { dest, dest_end } => {
if let Some(dest_end) = dest_end {
for i in *dest..=*dest_end {
state.registers[i] = Register::Value(Value::Null);
}
} else {
state.registers[*dest] = Register::Value(Value::Null);
}
}
} else {
state.registers[*dest] = Register::Value(Value::Null);
_ => unreachable!("unexpected Insn {:?}", insn),
}
state.pc += 1;
Ok(InsnFunctionStepResult::Step)
@@ -1809,7 +1811,11 @@ pub fn op_return(
pager: &Rc<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
let Insn::Return { return_reg } = insn else {
let Insn::Return {
return_reg,
can_fallthrough,
} = insn
else {
unreachable!("unexpected Insn {:?}", insn)
};
if let Value::Integer(pc) = state.registers[*return_reg].get_owned_value() {
@@ -1818,9 +1824,12 @@ pub fn op_return(
.unwrap_or_else(|_| panic!("Return register is negative: {}", pc));
state.pc = pc;
} else {
return Err(LimboError::InternalError(
"Return register is not an integer".to_string(),
));
if !*can_fallthrough {
return Err(LimboError::InternalError(
"Return register is not an integer".to_string(),
));
}
state.pc += 1;
}
Ok(InsnFunctionStepResult::Step)
}

View File

@@ -625,11 +625,14 @@ pub fn insn_to_str(
0,
"".to_string(),
),
Insn::Return { return_reg } => (
Insn::Return {
return_reg,
can_fallthrough,
} => (
"Return",
*return_reg as i32,
0,
0,
*can_fallthrough as i32,
Value::build_text(""),
0,
"".to_string(),

View File

@@ -429,8 +429,11 @@ pub enum Insn {
},
/// Returns to the program counter stored in register 'return_reg'.
/// If can_fallthrough is true, fall through to the next instruction
/// if return_reg does not contain an integer value. Otherwise raise an error.
Return {
return_reg: usize,
can_fallthrough: bool,
},
/// Write an integer value into a register.