mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-18 17:14:20 +01:00
fix handling of offset parameter set through variable
- before the fix db generated following plan: turso> EXPLAIN SELECT * FROM users LIMIT ? OFFSET ?; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 16 0 0 Start at 16 1 Variable 1 1 0 0 r[1]=parameter(1); OFFSET expr 2 MustBeInt 1 0 0 0 3 Variable 2 2 0 0 r[2]=parameter(2); OFFSET expr 4 MustBeInt 2 0 0 0 5 OffsetLimit 1 3 2 0 if r[1]>0 then r[3]=r[1]+max(0,r[2]) else r[3]=(-1) 6 OpenRead 0 2 0 0 table=users, root=2, iDb=0 7 Rewind 0 15 0 0 Rewind table users 8 Variable 2 2 0 0 r[2]=parameter(2); OFFSET expr 9 MustBeInt 2 0 0 0 10 IfPos 2 14 1 0 r[2]>0 -> r[2]-=1, goto 14 11 Column 0 0 4 0 r[4]=users.x 12 ResultRow 4 1 0 0 output=r[4] 13 DecrJumpZero 1 15 0 0 if (--r[1]==0) goto 15 14 Next 0 8 0 0 15 Halt 0 0 0 0 16 Transaction 0 1 1 0 iDb=0 tx_mode=Read 17 Goto 0 1 0 0 - the problem here is that Variable value is re-read at step 8 - which is wrong
This commit is contained in:
@@ -154,13 +154,7 @@ pub fn emit_order_by(
|
||||
});
|
||||
program.preassign_label_to_next_insn(sort_loop_start_label);
|
||||
|
||||
emit_offset(
|
||||
program,
|
||||
plan,
|
||||
sort_loop_next_label,
|
||||
t_ctx.reg_offset,
|
||||
&t_ctx.resolver,
|
||||
);
|
||||
emit_offset(program, sort_loop_next_label, t_ctx.reg_offset);
|
||||
|
||||
program.emit_insn(Insn::SorterData {
|
||||
cursor_id: sort_cursor,
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn emit_select_result(
|
||||
limit_ctx: Option<LimitCtx>,
|
||||
) -> Result<()> {
|
||||
if let (Some(jump_to), Some(_)) = (offset_jump_to, label_on_limit_reached) {
|
||||
emit_offset(program, plan, jump_to, reg_offset, resolver);
|
||||
emit_offset(program, jump_to, reg_offset);
|
||||
}
|
||||
|
||||
let start_reg = reg_result_cols_start;
|
||||
@@ -162,39 +162,14 @@ pub fn emit_result_row_and_limit(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn emit_offset(
|
||||
program: &mut ProgramBuilder,
|
||||
plan: &SelectPlan,
|
||||
jump_to: BranchOffset,
|
||||
reg_offset: Option<usize>,
|
||||
resolver: &Resolver,
|
||||
) {
|
||||
let Some(offset_expr) = &plan.offset else {
|
||||
pub fn emit_offset(program: &mut ProgramBuilder, jump_to: BranchOffset, reg_offset: Option<usize>) {
|
||||
let Some(reg_offset) = ®_offset else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(val) = try_fold_expr_to_i64(offset_expr) {
|
||||
if val > 0 {
|
||||
program.add_comment(program.offset(), "OFFSET const");
|
||||
program.emit_insn(Insn::IfPos {
|
||||
reg: reg_offset.expect("reg_offset must be Some"),
|
||||
target_pc: jump_to,
|
||||
decrement_by: 1,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let r = reg_offset.expect("reg_offset must be Some");
|
||||
|
||||
program.add_comment(program.offset(), "OFFSET expr");
|
||||
|
||||
_ = translate_expr(program, None, offset_expr, r, resolver);
|
||||
|
||||
program.emit_insn(Insn::MustBeInt { reg: r });
|
||||
|
||||
program.add_comment(program.offset(), "OFFSET const");
|
||||
program.emit_insn(Insn::IfPos {
|
||||
reg: r,
|
||||
reg: *reg_offset,
|
||||
target_pc: jump_to,
|
||||
decrement_by: 1,
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ fn emit_values_when_single_row(
|
||||
t_ctx: &TranslateCtx,
|
||||
) -> Result<usize> {
|
||||
let end_label = program.allocate_label();
|
||||
emit_offset(program, plan, end_label, t_ctx.reg_offset, &t_ctx.resolver);
|
||||
emit_offset(program, end_label, t_ctx.reg_offset);
|
||||
let first_row = &plan.values[0];
|
||||
let row_len = first_row.len();
|
||||
let start_reg = program.alloc_registers(row_len);
|
||||
@@ -87,7 +87,7 @@ fn emit_toplevel_values(
|
||||
});
|
||||
|
||||
let goto_label = program.allocate_label();
|
||||
emit_offset(program, plan, goto_label, t_ctx.reg_offset, &t_ctx.resolver);
|
||||
emit_offset(program, goto_label, t_ctx.reg_offset);
|
||||
let row_len = plan.values[0].len();
|
||||
let copy_start_reg = program.alloc_registers(row_len);
|
||||
for i in 0..row_len {
|
||||
|
||||
Reference in New Issue
Block a user