mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-31 13:54:27 +01:00
Merge 'Add support for unlikely(X)' from bit-aloo
Implements the unlikely(X) function. Removes runtime implementations of likely(), unlikely() and likelihood(), replacing them with panics if they reach the VDBE. Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #2559
This commit is contained in:
@@ -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 | |
|
||||
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user