Move where clause literal out of loop

This commit is contained in:
Bennett Clement
2024-07-14 14:00:25 +08:00
parent e9647bf425
commit a85f47310c
2 changed files with 29 additions and 0 deletions

View File

@@ -269,6 +269,7 @@ fn translate_select(mut select: Select) -> Result<Program> {
}
program.resolve_label(init_label, program.offset());
program.emit_insn(Insn::Transaction);
program.emit_run_once_insns();
program.emit_insn(Insn::Goto {
target_pc: start_offset,
});
@@ -501,7 +502,15 @@ fn translate_condition_expr(
let e1_reg = program.alloc_register();
let e2_reg = program.alloc_register();
let _ = translate_expr(program, select, e1, e1_reg)?;
match e1.as_ref() {
ast::Expr::Literal(_) => program.move_last_insn_out_of_loop(),
_ => {}
}
let _ = translate_expr(program, select, e2, e2_reg)?;
match e2.as_ref() {
ast::Expr::Literal(_) => program.move_last_insn_out_of_loop(),
_ => {}
}
if jump_target < 0 {
program.add_label_dependency(jump_target, program.offset());
}
@@ -1030,6 +1039,7 @@ fn translate_pragma(
program.emit_insn(Insn::Halt);
program.resolve_label(init_label, program.offset());
program.emit_insn(Insn::Transaction);
program.emit_run_once_insns();
program.emit_insn(Insn::Goto {
target_pc: start_offset,
});

View File

@@ -225,6 +225,8 @@ pub struct ProgramBuilder {
next_free_label: BranchOffset,
next_free_cursor_id: usize,
insns: Vec<Insn>,
// for temporarily storing instructions that will be put after Transaction opcode
run_once_insns: Vec<Insn>,
// Each label has a list of InsnReferences that must
// be resolved. Lists are indexed by: label.abs() - 1
unresolved_labels: Vec<Vec<InsnReference>>,
@@ -243,6 +245,7 @@ impl ProgramBuilder {
unresolved_labels: Vec::new(),
next_insn_label: None,
cursor_ref: Vec::new(),
run_once_insns: Vec::new(),
}
}
@@ -281,6 +284,18 @@ impl ProgramBuilder {
}
}
// Emit an instruction that will be put at the end of the program (after Transaction statement).
// This is useful for instructions that otherwise will be unnecessarily repeated in a loop.
// Example: In `SELECT * from users where name='John'`, it is unnecessary to set r[1]='John' as we SCAN users table.
// We could simply set it once before the SCAN started.
pub fn move_last_insn_out_of_loop(&mut self) {
self.run_once_insns.push(self.insns.pop().unwrap());
}
pub fn emit_run_once_insns(&mut self) {
self.insns.extend(self.run_once_insns.drain(..));
}
pub fn emit_insn_with_label_dependency(&mut self, insn: Insn, label: BranchOffset) {
self.insns.push(insn);
self.add_label_dependency(label, (self.insns.len() - 1) as BranchOffset);
@@ -430,6 +445,10 @@ impl ProgramBuilder {
}
pub fn build(self) -> Program {
assert!(
self.run_once_insns.is_empty(),
"run_once_insns is not empty when build() is called, did you forget to call emit_run_once_insns()?"
);
Program {
max_registers: self.next_free_register,
insns: self.insns,