Fix evalauting expression for limit and offset.

This commit is contained in:
rajajisai
2025-10-12 22:46:25 -04:00
parent 99f2df3d70
commit cd763ce373
2 changed files with 93 additions and 63 deletions

View File

@@ -3,14 +3,13 @@ use crate::translate::collate::get_collseq_from_expr;
use crate::translate::emitter::{emit_query, LimitCtx, Resolver, TranslateCtx};
use crate::translate::expr::translate_expr;
use crate::translate::plan::{Plan, QueryDestination, SelectPlan};
use crate::translate::result_row::try_fold_expr_to_i64;
use crate::vdbe::builder::{CursorType, ProgramBuilder};
use crate::vdbe::insn::Insn;
use crate::vdbe::BranchOffset;
use crate::{emit_explain, QueryMode, SymbolTable};
use std::sync::Arc;
use tracing::instrument;
use turso_parser::ast::{CompoundOperator, SortOrder};
use turso_parser::ast::{CompoundOperator, Expr, Literal, SortOrder};
use tracing::Level;
@@ -43,34 +42,46 @@ pub fn emit_program_for_compound_select(
// the entire compound select, not just a single subselect.
let limit_ctx = limit.as_ref().map(|limit| {
let reg = program.alloc_register();
if let Some(val) = try_fold_expr_to_i64(limit) {
program.emit_insn(Insn::Integer {
value: val,
dest: reg,
});
} else {
program.add_comment(program.offset(), "OFFSET expr");
_ = translate_expr(program, None, limit, reg, &right_most_ctx.resolver);
program.emit_insn(Insn::MustBeInt { reg });
match limit.as_ref() {
Expr::Literal(Literal::Numeric(n)) => {
if let Ok(value) = n.parse::<i64>() {
program.add_comment(program.offset(), "LIMIT counter");
program.emit_insn(Insn::Integer { value, dest: reg });
} else {
let value = n.parse::<f64>().unwrap();
program.emit_insn(Insn::Real { value, dest: reg });
program.add_comment(program.offset(), "LIMIT counter");
program.emit_insn(Insn::MustBeInt { reg });
}
}
_ => {
_ = translate_expr(program, None, limit, reg, &right_most_ctx.resolver);
program.add_comment(program.offset(), "LIMIT counter");
program.emit_insn(Insn::MustBeInt { reg });
}
}
LimitCtx::new_shared(reg)
});
let offset_reg = offset.as_ref().map(|offset_expr| {
let reg = program.alloc_register();
if let Some(val) = try_fold_expr_to_i64(offset_expr) {
// Compile-time constant offset
program.emit_insn(Insn::Integer {
value: val,
dest: reg,
});
} else {
program.add_comment(program.offset(), "OFFSET expr");
_ = translate_expr(program, None, offset_expr, reg, &right_most_ctx.resolver);
program.emit_insn(Insn::MustBeInt { reg });
match offset_expr.as_ref() {
Expr::Literal(Literal::Numeric(n)) => {
// Compile-time constant offset
if let Ok(value) = n.parse::<i64>() {
program.emit_insn(Insn::Integer { value, dest: reg });
} else {
let value = n.parse::<f64>().unwrap();
program.emit_insn(Insn::Real { value, dest: reg });
}
}
_ => {
_ = translate_expr(program, None, offset_expr, reg, &right_most_ctx.resolver);
}
}
program.add_comment(program.offset(), "OFFSET counter");
program.emit_insn(Insn::MustBeInt { reg });
let combined_reg = program.alloc_register();
program.add_comment(program.offset(), "OFFSET + LIMIT");
program.emit_insn(Insn::OffsetLimit {
offset_reg: reg,
combined_reg,

View File

@@ -6,7 +6,7 @@ use std::num::NonZeroUsize;
use std::sync::Arc;
use tracing::{instrument, Level};
use turso_parser::ast::{self, Expr};
use turso_parser::ast::{self, Expr, Literal};
use super::aggregation::emit_ungrouped_aggregation;
use super::expr::translate_expr;
@@ -37,7 +37,6 @@ use crate::translate::fkeys::{
};
use crate::translate::plan::{DeletePlan, JoinedTable, Plan, QueryDestination, Search};
use crate::translate::planner::ROWID_STRS;
use crate::translate::result_row::try_fold_expr_to_i64;
use crate::translate::values::emit_values;
use crate::translate::window::{emit_window_results, init_window, WindowMetadata};
use crate::util::{exprs_are_equivalent, normalize_ident};
@@ -1964,52 +1963,72 @@ fn init_limit(
if limit_ctx.initialize_counter {
if let Some(expr) = limit {
if let Some(value) = try_fold_expr_to_i64(expr) {
program.emit_insn(Insn::Integer {
value,
dest: limit_ctx.reg_limit,
});
} else {
let r = limit_ctx.reg_limit;
program.add_comment(program.offset(), "OFFSET expr");
_ = translate_expr(program, None, expr, r, &t_ctx.resolver);
program.emit_insn(Insn::MustBeInt { reg: r });
match expr.as_ref() {
Expr::Literal(Literal::Numeric(n)) => {
if let Ok(value) = n.parse::<i64>() {
program.add_comment(program.offset(), "LIMIT counter");
program.emit_insn(Insn::Integer {
value,
dest: limit_ctx.reg_limit,
});
} else {
program.emit_insn(Insn::Real {
value: n.parse::<f64>().unwrap(),
dest: limit_ctx.reg_limit,
});
program.add_comment(program.offset(), "LIMIT counter");
program.emit_insn(Insn::MustBeInt {
reg: limit_ctx.reg_limit,
});
}
}
_ => {
let r = limit_ctx.reg_limit;
_ = translate_expr(program, None, expr, r, &t_ctx.resolver);
program.emit_insn(Insn::MustBeInt { reg: r });
}
}
}
}
if t_ctx.reg_offset.is_none() {
if let Some(expr) = offset {
if let Some(value) = try_fold_expr_to_i64(expr) {
if value != 0 {
let reg = program.alloc_register();
t_ctx.reg_offset = Some(reg);
program.emit_insn(Insn::Integer { value, dest: reg });
let combined_reg = program.alloc_register();
t_ctx.reg_limit_offset_sum = Some(combined_reg);
program.emit_insn(Insn::OffsetLimit {
limit_reg: limit_ctx.reg_limit,
offset_reg: reg,
combined_reg,
});
let offset_reg = program.alloc_register();
t_ctx.reg_offset = Some(offset_reg);
match expr.as_ref() {
Expr::Literal(Literal::Numeric(n)) => {
if let Ok(value) = n.parse::<i64>() {
program.emit_insn(Insn::Integer {
value,
dest: offset_reg,
});
} else {
let value = n.parse::<f64>().unwrap();
program.emit_insn(Insn::Real {
value,
dest: limit_ctx.reg_limit,
});
program.emit_insn(Insn::MustBeInt {
reg: limit_ctx.reg_limit,
});
}
}
_ => {
_ = translate_expr(program, None, expr, offset_reg, &t_ctx.resolver);
}
} else {
let reg = program.alloc_register();
t_ctx.reg_offset = Some(reg);
let r = reg;
program.add_comment(program.offset(), "OFFSET expr");
_ = translate_expr(program, None, expr, r, &t_ctx.resolver);
program.emit_insn(Insn::MustBeInt { reg: r });
let combined_reg = program.alloc_register();
t_ctx.reg_limit_offset_sum = Some(combined_reg);
program.emit_insn(Insn::OffsetLimit {
limit_reg: limit_ctx.reg_limit,
offset_reg: reg,
combined_reg,
});
}
program.add_comment(program.offset(), "OFFSET counter");
program.emit_insn(Insn::MustBeInt { reg: offset_reg });
let combined_reg = program.alloc_register();
t_ctx.reg_limit_offset_sum = Some(combined_reg);
program.add_comment(program.offset(), "OFFSET + LIMIT");
program.emit_insn(Insn::OffsetLimit {
limit_reg: limit_ctx.reg_limit,
offset_reg,
combined_reg,
});
}
}