mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-25 03:54:21 +01:00
Merge 'Add support for nullif scalar function' from Kim Seon Woo
### EXPLAIN nullif(1,2) <img width="1339" alt="image" src="https://github.com/user-attachments/assets/08230797-914d-4922-b52c-5b2b2b4c2a12"> ### Issue https://github.com/penberg/limbo/issues/144 Closes #299
This commit is contained in:
@@ -74,7 +74,7 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| iif(X,Y,Z) | No | |
|
||||
| instr(X,Y) | No | |
|
||||
| last_insert_rowid() | No | |
|
||||
| length(X) | No | |
|
||||
| length(X) | Yes | |
|
||||
| like(X,Y) | No | |
|
||||
| like(X,Y,Z) | No | |
|
||||
| likelihood(X,Y) | No | |
|
||||
@@ -86,7 +86,7 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| ltrim(X,Y) | Yes | |
|
||||
| max(X,Y,...) | Yes | |
|
||||
| min(X,Y,...) | Yes | |
|
||||
| nullif(X,Y) | No | |
|
||||
| nullif(X,Y) | Yes | |
|
||||
| octet_length(X) | No | |
|
||||
| printf(FORMAT,...) | No | |
|
||||
| quote(X) | Yes | |
|
||||
|
||||
@@ -56,6 +56,7 @@ pub enum ScalarFunc {
|
||||
Length,
|
||||
Min,
|
||||
Max,
|
||||
Nullif,
|
||||
Substr,
|
||||
Substring,
|
||||
Date,
|
||||
@@ -83,6 +84,7 @@ impl ToString for ScalarFunc {
|
||||
ScalarFunc::Length => "length".to_string(),
|
||||
ScalarFunc::Min => "min".to_string(),
|
||||
ScalarFunc::Max => "max".to_string(),
|
||||
ScalarFunc::Nullif => "nullif".to_string(),
|
||||
ScalarFunc::Substr => "substr".to_string(),
|
||||
ScalarFunc::Substring => "substring".to_string(),
|
||||
ScalarFunc::Date => "date".to_string(),
|
||||
@@ -110,6 +112,7 @@ impl Func {
|
||||
"max" if arg_count > 1 => Ok(Func::Scalar(ScalarFunc::Max)),
|
||||
"min" if arg_count == 0 || arg_count == 1 => Ok(Func::Agg(AggFunc::Min)),
|
||||
"min" if arg_count > 1 => Ok(Func::Scalar(ScalarFunc::Min)),
|
||||
"nullif" if arg_count == 2 => Ok(Func::Scalar(ScalarFunc::Nullif)),
|
||||
"string_agg" => Ok(Func::Agg(AggFunc::StringAgg)),
|
||||
"sum" => Ok(Func::Agg(AggFunc::Sum)),
|
||||
"total" => Ok(Func::Agg(AggFunc::Total)),
|
||||
|
||||
@@ -1067,6 +1067,43 @@ pub fn translate_expr(
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::Nullif => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() != 2 {
|
||||
crate::bail_parse_error!(
|
||||
"nullif function must have two argument"
|
||||
);
|
||||
}
|
||||
args
|
||||
} else {
|
||||
crate::bail_parse_error!("nullif function with no arguments");
|
||||
};
|
||||
|
||||
let func_reg = program.alloc_register();
|
||||
let first_reg = program.alloc_register();
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[0],
|
||||
first_reg,
|
||||
cursor_hint,
|
||||
)?;
|
||||
let second_reg = program.alloc_register();
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[1],
|
||||
second_reg,
|
||||
cursor_hint,
|
||||
)?;
|
||||
program.emit_insn(Insn::Function {
|
||||
start_reg: func_reg,
|
||||
dest: target_register,
|
||||
func: crate::vdbe::Func::Scalar(srf),
|
||||
});
|
||||
|
||||
Ok(target_register)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
|
||||
@@ -1321,6 +1321,13 @@ impl Program {
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
Func::Scalar(ScalarFunc::Nullif) => {
|
||||
let start_reg = *start_reg;
|
||||
let first_value = &state.registers[start_reg + 1];
|
||||
let second_value = &state.registers[start_reg + 2];
|
||||
state.registers[*dest] = exec_nullif(first_value, second_value);
|
||||
state.pc += 1;
|
||||
}
|
||||
Func::Scalar(ScalarFunc::Substr) | Func::Scalar(ScalarFunc::Substring) => {
|
||||
let start_reg = *start_reg;
|
||||
let str_value = &state.registers[start_reg];
|
||||
@@ -1717,6 +1724,14 @@ fn exec_minmax<'a>(
|
||||
regs.into_iter().reduce(|a, b| op(a, b)).cloned()
|
||||
}
|
||||
|
||||
fn exec_nullif(first_value: &OwnedValue, second_value: &OwnedValue) -> OwnedValue {
|
||||
if first_value != second_value {
|
||||
first_value.clone()
|
||||
} else {
|
||||
OwnedValue::Null
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_substring(
|
||||
str_value: &OwnedValue,
|
||||
start_value: &OwnedValue,
|
||||
@@ -1867,9 +1882,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_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_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};
|
||||
@@ -2298,6 +2313,41 @@ mod tests {
|
||||
assert!(!exec_if(®, &null_reg, true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nullif() {
|
||||
assert_eq!(
|
||||
exec_nullif(&OwnedValue::Integer(1), &OwnedValue::Integer(1)),
|
||||
OwnedValue::Null
|
||||
);
|
||||
assert_eq!(
|
||||
exec_nullif(&OwnedValue::Float(1.1), &OwnedValue::Float(1.1)),
|
||||
OwnedValue::Null
|
||||
);
|
||||
assert_eq!(
|
||||
exec_nullif(
|
||||
&OwnedValue::Text(Rc::new("limbo".to_string())),
|
||||
&OwnedValue::Text(Rc::new("limbo".to_string()))
|
||||
),
|
||||
OwnedValue::Null
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
exec_nullif(&OwnedValue::Integer(1), &OwnedValue::Integer(2)),
|
||||
OwnedValue::Integer(1)
|
||||
);
|
||||
assert_eq!(
|
||||
exec_nullif(&OwnedValue::Float(1.1), &OwnedValue::Float(1.2)),
|
||||
OwnedValue::Float(1.1)
|
||||
);
|
||||
assert_eq!(
|
||||
exec_nullif(
|
||||
&OwnedValue::Text(Rc::new("limbo".to_string())),
|
||||
&OwnedValue::Text(Rc::new("limb".to_string()))
|
||||
),
|
||||
OwnedValue::Text(Rc::new("limbo".to_string()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_substring() {
|
||||
let str_value = OwnedValue::Text(Rc::new("limbo".to_string()));
|
||||
|
||||
@@ -279,6 +279,18 @@ do_execsql_test max-null {
|
||||
select max(null,null)
|
||||
} {}
|
||||
|
||||
do_execsql_test nullif {
|
||||
select nullif(1, 2)
|
||||
} {1}
|
||||
|
||||
do_execsql_test nullif {
|
||||
select nullif(1, 1)
|
||||
} {}
|
||||
|
||||
do_execsql_test nullif {
|
||||
select nullif('limbo', 'limbo')
|
||||
} {}
|
||||
|
||||
do_execsql_test substr-3-args {
|
||||
SELECT substr('limbo', 1, 3);
|
||||
} {lim}
|
||||
|
||||
Reference in New Issue
Block a user