mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-14 20:44:29 +01:00
Merge 'implementation of scalar function sign(X)' from Jean Arhancet
This is related to the issue https://github.com/penberg/limbo/issues/144. Add the scalar function `sign(X)` Closes #328
This commit is contained in:
@@ -97,7 +97,7 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| round(X,Y) | Yes | |
|
||||
| rtrim(X) | Yes | |
|
||||
| rtrim(X,Y) | Yes | |
|
||||
| sign(X) | No | |
|
||||
| sign(X) | Yes | |
|
||||
| soundex(X) | No | |
|
||||
| sqlite_compileoption_get(N) | No | |
|
||||
| sqlite_compileoption_used(X) | No | |
|
||||
|
||||
@@ -58,6 +58,7 @@ pub enum ScalarFunc {
|
||||
Min,
|
||||
Max,
|
||||
Nullif,
|
||||
Sign,
|
||||
Substr,
|
||||
Substring,
|
||||
Date,
|
||||
@@ -88,6 +89,7 @@ impl ToString for ScalarFunc {
|
||||
ScalarFunc::Min => "min".to_string(),
|
||||
ScalarFunc::Max => "max".to_string(),
|
||||
ScalarFunc::Nullif => "nullif".to_string(),
|
||||
ScalarFunc::Sign => "sign".to_string(),
|
||||
ScalarFunc::Substr => "substr".to_string(),
|
||||
ScalarFunc::Substring => "substring".to_string(),
|
||||
ScalarFunc::Date => "date".to_string(),
|
||||
@@ -151,6 +153,7 @@ impl Func {
|
||||
"rtrim" => Ok(Func::Scalar(ScalarFunc::RTrim)),
|
||||
"round" => Ok(Func::Scalar(ScalarFunc::Round)),
|
||||
"length" => Ok(Func::Scalar(ScalarFunc::Length)),
|
||||
"sign" => Ok(Func::Scalar(ScalarFunc::Sign)),
|
||||
"substr" => Ok(Func::Scalar(ScalarFunc::Substr)),
|
||||
"substring" => Ok(Func::Scalar(ScalarFunc::Substring)),
|
||||
"date" => Ok(Func::Scalar(ScalarFunc::Date)),
|
||||
|
||||
@@ -986,7 +986,8 @@ pub fn translate_expr(
|
||||
| ScalarFunc::Upper
|
||||
| ScalarFunc::Length
|
||||
| ScalarFunc::Unicode
|
||||
| ScalarFunc::Quote => {
|
||||
| ScalarFunc::Quote
|
||||
| ScalarFunc::Sign => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() != 1 {
|
||||
crate::bail_parse_error!(
|
||||
|
||||
116
core/vdbe/mod.rs
116
core/vdbe/mod.rs
@@ -1464,9 +1464,11 @@ impl Program {
|
||||
| ScalarFunc::Upper
|
||||
| ScalarFunc::Length
|
||||
| ScalarFunc::Unicode
|
||||
| ScalarFunc::Quote => {
|
||||
| ScalarFunc::Quote
|
||||
| ScalarFunc::Sign => {
|
||||
let reg_value = state.registers[*start_reg].borrow_mut();
|
||||
let result = match scalar_func {
|
||||
ScalarFunc::Sign => exec_sign(reg_value),
|
||||
ScalarFunc::Abs => exec_abs(reg_value),
|
||||
ScalarFunc::Lower => exec_lower(reg_value),
|
||||
ScalarFunc::Upper => exec_upper(reg_value),
|
||||
@@ -1862,6 +1864,45 @@ fn exec_concat_ws(registers: &[OwnedValue]) -> OwnedValue {
|
||||
OwnedValue::Text(Rc::new(result))
|
||||
}
|
||||
|
||||
fn exec_sign(reg: &OwnedValue) -> Option<OwnedValue> {
|
||||
let num = match reg {
|
||||
OwnedValue::Integer(i) => *i as f64,
|
||||
OwnedValue::Float(f) => *f,
|
||||
OwnedValue::Text(s) => {
|
||||
if let Ok(i) = s.parse::<i64>() {
|
||||
i as f64
|
||||
} else if let Ok(f) = s.parse::<f64>() {
|
||||
f
|
||||
} else {
|
||||
return Some(OwnedValue::Null);
|
||||
}
|
||||
}
|
||||
OwnedValue::Blob(b) => match std::str::from_utf8(b) {
|
||||
Ok(s) => {
|
||||
if let Ok(i) = s.parse::<i64>() {
|
||||
i as f64
|
||||
} else if let Ok(f) = s.parse::<f64>() {
|
||||
f
|
||||
} else {
|
||||
return Some(OwnedValue::Null);
|
||||
}
|
||||
}
|
||||
Err(_) => return Some(OwnedValue::Null),
|
||||
},
|
||||
_ => return Some(OwnedValue::Null),
|
||||
};
|
||||
|
||||
let sign = if num > 0.0 {
|
||||
1
|
||||
} else if num < 0.0 {
|
||||
-1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
Some(OwnedValue::Integer(sign))
|
||||
}
|
||||
|
||||
fn exec_abs(reg: &OwnedValue) -> Option<OwnedValue> {
|
||||
match reg {
|
||||
OwnedValue::Integer(x) => {
|
||||
@@ -2113,9 +2154,9 @@ fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
|
||||
mod tests {
|
||||
use super::{
|
||||
exec_abs, exec_char, exec_if, exec_length, exec_like, exec_lower, exec_ltrim, exec_minmax,
|
||||
exec_nullif, exec_quote, exec_random, exec_round, exec_rtrim, exec_substring, exec_trim,
|
||||
exec_unicode, exec_upper, get_new_rowid, Cursor, CursorResult, LimboError, OwnedRecord,
|
||||
OwnedValue, Result,
|
||||
exec_nullif, exec_quote, exec_random, exec_round, exec_rtrim, exec_sign, exec_substring,
|
||||
exec_trim, exec_unicode, exec_upper, get_new_rowid, Cursor, CursorResult, LimboError,
|
||||
OwnedRecord, OwnedValue, Result,
|
||||
};
|
||||
use mockall::{mock, predicate};
|
||||
use rand::{rngs::mock::StepRng, thread_rng};
|
||||
@@ -2643,4 +2684,71 @@ mod tests {
|
||||
expected_val
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exec_sign() {
|
||||
let input = OwnedValue::Integer(42);
|
||||
let expected = Some(OwnedValue::Integer(1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Integer(-42);
|
||||
let expected = Some(OwnedValue::Integer(-1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Integer(0);
|
||||
let expected = Some(OwnedValue::Integer(0));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Float(0.0);
|
||||
let expected = Some(OwnedValue::Integer(0));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Float(0.1);
|
||||
let expected = Some(OwnedValue::Integer(1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Float(42.0);
|
||||
let expected = Some(OwnedValue::Integer(1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Float(-42.0);
|
||||
let expected = Some(OwnedValue::Integer(-1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Text(Rc::new("abc".to_string()));
|
||||
let expected = Some(OwnedValue::Null);
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Text(Rc::new("42".to_string()));
|
||||
let expected = Some(OwnedValue::Integer(1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Text(Rc::new("-42".to_string()));
|
||||
let expected = Some(OwnedValue::Integer(-1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Text(Rc::new("0".to_string()));
|
||||
let expected = Some(OwnedValue::Integer(0));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Blob(Rc::new(b"abc".to_vec()));
|
||||
let expected = Some(OwnedValue::Null);
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Blob(Rc::new(b"42".to_vec()));
|
||||
let expected = Some(OwnedValue::Integer(1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Blob(Rc::new(b"-42".to_vec()));
|
||||
let expected = Some(OwnedValue::Integer(-1));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Blob(Rc::new(b"0".to_vec()));
|
||||
let expected = Some(OwnedValue::Integer(0));
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
|
||||
let input = OwnedValue::Null;
|
||||
let expected = Some(OwnedValue::Null);
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,3 +386,47 @@ do_execsql_test quote-null {
|
||||
do_execsql_test quote-integer {
|
||||
SELECT quote(123)
|
||||
} {123}
|
||||
|
||||
do_execsql_test sign-positive-integer {
|
||||
SELECT sign(42);
|
||||
} {1}
|
||||
|
||||
do_execsql_test sign-negative-integer {
|
||||
SELECT sign(-42);
|
||||
} {-1}
|
||||
|
||||
do_execsql_test sign-zero {
|
||||
SELECT sign(0);
|
||||
} {0}
|
||||
|
||||
do_execsql_test sign-positive-float {
|
||||
SELECT sign(42.0);
|
||||
} {1}
|
||||
|
||||
do_execsql_test sign-negative-float {
|
||||
SELECT sign(-42.0);
|
||||
} {-1}
|
||||
|
||||
do_execsql_test sign-zero-float {
|
||||
SELECT sign(0.0);
|
||||
} {0}
|
||||
|
||||
do_execsql_test sign-text-positive-integer {
|
||||
SELECT sign('42');
|
||||
} {1}
|
||||
|
||||
do_execsql_test sign-text-negative-integer {
|
||||
SELECT sign('-42');
|
||||
} {-1}
|
||||
|
||||
do_execsql_test sign-text-zero {
|
||||
SELECT sign('0');
|
||||
} {0}
|
||||
|
||||
do_execsql_test sign-text-non-numeric {
|
||||
SELECT sign('abc');
|
||||
} {}
|
||||
|
||||
do_execsql_test sign-null {
|
||||
SELECT sign(NULL);
|
||||
} {}
|
||||
|
||||
Reference in New Issue
Block a user