From 3581895f1857c2d6fb9703f3dc3aa0ce11905cae Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 12 Aug 2025 16:27:23 +0530 Subject: [PATCH 01/11] add unlikely scalar method --- core/function.rs | 3 +++ core/translate/expr.rs | 27 +++++++++++++++++++++++++++ core/vdbe/execute.rs | 9 +++++++++ 3 files changed, 39 insertions(+) diff --git a/core/function.rs b/core/function.rs index 0c29afd38..056054cec 100644 --- a/core/function.rs +++ b/core/function.rs @@ -331,6 +331,7 @@ pub enum ScalarFunc { BinRecordJsonObject, Attach, Detach, + Unlikely } impl ScalarFunc { @@ -393,6 +394,7 @@ impl ScalarFunc { ScalarFunc::BinRecordJsonObject => true, ScalarFunc::Attach => false, // changes database state ScalarFunc::Detach => false, // changes database state + ScalarFunc::Unlikely => true, } } } @@ -457,6 +459,7 @@ impl Display for ScalarFunc { Self::BinRecordJsonObject => "bin_record_json_object".to_string(), Self::Attach => "attach".to_string(), Self::Detach => "detach".to_string(), + Self::Unlikely => "unlikely".to_string() }; write!(f, "{str}") } diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 6bd60d2fb..e0dc0ef7a 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -1841,6 +1841,33 @@ pub fn translate_expr( "DETACH should be handled at statement level, not as expression" ); } + ScalarFunc::Unlikely => { + let args = if let Some(args) = args { + if args.len() != 1 { + crate::bail_parse_error!( + "Unlikely function must have exactly 1 argument", + ); + } + args + } else { + crate::bail_parse_error!("Unlikely function with no arguments",); + }; + let start_reg = program.alloc_register(); + translate_expr( + program, + referenced_tables, + &args[0], + start_reg, + resolver, + )?; + program.emit_insn(Insn::Function { + constant_mask: 0, + start_reg, + dest: target_register, + func: func_ctx, + }); + Ok(target_register) + } } } Func::Math(math_func) => match math_func.arity() { diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 0d80ff2ad..3186cbeed 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -4569,6 +4569,11 @@ pub fn op_function( // Set result to NULL (detach doesn't return a value) state.registers[*dest] = Register::Value(Value::Null); } + ScalarFunc::Unlikely => { + let value = &state.registers[*start_reg].borrow_mut(); + let result = value.get_owned_value().exec_unlikely(); + state.registers[*dest] = Register::Value(result); + } }, crate::function::Func::Vector(vector_func) => match vector_func { VectorFunc::Vector => { @@ -8051,6 +8056,10 @@ impl Value { pub fn exec_max<'a, T: Iterator>(regs: T) -> Value { regs.max().map(|v| v.to_owned()).unwrap_or(Value::Null) } + + fn exec_unlikely(&self) -> Value { + self.exec_likelihood(&Value::Float(0.0625)) + } } fn exec_concat_strings(registers: &[Register]) -> Value { From c9368ed80984948da429a54e19a918ca3bfdb5bf Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 12 Aug 2025 16:27:45 +0530 Subject: [PATCH 02/11] add test --- core/vdbe/execute.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 3186cbeed..eccb1f111 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -10061,4 +10061,27 @@ mod tests { assert!(!bitfield.get(i)); } } + + #[test] + fn test_unlikely() { + let input = Value::build_text("turso"); + let expected = Value::build_text("turso"); + assert_eq!(input.exec_unlikely(), expected); + + let input = Value::Integer(42); + let expected = Value::Integer(42); + assert_eq!(input.exec_unlikely(), expected); + + let input = Value::Float(99.99); + let expected = Value::Float(99.99); + assert_eq!(input.exec_unlikely(), expected); + + let input = Value::Null; + let expected = Value::Null; + assert_eq!(input.exec_unlikely(), expected); + + let input = Value::Blob(vec![10, 20, 30, 40]); + let expected = Value::Blob(vec![10, 20, 30, 40]); + assert_eq!(input.exec_unlikely(), expected); + } } From 71525c90e52e7266172ce58300dada0c0c8c2d4a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 12 Aug 2025 16:27:58 +0530 Subject: [PATCH 03/11] update compat.md --- COMPAT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COMPAT.md b/COMPAT.md index 310e8ee56..78ee93d3f 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -265,7 +265,7 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html). | unhex(X) | Yes | | | unhex(X,Y) | Yes | | | unicode(X) | Yes | | -| unlikely(X) | No | | +| unlikely(X) | Yes | | | upper(X) | Yes | | | zeroblob(N) | Yes | | From a545995b44566a95f28c47750c0244c84e511e1e Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 12 Aug 2025 16:36:22 +0530 Subject: [PATCH 04/11] fix fmt and clippy --- core/function.rs | 4 ++-- core/vdbe/execute.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/function.rs b/core/function.rs index 056054cec..e83879165 100644 --- a/core/function.rs +++ b/core/function.rs @@ -331,7 +331,7 @@ pub enum ScalarFunc { BinRecordJsonObject, Attach, Detach, - Unlikely + Unlikely, } impl ScalarFunc { @@ -459,7 +459,7 @@ impl Display for ScalarFunc { Self::BinRecordJsonObject => "bin_record_json_object".to_string(), Self::Attach => "attach".to_string(), Self::Detach => "detach".to_string(), - Self::Unlikely => "unlikely".to_string() + Self::Unlikely => "unlikely".to_string(), }; write!(f, "{str}") } diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index eccb1f111..08e0cadbd 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -10067,21 +10067,21 @@ mod tests { let input = Value::build_text("turso"); let expected = Value::build_text("turso"); assert_eq!(input.exec_unlikely(), expected); - + let input = Value::Integer(42); let expected = Value::Integer(42); assert_eq!(input.exec_unlikely(), expected); - + let input = Value::Float(99.99); let expected = Value::Float(99.99); assert_eq!(input.exec_unlikely(), expected); - + let input = Value::Null; let expected = Value::Null; assert_eq!(input.exec_unlikely(), expected); - + let input = Value::Blob(vec![10, 20, 30, 40]); let expected = Value::Blob(vec![10, 20, 30, 40]); assert_eq!(input.exec_unlikely(), expected); - } + } } From aff269f1d580271d8fba1cc5088103728b16bf29 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 12 Aug 2025 16:42:38 +0530 Subject: [PATCH 05/11] add unlikely to resolve function --- core/function.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/function.rs b/core/function.rs index e83879165..884b41655 100644 --- a/core/function.rs +++ b/core/function.rs @@ -751,6 +751,7 @@ impl Func { "replace" => Ok(Self::Scalar(ScalarFunc::Replace)), "likely" => Ok(Self::Scalar(ScalarFunc::Likely)), "likelihood" => Ok(Self::Scalar(ScalarFunc::Likelihood)), + "unlikely" => Ok(Self::Scalar(ScalarFunc::Unlikely)), #[cfg(feature = "json")] "json" => Ok(Self::Json(JsonFunc::Json)), #[cfg(feature = "json")] From e72097e2b7b1e4e56bb8810714a4f7a9c2430aa4 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 Aug 2025 22:46:22 +0530 Subject: [PATCH 06/11] strip likely and just translate the inner value --- core/translate/expr.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/translate/expr.rs b/core/translate/expr.rs index e0dc0ef7a..84d378b0e 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -1718,11 +1718,10 @@ pub fn translate_expr( start_reg, resolver, )?; - program.emit_insn(Insn::Function { - constant_mask: 0, - start_reg, - dest: target_register, - func: func_ctx, + program.emit_insn(Insn::Copy { + src_reg: start_reg, + dst_reg: target_register, + extra_amount: 0, }); Ok(target_register) } From eda3a823068cbd296246ec4ebb6c4405a0d019ed Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 Aug 2025 22:46:31 +0530 Subject: [PATCH 07/11] strip unylikely and just translate the inner value --- core/translate/expr.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 84d378b0e..7e7f11dd6 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -1859,11 +1859,10 @@ pub fn translate_expr( start_reg, resolver, )?; - program.emit_insn(Insn::Function { - constant_mask: 0, - start_reg, - dest: target_register, - func: func_ctx, + program.emit_insn(Insn::Copy { + src_reg: start_reg, + dst_reg: target_register, + extra_amount: 0, }); Ok(target_register) } From 198ba6ca62f8e04011601bc767924346aa9c9897 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 Aug 2025 22:50:29 +0530 Subject: [PATCH 08/11] panic in vdbe if we hit likely, likelihood, and unlikely scalar method --- core/vdbe/execute.rs | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 08e0cadbd..d3bf907b5 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -4390,20 +4390,6 @@ pub fn op_function( let result = exec_printf(&state.registers[*start_reg..*start_reg + arg_count])?; state.registers[*dest] = Register::Value(result); } - ScalarFunc::Likely => { - let value = &state.registers[*start_reg].borrow_mut(); - let result = value.get_owned_value().exec_likely(); - state.registers[*dest] = Register::Value(result); - } - ScalarFunc::Likelihood => { - assert_eq!(arg_count, 2); - let value = &state.registers[*start_reg]; - let probability = &state.registers[*start_reg + 1]; - let result = value - .get_owned_value() - .exec_likelihood(probability.get_owned_value()); - state.registers[*dest] = Register::Value(result); - } ScalarFunc::TableColumnsJsonArray => { assert_eq!(arg_count, 1); #[cfg(not(feature = "json"))] @@ -4569,10 +4555,10 @@ pub fn op_function( // Set result to NULL (detach doesn't return a value) state.registers[*dest] = Register::Value(Value::Null); } - ScalarFunc::Unlikely => { - let value = &state.registers[*start_reg].borrow_mut(); - let result = value.get_owned_value().exec_unlikely(); - state.registers[*dest] = Register::Value(result); + ScalarFunc::Unlikely | ScalarFunc::Likely | ScalarFunc::Likelihood => { + panic!( + "{scalar_func:?} should be stripped during expression translation and never reach VDBE", + ); } }, crate::function::Func::Vector(vector_func) => match vector_func { From 8e6df064df96500ad7468fba1a74c314b26ad4ab Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 Aug 2025 22:51:22 +0530 Subject: [PATCH 09/11] remove likelihood, likely and unlikely exec methods, as we dont need them --- core/vdbe/execute.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index d3bf907b5..4c41a1778 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -7888,14 +7888,6 @@ impl Value { Value::Float(result) } - fn exec_likely(&self) -> Value { - self.clone() - } - - fn exec_likelihood(&self, _probability: &Value) -> Value { - self.clone() - } - pub fn exec_add(&self, rhs: &Value) -> Value { (Numeric::from(self) + Numeric::from(rhs)).into() } @@ -8042,10 +8034,6 @@ impl Value { pub fn exec_max<'a, T: Iterator>(regs: T) -> Value { regs.max().map(|v| v.to_owned()).unwrap_or(Value::Null) } - - fn exec_unlikely(&self) -> Value { - self.exec_likelihood(&Value::Float(0.0625)) - } } fn exec_concat_strings(registers: &[Register]) -> Value { From 96be4eb40c849dcd6e0ed03ce6cceaca9d0546de Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 13 Aug 2025 22:51:36 +0530 Subject: [PATCH 10/11] remove the exec_* test --- core/vdbe/execute.rs | 79 -------------------------------------------- 1 file changed, 79 deletions(-) diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 4c41a1778..5b6a4d2dc 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -9961,62 +9961,6 @@ mod tests { ); } - #[test] - fn test_likely() { - let input = Value::build_text("limbo"); - let expected = Value::build_text("limbo"); - assert_eq!(input.exec_likely(), expected); - - let input = Value::Integer(100); - let expected = Value::Integer(100); - assert_eq!(input.exec_likely(), expected); - - let input = Value::Float(12.34); - let expected = Value::Float(12.34); - assert_eq!(input.exec_likely(), expected); - - let input = Value::Null; - let expected = Value::Null; - assert_eq!(input.exec_likely(), expected); - - let input = Value::Blob(vec![1, 2, 3, 4]); - let expected = Value::Blob(vec![1, 2, 3, 4]); - assert_eq!(input.exec_likely(), expected); - } - - #[test] - fn test_likelihood() { - let value = Value::build_text("limbo"); - let prob = Value::Float(0.5); - assert_eq!(value.exec_likelihood(&prob), value); - - let value = Value::build_text("database"); - let prob = Value::Float(0.9375); - assert_eq!(value.exec_likelihood(&prob), value); - - let value = Value::Integer(100); - let prob = Value::Float(1.0); - assert_eq!(value.exec_likelihood(&prob), value); - - let value = Value::Float(12.34); - let prob = Value::Float(0.5); - assert_eq!(value.exec_likelihood(&prob), value); - - let value = Value::Null; - let prob = Value::Float(0.5); - assert_eq!(value.exec_likelihood(&prob), value); - - let value = Value::Blob(vec![1, 2, 3, 4]); - let prob = Value::Float(0.5); - assert_eq!(value.exec_likelihood(&prob), value); - - let prob = Value::build_text("0.5"); - assert_eq!(value.exec_likelihood(&prob), value); - - let prob = Value::Null; - assert_eq!(value.exec_likelihood(&prob), value); - } - #[test] fn test_bitfield() { let mut bitfield = Bitfield::<4>::new(); @@ -10035,27 +9979,4 @@ mod tests { assert!(!bitfield.get(i)); } } - - #[test] - fn test_unlikely() { - let input = Value::build_text("turso"); - let expected = Value::build_text("turso"); - assert_eq!(input.exec_unlikely(), expected); - - let input = Value::Integer(42); - let expected = Value::Integer(42); - assert_eq!(input.exec_unlikely(), expected); - - let input = Value::Float(99.99); - let expected = Value::Float(99.99); - assert_eq!(input.exec_unlikely(), expected); - - let input = Value::Null; - let expected = Value::Null; - assert_eq!(input.exec_unlikely(), expected); - - let input = Value::Blob(vec![10, 20, 30, 40]); - let expected = Value::Blob(vec![10, 20, 30, 40]); - assert_eq!(input.exec_unlikely(), expected); - } } From 32e59614c720c43f66370eb7a8c6b9d989858833 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 14 Aug 2025 09:08:32 +0530 Subject: [PATCH 11/11] remove unnecessary copy instr in likelihood, likely and unlikely --- core/translate/expr.rs | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 7e7f11dd6..d2290fc9d 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -1710,19 +1710,13 @@ pub fn translate_expr( } else { crate::bail_parse_error!("likely function with no arguments",); }; - let start_reg = program.alloc_register(); translate_expr( program, referenced_tables, &args[0], - start_reg, + target_register, resolver, )?; - program.emit_insn(Insn::Copy { - src_reg: start_reg, - dst_reg: target_register, - extra_amount: 0, - }); Ok(target_register) } ScalarFunc::Likelihood => { @@ -1759,20 +1753,13 @@ pub fn translate_expr( "second argument of likelihood() must be a numeric literal", ); } - - let start_reg = program.alloc_register(); translate_expr( program, referenced_tables, &args[0], - start_reg, + target_register, resolver, )?; - program.emit_insn(Insn::Copy { - src_reg: start_reg, - dst_reg: target_register, - extra_amount: 0, - }); Ok(target_register) } ScalarFunc::TableColumnsJsonArray => { @@ -1851,19 +1838,14 @@ pub fn translate_expr( } else { crate::bail_parse_error!("Unlikely function with no arguments",); }; - let start_reg = program.alloc_register(); translate_expr( program, referenced_tables, &args[0], - start_reg, + target_register, resolver, )?; - program.emit_insn(Insn::Copy { - src_reg: start_reg, - dst_reg: target_register, - extra_amount: 0, - }); + Ok(target_register) } }