mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-27 21:14:21 +01:00
Merge 'Implement support for iif()' from Alex Miller
In sqlite, iif() looks like: ``` sqlite> create table iiftest(a int, b int, c int); sqlite> explain select iif(a,b,c) from iiftest; addr opcode p1 p2 p3 p4 p5 comment ---- ------------- ---- ---- ---- ------------- -- ------------- 0 Init 0 11 0 0 Start at 11 1 OpenRead 0 2 0 3 0 root=2 iDb=0; iiftest 2 Rewind 0 10 0 0 3 Column 0 0 2 0 r[2]= cursor 0 column 0 4 IfNot 2 7 1 0 5 Column 0 1 1 0 r[1]= cursor 0 column 1 6 Goto 0 8 0 0 7 Column 0 2 1 0 r[1]= cursor 0 column 2 8 ResultRow 1 1 0 0 output=r[1] 9 Next 0 3 0 1 10 Halt 0 0 0 0 11 Transaction 0 0 1 0 1 usesStmtJournal=0 12 Goto 0 1 0 0 ``` And with this change, in limbo it looks like: ``` addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 14 0 0 Start at 14 1 OpenReadAsync 0 2 0 0 table=iiftest, root=2 2 OpenReadAwait 0 0 0 0 3 RewindAsync 0 0 0 0 4 RewindAwait 0 13 0 0 Rewind table iiftest 5 Column 0 0 2 0 r[2]=iiftest.a 6 IfNot 2 9 1 0 if !r[2] goto 9 7 Column 0 1 1 0 r[1]=iiftest.b 8 Goto 0 10 0 0 9 Column 0 2 1 0 r[1]=iiftest.c 10 ResultRow 1 1 0 0 output=r[1] 11 NextAsync 0 0 0 0 12 NextAwait 0 5 0 0 13 Halt 0 0 0 0 14 Transaction 0 0 0 0 15 Goto 0 1 0 0 ``` --- Rust commentary overly welcome, as idk what I'm doing in this language. Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #424
This commit is contained in:
@@ -111,7 +111,7 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
|
||||
| glob(X,Y) | Yes | |
|
||||
| hex(X) | Yes | |
|
||||
| ifnull(X,Y) | Yes | |
|
||||
| iif(X,Y,Z) | No | |
|
||||
| iif(X,Y,Z) | Yes | |
|
||||
| instr(X,Y) | Yes | |
|
||||
| last_insert_rowid() | Yes | |
|
||||
| length(X) | Yes | |
|
||||
|
||||
@@ -56,6 +56,7 @@ pub enum ScalarFunc {
|
||||
ConcatWs,
|
||||
Glob,
|
||||
IfNull,
|
||||
Iif,
|
||||
Instr,
|
||||
Like,
|
||||
Abs,
|
||||
@@ -98,6 +99,7 @@ impl Display for ScalarFunc {
|
||||
ScalarFunc::ConcatWs => "concat_ws".to_string(),
|
||||
ScalarFunc::Glob => "glob".to_string(),
|
||||
ScalarFunc::IfNull => "ifnull".to_string(),
|
||||
ScalarFunc::Iif => "iif".to_string(),
|
||||
ScalarFunc::Instr => "instr".to_string(),
|
||||
ScalarFunc::Like => "like(2)".to_string(),
|
||||
ScalarFunc::Abs => "abs".to_string(),
|
||||
@@ -178,6 +180,7 @@ impl Func {
|
||||
"concat_ws" => Ok(Func::Scalar(ScalarFunc::ConcatWs)),
|
||||
"glob" => Ok(Func::Scalar(ScalarFunc::Glob)),
|
||||
"ifnull" => Ok(Func::Scalar(ScalarFunc::IfNull)),
|
||||
"iif" => Ok(Func::Scalar(ScalarFunc::Iif)),
|
||||
"instr" => Ok(Func::Scalar(ScalarFunc::Instr)),
|
||||
"like" => Ok(Func::Scalar(ScalarFunc::Like)),
|
||||
"abs" => Ok(Func::Scalar(ScalarFunc::Abs)),
|
||||
|
||||
@@ -1071,6 +1071,56 @@ pub fn translate_expr(
|
||||
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::Iif => {
|
||||
let args = match args {
|
||||
Some(args) if args.len() == 3 => args,
|
||||
_ => crate::bail_parse_error!(
|
||||
"{} requires exactly 3 arguments",
|
||||
srf.to_string()
|
||||
),
|
||||
};
|
||||
let temp_reg = program.alloc_register();
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[0],
|
||||
temp_reg,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
let jump_target_when_false = program.allocate_label();
|
||||
program.emit_insn_with_label_dependency(
|
||||
Insn::IfNot {
|
||||
reg: temp_reg,
|
||||
target_pc: jump_target_when_false,
|
||||
null_reg: 1,
|
||||
},
|
||||
jump_target_when_false,
|
||||
);
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[1],
|
||||
target_register,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
let jump_target_result = program.allocate_label();
|
||||
program.emit_insn_with_label_dependency(
|
||||
Insn::Goto {
|
||||
target_pc: jump_target_result,
|
||||
},
|
||||
jump_target_result,
|
||||
);
|
||||
program.resolve_label(jump_target_when_false, program.offset());
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[2],
|
||||
target_register,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
program.resolve_label(jump_target_result, program.offset());
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::Glob | ScalarFunc::Like => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() < 2 {
|
||||
|
||||
@@ -2106,6 +2106,13 @@ impl Program {
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
ScalarFunc::IfNull => {}
|
||||
ScalarFunc::Iif => {}
|
||||
ScalarFunc::Instr => {
|
||||
let reg_value = &state.registers[*start_reg];
|
||||
let pattern_value = &state.registers[*start_reg + 1];
|
||||
let result = exec_instr(reg_value, pattern_value);
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
ScalarFunc::LastInsertRowid => {
|
||||
if let Some(conn) = self.connection.upgrade() {
|
||||
state.registers[*dest] =
|
||||
@@ -2114,12 +2121,6 @@ impl Program {
|
||||
state.registers[*dest] = OwnedValue::Null;
|
||||
}
|
||||
}
|
||||
ScalarFunc::Instr => {
|
||||
let reg_value = &state.registers[*start_reg];
|
||||
let pattern_value = &state.registers[*start_reg + 1];
|
||||
let result = exec_instr(reg_value, pattern_value);
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
ScalarFunc::Like => {
|
||||
let pattern = &state.registers[*start_reg];
|
||||
let text = &state.registers[*start_reg + 1];
|
||||
|
||||
@@ -75,6 +75,14 @@ do_execsql_test ifnull-2 {
|
||||
select ifnull(null, 2);
|
||||
} {2}
|
||||
|
||||
do_execsql_test iif-true {
|
||||
select iif(1, 'pass', 'fail');
|
||||
} {pass}
|
||||
|
||||
do_execsql_test iif-false {
|
||||
select iif(0, 'fail', 'pass');
|
||||
} {pass}
|
||||
|
||||
do_execsql_test instr-str {
|
||||
select instr('limbo', 'im');
|
||||
} {2}
|
||||
|
||||
Reference in New Issue
Block a user