mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-05 01:04:22 +01:00
Merge 'Add support for concat_ws scalar function' from Kim Seon Woo
Adding support for `concat_ws` <img width="1604" alt="image" src="https://github.com/user- attachments/assets/8281d0c1-c338-4695-aa17-3b86f16625d3"> ## Related issue https://github.com/penberg/limbo/issues/144 Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #324
This commit is contained in:
@@ -66,7 +66,7 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| char(X1,X2,...,XN) | Yes | |
|
||||
| coalesce(X,Y,...) | Yes | |
|
||||
| concat(X,...) | Yes | |
|
||||
| concat_ws(SEP,X,...) | No | |
|
||||
| concat_ws(SEP,X,...) | Yes | |
|
||||
| format(FORMAT,...) | No | |
|
||||
| glob(X,Y) | No | |
|
||||
| hex(X) | No | |
|
||||
|
||||
@@ -43,6 +43,7 @@ pub enum ScalarFunc {
|
||||
Char,
|
||||
Coalesce,
|
||||
Concat,
|
||||
ConcatWs,
|
||||
IfNull,
|
||||
Like,
|
||||
Abs,
|
||||
@@ -72,6 +73,7 @@ impl ToString for ScalarFunc {
|
||||
ScalarFunc::Char => "char".to_string(),
|
||||
ScalarFunc::Coalesce => "coalesce".to_string(),
|
||||
ScalarFunc::Concat => "concat".to_string(),
|
||||
ScalarFunc::ConcatWs => "concat_ws".to_string(),
|
||||
ScalarFunc::IfNull => "ifnull".to_string(),
|
||||
ScalarFunc::Like => "like(2)".to_string(),
|
||||
ScalarFunc::Abs => "abs".to_string(),
|
||||
@@ -137,6 +139,7 @@ impl Func {
|
||||
"char" => Ok(Func::Scalar(ScalarFunc::Char)),
|
||||
"coalesce" => Ok(Func::Scalar(ScalarFunc::Coalesce)),
|
||||
"concat" => Ok(Func::Scalar(ScalarFunc::Concat)),
|
||||
"concat_ws" => Ok(Func::Scalar(ScalarFunc::ConcatWs)),
|
||||
"ifnull" => Ok(Func::Scalar(ScalarFunc::IfNull)),
|
||||
"like" => Ok(Func::Scalar(ScalarFunc::Like)),
|
||||
"abs" => Ok(Func::Scalar(ScalarFunc::Abs)),
|
||||
|
||||
@@ -864,6 +864,45 @@ pub fn translate_expr(
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::ConcatWs => {
|
||||
let args = match args {
|
||||
Some(args) if args.len() >= 2 => args,
|
||||
Some(_) => crate::bail_parse_error!(
|
||||
"{} function requires at least 2 arguments",
|
||||
srf.to_string()
|
||||
),
|
||||
None => crate::bail_parse_error!(
|
||||
"{} function requires arguments",
|
||||
srf.to_string()
|
||||
),
|
||||
};
|
||||
|
||||
let temp_register = program.alloc_register();
|
||||
for arg in args.iter() {
|
||||
let reg = program.alloc_register();
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
arg,
|
||||
reg,
|
||||
cursor_hint,
|
||||
cached_results,
|
||||
)?;
|
||||
}
|
||||
program.emit_insn(Insn::Function {
|
||||
constant_mask: 0,
|
||||
start_reg: temp_register + 1,
|
||||
dest: temp_register,
|
||||
func: func_ctx,
|
||||
});
|
||||
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: temp_register,
|
||||
dst_reg: target_register,
|
||||
amount: 1,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::IfNull => {
|
||||
let args = match args {
|
||||
Some(args) if args.len() == 2 => args,
|
||||
|
||||
@@ -1434,6 +1434,12 @@ impl Program {
|
||||
);
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
ScalarFunc::ConcatWs => {
|
||||
let result = exec_concat_ws(
|
||||
&state.registers[*start_reg..*start_reg + arg_count],
|
||||
);
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
ScalarFunc::IfNull => {}
|
||||
ScalarFunc::Like => {
|
||||
let pattern = &state.registers[*start_reg];
|
||||
@@ -1828,6 +1834,34 @@ fn exec_concat(registers: &[OwnedValue]) -> OwnedValue {
|
||||
OwnedValue::Text(Rc::new(result))
|
||||
}
|
||||
|
||||
fn exec_concat_ws(registers: &[OwnedValue]) -> OwnedValue {
|
||||
if registers.is_empty() {
|
||||
return OwnedValue::Null;
|
||||
}
|
||||
|
||||
let separator = match ®isters[0] {
|
||||
OwnedValue::Text(text) => text.clone(),
|
||||
OwnedValue::Integer(i) => Rc::new(i.to_string()),
|
||||
OwnedValue::Float(f) => Rc::new(f.to_string()),
|
||||
_ => return OwnedValue::Null,
|
||||
};
|
||||
|
||||
let mut result = String::new();
|
||||
for (i, reg) in registers.iter().enumerate().skip(1) {
|
||||
if i > 1 {
|
||||
result.push_str(&separator);
|
||||
}
|
||||
match reg {
|
||||
OwnedValue::Text(text) => result.push_str(text),
|
||||
OwnedValue::Integer(i) => result.push_str(&i.to_string()),
|
||||
OwnedValue::Float(f) => result.push_str(&f.to_string()),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
OwnedValue::Text(Rc::new(result))
|
||||
}
|
||||
|
||||
fn exec_abs(reg: &OwnedValue) -> Option<OwnedValue> {
|
||||
match reg {
|
||||
OwnedValue::Integer(x) => {
|
||||
|
||||
@@ -3,22 +3,38 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test concat-1 {
|
||||
do_execsql_test concat-chars {
|
||||
select concat('l', 'i');
|
||||
} {li}
|
||||
|
||||
do_execsql_test concat-2 {
|
||||
do_execsql_test concat-char-and-number {
|
||||
select concat('l', 1);
|
||||
} {l1}
|
||||
|
||||
do_execsql_test concat-3 {
|
||||
do_execsql_test concat-char-and-decimal {
|
||||
select concat('l', 1.5);
|
||||
} {l1.5}
|
||||
|
||||
do_execsql_test concat-4 {
|
||||
do_execsql_test concat-char-null-char {
|
||||
select concat('l', null, 'i');
|
||||
} {li}
|
||||
|
||||
do_execsql_test concat_ws-numbers {
|
||||
select concat_ws(',', 1, 2);
|
||||
} {1,2}
|
||||
|
||||
do_execsql_test concat_ws-single-number {
|
||||
select concat_ws(',', 1);
|
||||
} {1}
|
||||
|
||||
do_execsql_test concat_ws-null {
|
||||
select concat_ws(null, 1, 2);
|
||||
} {}
|
||||
|
||||
do_execsql_test concat_ws-multiple {
|
||||
select concat_ws(',', 1, 2), concat_ws(',', 3, 4)
|
||||
} {1,2|3,4}
|
||||
|
||||
do_execsql_test char {
|
||||
select char(108, 105)
|
||||
} {li}
|
||||
@@ -369,4 +385,4 @@ do_execsql_test quote-null {
|
||||
|
||||
do_execsql_test quote-integer {
|
||||
SELECT quote(123)
|
||||
} {123}
|
||||
} {123}
|
||||
|
||||
Reference in New Issue
Block a user