diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index 439a3ff2e..d8dcb1c86 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -489,6 +489,16 @@ pub enum Insn { }, } +fn cast_text_to_numerical(value: &str) -> OwnedValue { + if let Ok(x) = value.parse::() { + OwnedValue::Integer(x) + } else if let Ok(x) = value.parse::() { + OwnedValue::Float(x) + } else { + OwnedValue::Integer(0) + } +} + pub fn exec_add(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { if let OwnedValue::Agg(agg) = lhs { lhs = agg.final_value(); @@ -502,6 +512,13 @@ pub fn exec_add(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { (OwnedValue::Float(f), OwnedValue::Integer(i)) | (OwnedValue::Integer(i), OwnedValue::Float(f)) => OwnedValue::Float(*f + *i as f64), (OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null, + (OwnedValue::Text(lhs), OwnedValue::Text(rhs)) => exec_add( + &cast_text_to_numerical(&lhs.value), + &cast_text_to_numerical(&rhs.value), + ), + (OwnedValue::Text(text), other) | (other, OwnedValue::Text(text)) => { + exec_add(&cast_text_to_numerical(&text.value), other) + } _ => todo!(), } } @@ -519,6 +536,16 @@ pub fn exec_subtract(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { (OwnedValue::Float(lhs), OwnedValue::Integer(rhs)) => OwnedValue::Float(lhs - *rhs as f64), (OwnedValue::Integer(lhs), OwnedValue::Float(rhs)) => OwnedValue::Float(*lhs as f64 - rhs), (OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null, + (OwnedValue::Text(lhs), OwnedValue::Text(rhs)) => exec_subtract( + &cast_text_to_numerical(&lhs.value), + &cast_text_to_numerical(&rhs.value), + ), + (OwnedValue::Text(text), other) => { + exec_subtract(&cast_text_to_numerical(&text.value), other) + } + (other, OwnedValue::Text(text)) => { + exec_subtract(other, &cast_text_to_numerical(&text.value)) + } _ => todo!(), } } @@ -535,6 +562,14 @@ pub fn exec_multiply(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { (OwnedValue::Integer(i), OwnedValue::Float(f)) | (OwnedValue::Float(f), OwnedValue::Integer(i)) => OwnedValue::Float(*i as f64 * { *f }), (OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null, + (OwnedValue::Text(lhs), OwnedValue::Text(rhs)) => exec_multiply( + &cast_text_to_numerical(&lhs.value), + &cast_text_to_numerical(&rhs.value), + ), + (OwnedValue::Text(text), other) | (other, OwnedValue::Text(text)) => { + exec_multiply(&cast_text_to_numerical(&text.value), other) + } + _ => todo!(), } } @@ -553,6 +588,12 @@ pub fn exec_divide(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { (OwnedValue::Float(lhs), OwnedValue::Integer(rhs)) => OwnedValue::Float(lhs / *rhs as f64), (OwnedValue::Integer(lhs), OwnedValue::Float(rhs)) => OwnedValue::Float(*lhs as f64 / rhs), (OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null, + (OwnedValue::Text(lhs), OwnedValue::Text(rhs)) => exec_divide( + &cast_text_to_numerical(&lhs.value), + &cast_text_to_numerical(&rhs.value), + ), + (OwnedValue::Text(text), other) => exec_divide(&cast_text_to_numerical(&text.value), other), + (other, OwnedValue::Text(text)) => exec_divide(other, &cast_text_to_numerical(&text.value)), _ => todo!(), } } @@ -576,9 +617,17 @@ pub fn exec_bit_and(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { } (OwnedValue::Float(lh), OwnedValue::Integer(rh)) => OwnedValue::Integer(*lh as i64 & rh), (OwnedValue::Integer(lh), OwnedValue::Float(rh)) => OwnedValue::Integer(lh & *rh as i64), + (OwnedValue::Text(lhs), OwnedValue::Text(rhs)) => exec_bit_and( + &cast_text_to_numerical(&lhs.value), + &cast_text_to_numerical(&rhs.value), + ), + (OwnedValue::Text(text), other) | (other, OwnedValue::Text(text)) => { + exec_bit_and(&cast_text_to_numerical(&text.value), other) + } _ => todo!(), } } + pub fn exec_bit_or(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { if let OwnedValue::Agg(agg) = lhs { lhs = agg.final_value(); @@ -594,6 +643,13 @@ pub fn exec_bit_or(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { (OwnedValue::Float(lh), OwnedValue::Float(rh)) => { OwnedValue::Integer(*lh as i64 | *rh as i64) } + (OwnedValue::Text(lhs), OwnedValue::Text(rhs)) => exec_bit_or( + &cast_text_to_numerical(&lhs.value), + &cast_text_to_numerical(&rhs.value), + ), + (OwnedValue::Text(text), other) | (other, OwnedValue::Text(text)) => { + exec_bit_or(&cast_text_to_numerical(&text.value), other) + } _ => todo!(), } } @@ -632,6 +688,7 @@ pub fn exec_bit_not(mut reg: &OwnedValue) -> OwnedValue { OwnedValue::Null => OwnedValue::Null, OwnedValue::Integer(i) => OwnedValue::Integer(!i), OwnedValue::Float(f) => OwnedValue::Integer(!(*f as i64)), + OwnedValue::Text(text) => exec_bit_not(&cast_text_to_numerical(&text.value)), _ => todo!(), } } diff --git a/testing/math.test b/testing/math.test index 9dc517755..6183bc28b 100644 --- a/testing/math.test +++ b/testing/math.test @@ -31,6 +31,19 @@ do_execsql_test add-agg-float-agg-int { SELECT sum(1.5) + sum(2) } {3.5} +foreach {testnum lhs rhs ans} { + 1 'a' 'a' 0 + 2 'a' 10 10 + 3 10 'a' 10 + 4 'a' 11.0 11.0 + 5 11.0 'a' 11.0 + 7 '1' '2' 3 + 8 '1.0' '2' 3.0 + 9 '1.0' '3.0' 4.0 +} { + do_execsql_test add-text-$testnum "SELECT $lhs + $rhs" $::ans +} + do_execsql_test subtract-int { SELECT 10 - 1 } {9} @@ -55,6 +68,19 @@ do_execsql_test subtract-agg-float-agg-int { SELECT sum(3.5) - sum(1) } {2.5} +foreach {testnum lhs rhs ans} { + 1 'a' 'a' 0 + 2 'a' 10 -10 + 3 10 'a' 10 + 4 'a' 11.0 -11.0 + 5 11.0 'a' 11.0 + 7 '1' '2' -1 + 8 '1.0' '2' -1.0 + 9 '1.0' '3.0' -2.0 +} { + do_execsql_test subtract-text-$testnum "SELECT $lhs - $rhs" $::ans +} + do_execsql_test multiply-int { SELECT 10 * 2 } {20} @@ -83,6 +109,19 @@ do_execsql_test multiply-agg-float-agg-int { SELECT sum(2.5) * sum(3) } {7.5} +foreach {testnum lhs rhs ans} { + 1 'a' 'a' 0 + 2 'a' 10 0 + 3 10 'a' 0 + 4 'a' 11.0 0.0 + 5 11.0 'a' 0.0 + 7 '1' '2' 2 + 8 '1.0' '2' 2.0 + 9 '1.0' '3.0' 3.0 +} { + do_execsql_test multiply-text-$testnum "SELECT $lhs * $rhs" $::ans +} + do_execsql_test divide-int { SELECT 10 / 2 } {5} @@ -131,6 +170,18 @@ do_execsql_test divide-agg-float-agg-int { SELECT sum(4.0) / sum(2) } {2.0} +foreach {testnum lhs rhs ans} { + 1 'a' 'a' {} + 2 'a' 10 0 + 3 10 'a' {} + 4 'a' 11.0 0.0 + 5 11.0 'a' {} + 7 '1' '2' 0 + 8 '1.0' '2' 0.5 + 9 '1.0' '4.0' 0.25 +} { + do_execsql_test divide-text-$testnum "SELECT $lhs / $rhs" $::ans +} do_execsql_test add-agg-int { SELECT sum(id) + 10 from products @@ -299,6 +350,21 @@ do_execsql_test bitwise-and-int-agg-int-agg { SELECT sum(id) & sum(id) from products } {66} +foreach {testnum lhs rhs ans} { + 1 'a' 'a' 0 + 2 'a' 10 0 + 3 10 'a' 0 + 4 'a' 11.0 0 + 5 11.0 'a' 0 + 7 '1' '2' 0 + 8 '1.0' '2' 0 + 9 '1.0' '4.0' 0 + 10 '1.0' '1.0' 1 + 11 '1' '1' 1 +} { + do_execsql_test bitwise-and-text-$testnum "SELECT $lhs & $rhs" $::ans +} + do_execsql_test bitwise-or-int-null { SELECT 1234 | NULL @@ -324,6 +390,21 @@ do_execsql_test bitwise-or-float-float { SELECT 1234.6 | 5432.2 } {5626} +foreach {testnum lhs rhs ans} { + 1 'a' 'a' 0 + 2 'a' 10 10 + 3 10 'a' 10 + 4 'a' 11.0 11 + 5 11.0 'a' 11 + 7 '1' '2' 3 + 8 '1.0' '2' 3 + 9 '1.0' '4.0' 5 + 10 '1.0' '1.0' 1 + 11 '1' '1' 1 +} { + do_execsql_test bitwise-or-text-$testnum "SELECT $lhs | $rhs" $::ans +} + do_execsql_test bitwise-and-int-agg-int-agg { SELECT sum(id) | sum(id) from products } {66} @@ -341,6 +422,14 @@ do_execsql_test bitwise-not-float { SELECT ~823.34 } {-824} +do_execsql_test bitwise-not-text-float { + SELECT ~'823.34' +} {-824} + +do_execsql_test bitwise-not-text-int { + SELECT ~'1234' +} {-1235} + do_execsql_test bitwise-not-scalar-float { SELECT ~abs(693.9) } {-694}