diff --git a/COMPAT.md b/COMPAT.md index 723ab1938..a81641055 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -264,7 +264,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 | | diff --git a/core/function.rs b/core/function.rs index 0c29afd38..884b41655 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}") } @@ -748,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")] diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 6bd60d2fb..d2290fc9d 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -1710,20 +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::Function { - constant_mask: 0, - start_reg, - dest: target_register, - func: func_ctx, - }); Ok(target_register) } ScalarFunc::Likelihood => { @@ -1760,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 => { @@ -1841,6 +1827,27 @@ 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",); + }; + translate_expr( + program, + referenced_tables, + &args[0], + target_register, + resolver, + )?; + + Ok(target_register) + } } } Func::Math(math_func) => match math_func.arity() { diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index e2ee9f795..3144cd8a5 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -4473,20 +4473,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"))] @@ -4652,6 +4638,11 @@ pub fn op_function( // Set result to NULL (detach doesn't return a value) state.registers[*dest] = Register::Value(Value::Null); } + 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 { VectorFunc::Vector => { @@ -7989,14 +7980,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() } @@ -10067,62 +10050,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();