diff --git a/core/translate/expr.rs b/core/translate/expr.rs index b0b29bc1..2fa5fb95 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -704,6 +704,13 @@ pub fn translate_expr( dest: target_register, }); } + ast::Operator::Subtract => { + program.emit_insn(Insn::Subtract { + lhs: e1_reg, + rhs: e2_reg, + dest: target_register, + }); + } ast::Operator::Multiply => { program.emit_insn(Insn::Multiply { lhs: e1_reg, diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index b437b9d5..c21a3853 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -28,6 +28,15 @@ pub fn insn_to_str( 0, format!("r[{}]=r[{}]+r[{}]", dest, lhs, rhs), ), + Insn::Subtract { lhs, rhs, dest } => ( + "Subtract", + *lhs as i32, + *rhs as i32, + *dest as i32, + OwnedValue::Text(Rc::new("".to_string())), + 0, + format!("r[{}]=r[{}]-r[{}]", dest, lhs, rhs), + ), Insn::Multiply { lhs, rhs, dest } => ( "Multiply", *lhs as i32, diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 32216514..86da1c26 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -94,6 +94,12 @@ pub enum Insn { rhs: usize, dest: usize, }, + // Subtract rhs from lhs and store in dest + Subtract { + lhs: usize, + rhs: usize, + dest: usize, + }, // Multiply two registers and store the result in a third register. Multiply { lhs: usize, @@ -645,6 +651,60 @@ impl Program { } state.pc += 1; } + Insn::Subtract { lhs, rhs, dest } => { + let lhs = *lhs; + let rhs = *rhs; + let dest = *dest; + match (&state.registers[lhs], &state.registers[rhs]) { + (OwnedValue::Integer(lhs), OwnedValue::Integer(rhs)) => { + state.registers[dest] = OwnedValue::Integer(lhs - rhs); + } + (OwnedValue::Float(lhs), OwnedValue::Float(rhs)) => { + state.registers[dest] = OwnedValue::Float(lhs - rhs); + } + (OwnedValue::Float(lhs), OwnedValue::Integer(rhs)) + | (OwnedValue::Integer(rhs), OwnedValue::Float(lhs)) => { + state.registers[dest] = OwnedValue::Float(lhs - *rhs as f64); + } + (OwnedValue::Null, _) | (_, OwnedValue::Null) => { + state.registers[dest] = OwnedValue::Null; + } + (OwnedValue::Agg(aggctx), other) | (other, OwnedValue::Agg(aggctx)) => { + match other { + OwnedValue::Null => { + state.registers[dest] = OwnedValue::Null; + } + OwnedValue::Integer(i) => match aggctx.final_value() { + OwnedValue::Float(acc) => { + state.registers[dest] = OwnedValue::Float(acc - *i as f64); + } + OwnedValue::Integer(acc) => { + state.registers[dest] = OwnedValue::Integer(acc - i); + } + _ => { + todo!("{:?}", aggctx); + } + }, + OwnedValue::Float(f) => match aggctx.final_value() { + OwnedValue::Float(acc) => { + state.registers[dest] = OwnedValue::Float(acc - f); + } + OwnedValue::Integer(acc) => { + state.registers[dest] = OwnedValue::Float(*acc as f64 - f); + } + _ => { + todo!("{:?}", aggctx); + } + }, + rest => unimplemented!("{:?}", rest), + } + } + others => { + todo!("{:?}", others); + } + } + state.pc += 1; + } Insn::Multiply { lhs, rhs, dest } => { let lhs = *lhs; let rhs = *rhs; diff --git a/testing/select.test b/testing/select.test index d69f3c07..26d981d7 100755 --- a/testing/select.test +++ b/testing/select.test @@ -35,6 +35,10 @@ do_execsql_test select-add { select u.age + 1 from users u where u.age = 91 limit 1; } {92} +do_execsql_test select-subtract { + select u.age - 1 from users u where u.age = 91 limit 1; +} {90} + do_execsql_test case-insensitive-columns { select u.aGe + 1 from USERS u where U.AGe = 91 limit 1; } {92}