Merge 'core/translate: Add if alias and allow iff to have more arguments' from Pavan Nambi

closes #3689

Closes #3690
This commit is contained in:
Pekka Enberg
2025-10-13 08:53:00 +03:00
committed by GitHub
3 changed files with 109 additions and 43 deletions

View File

@@ -752,7 +752,7 @@ impl Func {
"total_changes" => Ok(Self::Scalar(ScalarFunc::TotalChanges)),
"glob" => Ok(Self::Scalar(ScalarFunc::Glob)),
"ifnull" => Ok(Self::Scalar(ScalarFunc::IfNull)),
"iif" => Ok(Self::Scalar(ScalarFunc::Iif)),
"if" | "iif" => Ok(Self::Scalar(ScalarFunc::Iif)),
"instr" => Ok(Self::Scalar(ScalarFunc::Instr)),
"like" => Ok(Self::Scalar(ScalarFunc::Like)),
"abs" => Ok(Self::Scalar(ScalarFunc::Abs)),

View File

@@ -1143,51 +1143,66 @@ pub fn translate_expr(
Ok(target_register)
}
ScalarFunc::Iif => {
if args.len() != 3 {
crate::bail_parse_error!(
"{} requires exactly 3 arguments",
srf.to_string()
);
let args = expect_arguments_min!(args, 2, srf);
let iif_end_label = program.allocate_label();
let condition_reg = program.alloc_register();
for pair in args.chunks_exact(2) {
let condition_expr = &pair[0];
let value_expr = &pair[1];
let next_check_label = program.allocate_label();
translate_expr_no_constant_opt(
program,
referenced_tables,
condition_expr,
condition_reg,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
program.emit_insn(Insn::IfNot {
reg: condition_reg,
target_pc: next_check_label,
jump_if_null: true,
});
translate_expr_no_constant_opt(
program,
referenced_tables,
value_expr,
target_register,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
program.emit_insn(Insn::Goto {
target_pc: iif_end_label,
});
program.preassign_label_to_next_insn(next_check_label);
}
let temp_reg = program.alloc_register();
translate_expr_no_constant_opt(
program,
referenced_tables,
&args[0],
temp_reg,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
let jump_target_when_false = program.allocate_label();
program.emit_insn(Insn::IfNot {
reg: temp_reg,
target_pc: jump_target_when_false,
jump_if_null: true,
});
translate_expr_no_constant_opt(
program,
referenced_tables,
&args[1],
target_register,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
let jump_target_result = program.allocate_label();
program.emit_insn(Insn::Goto {
target_pc: jump_target_result,
});
program.preassign_label_to_next_insn(jump_target_when_false);
translate_expr_no_constant_opt(
program,
referenced_tables,
&args[2],
target_register,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
program.preassign_label_to_next_insn(jump_target_result);
if args.len() % 2 != 0 {
translate_expr_no_constant_opt(
program,
referenced_tables,
args.last().unwrap(),
target_register,
resolver,
NoConstantOptReason::RegisterReuse,
)?;
} else {
program.emit_insn(Insn::Null {
dest: target_register,
dest_end: None,
});
}
program.preassign_label_to_next_insn(iif_end_label);
Ok(target_register)
}
ScalarFunc::Glob | ScalarFunc::Like => {
if args.len() < 2 {
crate::bail_parse_error!(

View File

@@ -1023,7 +1023,58 @@ do_execsql_test sum-8 {
} {1.2}
# https://github.com/tursodatabase/turso/issues/3689
do_execsql_test iif-3-args-true {
select iif(1 < 2, 'yes', 'no');
} {yes}
do_execsql_test iif-3-args-false {
select iif(1 > 2, 'yes', 'no');
} {no}
do_execsql_test iif-2-args-true {
select iif(1 < 2, 'yes');
} {yes}
do_execsql_test iif-2-args-false-is-null {
select iif(1 > 2, 'yes');
} {}
do_execsql_test iif-multi-args-finds-first-true {
select iif(0, 'a', 1, 'b', 2, 'c', 'default');
} {b}
do_execsql_test iif-multi-args-falls-to-else {
select iif(0, 'a', 0, 'b', 0, 'c', 'default');
} {default}
do_execsql_test if-alias-3-args-true {
select if(1 < 2, 'yes', 'no');
} {yes}
do_execsql_test if-alias-3-args-false {
select if(1 > 2, 'yes', 'no');
} {no}
do_execsql_test if-alias-2-args-true {
select if(1 < 2, 'ok');
} {ok}
do_execsql_test if-alias-multi-args-finds-first-true {
select if(0, 'a', 1, 'b', 'c');
} {b}
do_execsql_test if-alias-multi-args-falls-to-else {
select if(0, 'a', 0, 'b', 'c');
} {c}
do_execsql_test if-alias-multi-args-no-else-is-null {
select if(0, 'a', 0, 'b');
} {}
# TODO: sqlite seems not enable soundex() by default unless build it with SQLITE_SOUNDEX enabled.
# do_execsql_test soundex-text {
# select soundex('Pfister'), soundex('husobee'), soundex('Tymczak'), soundex('Ashcraft'), soundex('Robert'), soundex('Rupert'), soundex('Rubin'), soundex('Kant'), soundex('Knuth'), soundex('x'), soundex('');
# } {P236|H210|T522|A261|R163|R163|R150|K530|K530|X000|0000}