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 {