diff --git a/core/translate.rs b/core/translate.rs index f4c69efb9..f9b77deda 100644 --- a/core/translate.rs +++ b/core/translate.rs @@ -226,7 +226,7 @@ fn translate_select(mut select: Select) -> Result { 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 { 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, program: &mut ProgramBuilder) fn insert_where_clause_instructions( select: &Select, program: &mut ProgramBuilder, -) -> Result> { +) -> Result> { 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::(); + 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, diff --git a/core/vdbe.rs b/core/vdbe.rs index 7f65c3d41..87700c82d 100644 --- a/core/vdbe.rs +++ b/core/vdbe.rs @@ -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);