mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-07 02:04:21 +01:00
Merge pull request #182 from brayanjuls/upper_lower_scalar_func
implementation of scalar functions `upper` and `lower`
This commit is contained in:
@@ -81,7 +81,7 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| likely(X) | No | |
|
||||
| load_extension(X) | No | |
|
||||
| load_extension(X,Y) | No | |
|
||||
| lower(X) | No | |
|
||||
| lower(X) | Yes | |
|
||||
| ltrim(X) | No | |
|
||||
| ltrim(X,Y) | No | |
|
||||
| max(X,Y,...) | No | |
|
||||
@@ -116,7 +116,7 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| unhex(X,Y) | No | |
|
||||
| unicode(X) | No | |
|
||||
| unlikely(X) | No | |
|
||||
| upper(X) | No | |
|
||||
| upper(X) | Yes | |
|
||||
| zeroblob(N) | No | |
|
||||
|
||||
### Aggregate functions
|
||||
|
||||
44
core/expr.rs
44
core/expr.rs
@@ -309,6 +309,50 @@ pub fn translate_expr(
|
||||
func: SingleRowFunc::Abs,
|
||||
});
|
||||
|
||||
Ok(target_register)
|
||||
}
|
||||
SingleRowFunc::Upper => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() != 1 {
|
||||
anyhow::bail!(
|
||||
"Parse error: upper function with not exactly 1 argument"
|
||||
);
|
||||
}
|
||||
args
|
||||
} else {
|
||||
anyhow::bail!("Parse error: upper function with no arguments");
|
||||
};
|
||||
|
||||
let regs = program.alloc_register();
|
||||
let _ = translate_expr(program, select, &args[0], regs)?;
|
||||
program.emit_insn(Insn::Function {
|
||||
start_reg: regs,
|
||||
dest: target_register,
|
||||
func: SingleRowFunc::Upper,
|
||||
});
|
||||
|
||||
Ok(target_register)
|
||||
}
|
||||
SingleRowFunc::Lower => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() != 1 {
|
||||
anyhow::bail!(
|
||||
"Parse error: lower function with not exactly 1 argument"
|
||||
);
|
||||
}
|
||||
args
|
||||
} else {
|
||||
anyhow::bail!("Parse error: lower function with no arguments");
|
||||
};
|
||||
|
||||
let regs = program.alloc_register();
|
||||
let _ = translate_expr(program, select, &args[0], regs)?;
|
||||
program.emit_insn(Insn::Function {
|
||||
start_reg: regs,
|
||||
dest: target_register,
|
||||
func: SingleRowFunc::Lower,
|
||||
});
|
||||
|
||||
Ok(target_register)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ pub enum SingleRowFunc {
|
||||
Coalesce,
|
||||
Like,
|
||||
Abs,
|
||||
Upper,
|
||||
Lower,
|
||||
}
|
||||
|
||||
impl ToString for SingleRowFunc {
|
||||
@@ -40,6 +42,8 @@ impl ToString for SingleRowFunc {
|
||||
SingleRowFunc::Coalesce => "coalesce".to_string(),
|
||||
SingleRowFunc::Like => "like(2)".to_string(),
|
||||
SingleRowFunc::Abs => "abs".to_string(),
|
||||
SingleRowFunc::Upper => "upper".to_string(),
|
||||
SingleRowFunc::Lower => "lower".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,6 +69,8 @@ impl FromStr for Func {
|
||||
"coalesce" => Ok(Func::SingleRow(SingleRowFunc::Coalesce)),
|
||||
"like" => Ok(Func::SingleRow(SingleRowFunc::Like)),
|
||||
"abs" => Ok(Func::SingleRow(SingleRowFunc::Abs)),
|
||||
"upper" => Ok(Func::SingleRow(SingleRowFunc::Upper)),
|
||||
"lower" => Ok(Func::SingleRow(SingleRowFunc::Lower)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
55
core/vdbe.rs
55
core/vdbe.rs
@@ -1271,6 +1271,24 @@ impl Program {
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
SingleRowFunc::Upper => {
|
||||
let reg_value = state.registers[*start_reg].borrow_mut();
|
||||
if let Some(value) = exec_upper(reg_value) {
|
||||
state.registers[*dest] = value;
|
||||
} else {
|
||||
state.registers[*dest] = OwnedValue::Null;
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
SingleRowFunc::Lower => {
|
||||
let reg_value = state.registers[*start_reg].borrow_mut();
|
||||
if let Some(value) = exec_lower(reg_value) {
|
||||
state.registers[*dest] = value;
|
||||
} else {
|
||||
state.registers[*dest] = OwnedValue::Null;
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1809,6 +1827,19 @@ fn get_indent_count(indent_count: usize, curr_insn: &Insn, prev_insn: Option<&In
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_lower(reg: &OwnedValue) -> Option<OwnedValue> {
|
||||
match reg {
|
||||
OwnedValue::Text(t) => Some(OwnedValue::Text(Rc::new(t.to_lowercase()))),
|
||||
t => Some(t.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_upper(reg: &OwnedValue) -> Option<OwnedValue> {
|
||||
match reg {
|
||||
OwnedValue::Text(t) => Some(OwnedValue::Text(Rc::new(t.to_uppercase()))),
|
||||
t => Some(t.to_owned()),
|
||||
}
|
||||
}
|
||||
fn exec_abs(reg: &OwnedValue) -> Option<OwnedValue> {
|
||||
match reg {
|
||||
OwnedValue::Integer(x) => {
|
||||
@@ -1852,9 +1883,31 @@ fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{exec_abs, exec_if, exec_like, OwnedValue};
|
||||
use super::{exec_abs, exec_if, exec_like, exec_lower, exec_upper, OwnedValue};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn test_upper_case() {
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Limbo")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("LIMBO")));
|
||||
assert_eq!(exec_upper(&input_str).unwrap(), expected_str);
|
||||
|
||||
let input_int = OwnedValue::Integer(10);
|
||||
assert_eq!(exec_upper(&input_int).unwrap(), input_int);
|
||||
assert_eq!(exec_upper(&OwnedValue::Null).unwrap(), OwnedValue::Null)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lower_case() {
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Limbo")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("limbo")));
|
||||
assert_eq!(exec_lower(&input_str).unwrap(), expected_str);
|
||||
|
||||
let input_int = OwnedValue::Integer(10);
|
||||
assert_eq!(exec_lower(&input_int).unwrap(), input_int);
|
||||
assert_eq!(exec_lower(&OwnedValue::Null).unwrap(), OwnedValue::Null)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs() {
|
||||
let int_positive_reg = OwnedValue::Integer(10);
|
||||
|
||||
@@ -18,3 +18,35 @@ do_execsql_test abs-char {
|
||||
do_execsql_test abs-null {
|
||||
select abs(null);
|
||||
} {}
|
||||
|
||||
do_execsql_test upper {
|
||||
select upper('Limbo')
|
||||
} {LIMBO}
|
||||
|
||||
do_execsql_test upper-number {
|
||||
select upper(1)
|
||||
} {1}
|
||||
|
||||
do_execsql_test upper-char {
|
||||
select upper('a')
|
||||
} {A}
|
||||
|
||||
do_execsql_test upper-null {
|
||||
select upper(null)
|
||||
} {}
|
||||
|
||||
do_execsql_test lower {
|
||||
select lower('Limbo')
|
||||
} {limbo}
|
||||
|
||||
do_execsql_test lower-number {
|
||||
select lower(1)
|
||||
} {1}
|
||||
|
||||
do_execsql_test lower-char {
|
||||
select lower('A')
|
||||
} {a}
|
||||
|
||||
do_execsql_test lower-null {
|
||||
select lower(null)
|
||||
} {}
|
||||
|
||||
Reference in New Issue
Block a user