mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-03 16:34:19 +01:00
TLDR: no need to call either of: program.emit_insn_with_label_dependency() -> just call program.emit_insn() program.defer_label_resolution() -> just call program.resolve_label() Changes: - make BranchOffset an explicit enum (Label, Offset, Placeholder) - remove program.emit_insn_with_label_dependency() - label dependency is automatically detected - for label to offset mapping, use a hashmap from label(negative i32) to offset (positive u32) - resolve all labels in program.build() - remove program.defer_label_resolution() - all labels are resolved in build()
81 lines
2.4 KiB
Rust
81 lines
2.4 KiB
Rust
use crate::{
|
|
vdbe::{builder::ProgramBuilder, insn::Insn, BranchOffset},
|
|
Result,
|
|
};
|
|
|
|
use super::{
|
|
emitter::TranslateCtx,
|
|
expr::translate_expr,
|
|
plan::{SelectPlan, SelectQueryType},
|
|
};
|
|
|
|
/// Emits the bytecode for:
|
|
/// - all result columns
|
|
/// - result row (or if a subquery, yields to the parent query)
|
|
/// - limit
|
|
pub fn emit_select_result(
|
|
program: &mut ProgramBuilder,
|
|
t_ctx: &mut TranslateCtx,
|
|
plan: &SelectPlan,
|
|
label_on_limit_reached: Option<BranchOffset>,
|
|
) -> Result<()> {
|
|
let start_reg = t_ctx.reg_result_cols_start.unwrap();
|
|
for (i, rc) in plan.result_columns.iter().enumerate() {
|
|
let reg = start_reg + i;
|
|
translate_expr(
|
|
program,
|
|
Some(&plan.referenced_tables),
|
|
&rc.expr,
|
|
reg,
|
|
&t_ctx.resolver,
|
|
)?;
|
|
}
|
|
emit_result_row_and_limit(program, t_ctx, plan, start_reg, label_on_limit_reached)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Emits the bytecode for:
|
|
/// - result row (or if a subquery, yields to the parent query)
|
|
/// - limit
|
|
pub fn emit_result_row_and_limit(
|
|
program: &mut ProgramBuilder,
|
|
t_ctx: &mut TranslateCtx,
|
|
plan: &SelectPlan,
|
|
result_columns_start_reg: usize,
|
|
label_on_limit_reached: Option<BranchOffset>,
|
|
) -> Result<()> {
|
|
match &plan.query_type {
|
|
SelectQueryType::TopLevel => {
|
|
program.emit_insn(Insn::ResultRow {
|
|
start_reg: result_columns_start_reg,
|
|
count: plan.result_columns.len(),
|
|
});
|
|
}
|
|
SelectQueryType::Subquery { yield_reg, .. } => {
|
|
program.emit_insn(Insn::Yield {
|
|
yield_reg: *yield_reg,
|
|
end_offset: BranchOffset::Offset(0),
|
|
});
|
|
}
|
|
}
|
|
|
|
if let Some(limit) = plan.limit {
|
|
if label_on_limit_reached.is_none() {
|
|
// There are cases where LIMIT is ignored, e.g. aggregation without a GROUP BY clause.
|
|
// We already early return on LIMIT 0, so we can just return here since the n of rows
|
|
// is always 1 here.
|
|
return Ok(());
|
|
}
|
|
program.emit_insn(Insn::Integer {
|
|
value: limit as i64,
|
|
dest: t_ctx.reg_limit.unwrap(),
|
|
});
|
|
program.mark_last_insn_constant();
|
|
program.emit_insn(Insn::DecrJumpZero {
|
|
reg: t_ctx.reg_limit.unwrap(),
|
|
target_pc: label_on_limit_reached.unwrap(),
|
|
});
|
|
}
|
|
Ok(())
|
|
}
|