From f08d62b446db6820885179247c29d0b8cb0e3bbd Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Fri, 27 Dec 2024 15:38:07 -0500 Subject: [PATCH 1/3] Add Remainder vdbe oppcode --- core/translate/expr.rs | 7 +++ core/vdbe/explain.rs | 9 ++++ core/vdbe/mod.rs | 103 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 275851201..10405f97c 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -693,6 +693,13 @@ pub fn translate_expr( dest: target_register, }); } + ast::Operator::Modulus => { + program.emit_insn(Insn::Remainder { + lhs: e1_reg, + rhs: e2_reg, + dest: target_register, + }); + } ast::Operator::BitwiseAnd => { program.emit_insn(Insn::BitAnd { lhs: e1_reg, diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index a2d722948..28a87b2d6 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -82,6 +82,15 @@ pub fn insn_to_str( 0, format!("r[{}]=~r[{}]", dest, reg), ), + Insn::Remainder { lhs, rhs, dest } => ( + "Modulus", + *lhs as i32, + *rhs as i32, + *dest as i32, + OwnedValue::build_text(Rc::new("".to_string())), + 0, + format!("r[{}]=r[{}]%r[{}]", dest, lhs, rhs), + ), Insn::Null { dest, dest_end } => ( "Null", 0, diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 980aab282..01c0b3cd1 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -119,6 +119,12 @@ pub enum Insn { reg: usize, dest: usize, }, + // Divide lhs by rhs and place the remainder in dest register. + Remainder { + lhs: usize, + rhs: usize, + dest: usize, + }, // Jump to the instruction at address P1, P2, or P3 depending on whether in the most recent Compare instruction the P1 vector was less than, equal to, or greater than the P2 vector, respectively. Jump { target_pc_lt: BranchOffset, @@ -1224,6 +1230,103 @@ impl Program { } state.pc += 1; } + Insn::Remainder { lhs, rhs, dest } => { + let lhs = *lhs; + let rhs = *rhs; + let dest = *dest; + state.registers[dest] = match (&state.registers[lhs], &state.registers[rhs]) { + (OwnedValue::Null, _) + | (_, OwnedValue::Null) + | (_, OwnedValue::Integer(0)) + | (_, OwnedValue::Float(0.0)) => OwnedValue::Null, + (OwnedValue::Integer(lhs), OwnedValue::Integer(rhs)) => { + OwnedValue::Integer(lhs % rhs) + } + (OwnedValue::Float(lhs), OwnedValue::Float(rhs)) => { + OwnedValue::Float(((*lhs as i64) % (*rhs as i64)) as f64) + } + (OwnedValue::Float(lhs), OwnedValue::Integer(rhs)) => { + OwnedValue::Float(((*lhs as i64) % rhs) as f64) + } + (OwnedValue::Integer(lhs), OwnedValue::Float(rhs)) => { + OwnedValue::Float((lhs % *rhs as i64) as f64) + } + (lhs, OwnedValue::Agg(agg_rhs)) => match lhs { + OwnedValue::Agg(agg_lhs) => { + let acc = agg_lhs.final_value(); + let acc2 = agg_rhs.final_value(); + match (acc, acc2) { + (_, OwnedValue::Integer(0)) + | (_, OwnedValue::Float(0.0)) + | (_, OwnedValue::Null) + | (OwnedValue::Null, _) => OwnedValue::Null, + (OwnedValue::Integer(l), OwnedValue::Integer(r)) => { + OwnedValue::Integer(l % r) + } + (OwnedValue::Float(lh_f), OwnedValue::Float(rh_f)) => { + OwnedValue::Float(((*lh_f as i64) % (*rh_f as i64)) as f64) + } + (OwnedValue::Integer(lh_i), OwnedValue::Float(rh_f)) => { + OwnedValue::Float((lh_i % (*rh_f as i64)) as f64) + } + _ => { + todo!("{:?} {:?}", acc, acc2); + } + } + } + OwnedValue::Integer(lh_i) => match agg_rhs.final_value() { + OwnedValue::Null => OwnedValue::Null, + OwnedValue::Float(rh_f) => { + OwnedValue::Float((lh_i % (*rh_f as i64)) as f64) + } + OwnedValue::Integer(rh_i) => OwnedValue::Integer(lh_i % rh_i), + _ => { + todo!("{:?}", agg_rhs); + } + }, + OwnedValue::Float(lh_f) => match agg_rhs.final_value() { + OwnedValue::Null => OwnedValue::Null, + OwnedValue::Float(rh_f) => { + OwnedValue::Float(((*lh_f as i64) % (*rh_f as i64)) as f64) + } + OwnedValue::Integer(rh_i) => { + OwnedValue::Float(((*lh_f as i64) % rh_i) as f64) + } + _ => { + todo!("{:?}", agg_rhs); + } + }, + _ => todo!("{:?}", rhs), + }, + (OwnedValue::Agg(aggctx), rhs) => match rhs { + OwnedValue::Integer(rh_i) => match aggctx.final_value() { + OwnedValue::Null => OwnedValue::Null, + OwnedValue::Float(lh_f) => { + OwnedValue::Float(((*lh_f as i64) % rh_i) as f64) + } + OwnedValue::Integer(lh_i) => OwnedValue::Integer(lh_i % rh_i), + _ => { + todo!("{:?}", aggctx); + } + }, + OwnedValue::Float(rh_f) => match aggctx.final_value() { + OwnedValue::Null => OwnedValue::Null, + OwnedValue::Float(lh_f) => { + OwnedValue::Float(((*lh_f as i64) % (*rh_f as i64)) as f64) + } + OwnedValue::Integer(lh_i) => { + OwnedValue::Float((lh_i % (*rh_f as i64)) as f64) + } + _ => { + todo!("{:?}", aggctx); + } + }, + _ => todo!("{:?}", rhs), + }, + _ => todo!("{:?} {:?}", state.registers[lhs], state.registers[rhs]), + }; + state.pc += 1; + } Insn::Null { dest, dest_end } => { if let Some(dest_end) = dest_end { for i in *dest..=*dest_end { From 82de59dd88bd2c8f4e9be7054bd8d99d42d2743c Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Fri, 27 Dec 2024 15:38:29 -0500 Subject: [PATCH 2/3] Add compatability tests for mod operator --- testing/math.test | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/testing/math.test b/testing/math.test index 7b27495e3..9dc517755 100644 --- a/testing/math.test +++ b/testing/math.test @@ -1025,3 +1025,51 @@ do_execsql_test log-null-int { do_execsql_test log-int-null { SELECT log(5, null) } {} + +do_execsql_test mod-int-null { + SELECT 183 % null +} {} + +do_execsql_test mod-int-0 { + SELECT 183 % 0 +} {} + +do_execsql_test mod-int-int { + SELECT 183 % 10 +} { 3 } + +do_execsql_test mod-int-float { + SELECT 38 % 10.35 +} { 8.0 } + +do_execsql_test mod-float-int { + SELECT 38.43 % 13 +} { 12.0 } + +do_execsql_test mod-0-float { + SELECT 0 % 12.0 +} { 0.0 } + +do_execsql_test mod-float-0 { + SELECT 23.14 % 0 +} {} + +do_execsql_test mod-float-float { + SELECT 23.14 % 12.0 +} { 11.0 } + +do_execsql_test mod-float-agg { + SELECT 23.14 % sum(id) from products +} { 23.0 } + +do_execsql_test mod-int-agg { + SELECT 17 % sum(id) from users +} { 17 } + +do_execsql_test mod-agg-int { + SELECT count(*) % 17 from users +} { 4 } + +do_execsql_test mod-agg-float { + SELECT count(*) % 2.43 from users +} { 0.0 } From ddf229c4329392d62dac22018a4a9be15022cc38 Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Fri, 27 Dec 2024 15:38:44 -0500 Subject: [PATCH 3/3] Update COMPAT.md --- COMPAT.md | 2 +- core/vdbe/explain.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 71a00290b..1cdc475a8 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -395,7 +395,7 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html). | ReadCookie | No | | Real | Yes | | RealAffinity | Yes | -| Remainder | No | +| Remainder | Yes | | ResetCount | No | | ResultRow | Yes | | Return | Yes | diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index 28a87b2d6..a17ababcf 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -83,7 +83,7 @@ pub fn insn_to_str( format!("r[{}]=~r[{}]", dest, reg), ), Insn::Remainder { lhs, rhs, dest } => ( - "Modulus", + "Remainder", *lhs as i32, *rhs as i32, *dest as i32,