Merge pull request #238 from macroexpansion/feature/add-ltrim-scalar-function

This commit is contained in:
Pekka Enberg
2024-07-27 15:57:48 +03:00
committed by GitHub
5 changed files with 85 additions and 5 deletions

View File

@@ -82,8 +82,8 @@ This document describes the SQLite compatibility status of Limbo:
| load_extension(X) | No | |
| load_extension(X,Y) | No | |
| lower(X) | Yes | |
| ltrim(X) | No | |
| ltrim(X,Y) | No | |
| ltrim(X) | Yes | |
| ltrim(X,Y) | Yes | |
| max(X,Y,...) | No | |
| min(X,Y,...) | No | |
| nullif(X,Y) | No | |

View File

@@ -34,6 +34,7 @@ pub enum ScalarFunc {
Lower,
Random,
Trim,
LTrim,
Round,
Length,
Min,
@@ -52,6 +53,7 @@ impl ToString for ScalarFunc {
ScalarFunc::Lower => "lower".to_string(),
ScalarFunc::Random => "random".to_string(),
ScalarFunc::Trim => "trim".to_string(),
ScalarFunc::LTrim => "ltrim".to_string(),
ScalarFunc::Round => "round".to_string(),
ScalarFunc::Length => "length".to_string(),
ScalarFunc::Min => "min".to_string(),
@@ -88,6 +90,7 @@ impl Func {
"lower" => Ok(Func::Scalar(ScalarFunc::Lower)),
"random" => Ok(Func::Scalar(ScalarFunc::Random)),
"trim" => Ok(Func::Scalar(ScalarFunc::Trim)),
"ltrim" => Ok(Func::Scalar(ScalarFunc::LTrim)),
"round" => Ok(Func::Scalar(ScalarFunc::Round)),
"length" => Ok(Func::Scalar(ScalarFunc::Length)),
"date" => Ok(Func::Scalar(ScalarFunc::Date)),

View File

@@ -275,7 +275,7 @@ pub fn translate_expr(
});
Ok(target_register)
}
ScalarFunc::Trim | ScalarFunc::Round => {
ScalarFunc::Trim | ScalarFunc::LTrim | ScalarFunc::Round => {
let args = if let Some(args) = args {
if args.len() > 2 {
crate::bail_parse_error!(

View File

@@ -1115,6 +1115,16 @@ impl Program {
state.registers[*dest] = result;
state.pc += 1;
}
ScalarFunc::LTrim => {
let start_reg = *start_reg;
let reg_value = state.registers[start_reg].clone();
let pattern_value = state.registers.get(start_reg + 1).cloned();
let result = exec_ltrim(&reg_value, pattern_value);
state.registers[*dest] = result;
state.pc += 1;
}
ScalarFunc::Round => {
let start_reg = *start_reg;
let reg_value = state.registers[start_reg].clone();
@@ -1350,6 +1360,25 @@ fn exec_trim(reg: &OwnedValue, pattern: Option<OwnedValue>) -> OwnedValue {
}
}
// Implements LTRIM pattern matching.
fn exec_ltrim(reg: &OwnedValue, pattern: Option<OwnedValue>) -> OwnedValue {
match (reg, pattern) {
(reg, Some(pattern)) => match reg {
OwnedValue::Text(_) | OwnedValue::Integer(_) | OwnedValue::Float(_) => {
let pattern_chars: Vec<char> = pattern.to_string().chars().collect();
OwnedValue::Text(Rc::new(
reg.to_string()
.trim_start_matches(&pattern_chars[..])
.to_string(),
))
}
_ => reg.to_owned(),
},
(OwnedValue::Text(t), None) => OwnedValue::Text(Rc::new(t.trim_start().to_string())),
(reg, _) => reg.to_owned(),
}
}
// exec_if returns whether you should jump
fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
match reg {
@@ -1367,8 +1396,8 @@ fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
#[cfg(test)]
mod tests {
use super::{
exec_abs, exec_if, exec_length, exec_like, exec_lower, exec_minmax, exec_random,
exec_round, exec_trim, exec_unicode, exec_upper, OwnedValue,
exec_abs, exec_if, exec_length, exec_like, exec_lower, exec_ltrim, exec_minmax,
exec_random, exec_round, exec_trim, exec_unicode, exec_upper, OwnedValue,
};
use std::rc::Rc;
@@ -1477,6 +1506,18 @@ mod tests {
assert_eq!(exec_trim(&input_str, Some(pattern_str)), expected_str);
}
#[test]
fn test_ltrim() {
let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice ")));
let expected_str = OwnedValue::Text(Rc::new(String::from("Bob and Alice ")));
assert_eq!(exec_ltrim(&input_str, None), expected_str);
let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice ")));
let pattern_str = OwnedValue::Text(Rc::new(String::from("Bob and")));
let expected_str = OwnedValue::Text(Rc::new(String::from("Alice ")));
assert_eq!(exec_ltrim(&input_str, Some(pattern_str)), expected_str);
}
#[test]
fn test_upper_case() {
let input_str = OwnedValue::Text(Rc::new(String::from("Limbo")));

View File

@@ -87,6 +87,42 @@ do_execsql_test trim-no-match-pattern {
SELECT trim('Limbo', 'xyz');
} {Limbo}
do_execsql_test ltrim {
SELECT ltrim(' Limbo ');
} {"Limbo "}
do_execsql_test ltrim-number {
SELECT ltrim(1);
} {1}
do_execsql_test ltrim-null {
SELECT ltrim(null);
} {}
do_execsql_test ltrim-leading-whitespace {
SELECT ltrim(' Leading');
} {Leading}
do_execsql_test ltrim-no-leading-whitespace {
SELECT ltrim('Limbo');
} {Limbo}
do_execsql_test ltrim-pattern {
SELECT ltrim('Limbo', 'Limbo');
} {}
do_execsql_test ltrim-pattern-number {
SELECT ltrim(1, '1');
} {}
do_execsql_test ltrim-pattern-null {
SELECT ltrim(null, 'null');
} {}
do_execsql_test ltrim-no-match-pattern {
SELECT ltrim('Limbo', 'xyz');
} {Limbo}
do_execsql_test round-float-no-precision {
SELECT round(123.456);
} {123.0}