Merge pull request #138 from jussisaurio/optimize-where

This commit is contained in:
Pekka Enberg
2024-07-14 08:09:39 +03:00
committed by GitHub
2 changed files with 84 additions and 14 deletions

View File

@@ -226,7 +226,7 @@ fn translate_select(mut select: Select) -> Result<Program> {
emit_limit_insn(&limit_info, &mut program);
}
if let Some((where_clause_label, where_reg)) = where_maybe {
if let Some(where_clause_label) = where_maybe {
program.resolve_label(where_clause_label, program.offset());
}
@@ -254,7 +254,7 @@ fn translate_select(mut select: Select) -> Result<Program> {
assert!(!select.exist_aggregation);
let where_maybe = insert_where_clause_instructions(&select, &mut program)?;
let (register_start, register_end) = translate_columns(&mut program, &select)?;
if let Some((where_clause_label, where_reg)) = where_maybe {
if let Some(where_clause_label) = where_maybe {
program.resolve_label(where_clause_label, program.offset() + 1);
}
program.emit_insn(Insn::ResultRow {
@@ -295,19 +295,11 @@ fn emit_limit_insn(limit_info: &Option<LimitInfo>, program: &mut ProgramBuilder)
fn insert_where_clause_instructions(
select: &Select,
program: &mut ProgramBuilder,
) -> Result<Option<(BranchOffset, usize)>> {
) -> Result<Option<BranchOffset>> {
if let Some(w) = &select.where_clause {
let where_reg = program.alloc_register();
let _ = translate_expr(program, &select, w, where_reg)?;
let label = program.allocate_label();
program.emit_insn_with_label_dependency(
Insn::IfNot {
reg: where_reg,
target_pc: label, // jump to 'next row' instruction if where not matched
},
label,
);
Ok(Some((label, where_reg))) // We emit a placeholder because we determine the jump target later (after we know where the 'cursor next' instruction is)
translate_condition_expr(program, &select, w, label)?;
Ok(Some(label))
} else {
Ok(None)
}
@@ -509,6 +501,84 @@ fn analyze_expr(expr: &Expr, column_info_out: &mut ColumnInfo) {
}
}
fn translate_condition_expr(
program: &mut ProgramBuilder,
select: &Select,
expr: &ast::Expr,
jump_target: BranchOffset,
) -> Result<()> {
match expr {
ast::Expr::Between { .. } => todo!(),
ast::Expr::Binary(e1, op, e2) => {
let e1_reg = program.alloc_register();
let e2_reg = program.alloc_register();
let _ = translate_expr(program, select, e1, e1_reg)?;
let _ = translate_expr(program, select, e2, e2_reg)?;
if jump_target < 0 {
program.add_label_dependency(jump_target, program.offset());
}
program.emit_insn(match op {
ast::Operator::NotEquals => Insn::Eq {
lhs: e1_reg,
rhs: e2_reg,
target_pc: jump_target,
},
ast::Operator::Equals => Insn::Ne {
lhs: e1_reg,
rhs: e2_reg,
target_pc: jump_target,
},
ast::Operator::Less => Insn::Ge {
lhs: e1_reg,
rhs: e2_reg,
target_pc: jump_target,
},
ast::Operator::LessEquals => Insn::Gt {
lhs: e1_reg,
rhs: e2_reg,
target_pc: jump_target,
},
ast::Operator::Greater => Insn::Le {
lhs: e1_reg,
rhs: e2_reg,
target_pc: jump_target,
},
ast::Operator::GreaterEquals => Insn::Lt {
lhs: e1_reg,
rhs: e2_reg,
target_pc: jump_target,
},
_ => todo!(),
});
Ok(())
}
ast::Expr::Literal(lit) => match lit {
ast::Literal::Numeric(val) => {
let maybe_int = val.parse::<i64>();
if let Ok(int_value) = maybe_int {
let reg = program.alloc_register();
program.emit_insn(Insn::Integer {
value: int_value,
dest: reg,
});
if jump_target < 0 {
program.add_label_dependency(jump_target, program.offset());
}
program.emit_insn(Insn::IfNot {
reg,
target_pc: jump_target,
});
Ok(())
} else {
anyhow::bail!("Parse error: unsupported literal type in condition");
}
}
_ => todo!(),
},
_ => todo!(),
}
}
fn translate_expr(
program: &mut ProgramBuilder,
select: &Select,

View File

@@ -298,7 +298,7 @@ impl ProgramBuilder {
(label.abs() - 1) as usize
}
fn add_label_dependency(&mut self, label: BranchOffset, insn_reference: BranchOffset) {
pub fn add_label_dependency(&mut self, label: BranchOffset, insn_reference: BranchOffset) {
assert!(insn_reference >= 0);
assert!(label < 0);
let label_index = self.label_to_index(label);