mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-09 10:14:21 +01:00
Support log(X) and log(B,X) math functions
This commit is contained in:
@@ -179,8 +179,8 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
|
||||
| exp(X) | Yes | |
|
||||
| floor(X) | Yes | |
|
||||
| ln(X) | Yes | |
|
||||
| log(B,X) | No | |
|
||||
| log(X) | No | |
|
||||
| log(B,X) | Yes | |
|
||||
| log(X) | Yes | |
|
||||
| log10(X) | Yes | |
|
||||
| log2(X) | Yes | |
|
||||
| mod(X,Y) | Yes | |
|
||||
|
||||
@@ -1696,7 +1696,40 @@ pub fn translate_expr(
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
|
||||
MathFuncArity::UnaryOrBinary => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() > 2 {
|
||||
crate::bail_parse_error!(
|
||||
"{} function with more than 2 arguments",
|
||||
math_func
|
||||
);
|
||||
}
|
||||
args
|
||||
} else {
|
||||
crate::bail_parse_error!("{} function with no arguments", math_func);
|
||||
};
|
||||
|
||||
let regs = program.alloc_registers(args.len());
|
||||
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
arg,
|
||||
regs + i,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
}
|
||||
|
||||
program.emit_insn(Insn::Function {
|
||||
constant_mask: 0,
|
||||
start_reg: regs,
|
||||
dest: target_register,
|
||||
func: func_ctx,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2509,7 +2509,24 @@ impl Program {
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
MathFuncArity::UnaryOrBinary => match math_func {
|
||||
MathFunc::Log => {
|
||||
let lhs = &state.registers[*start_reg];
|
||||
let rhs = state.registers.get(*start_reg + 1);
|
||||
|
||||
let result = if let Some(arg) = rhs {
|
||||
exec_math_log(arg, Some(lhs))
|
||||
} else {
|
||||
exec_math_log(lhs, None)
|
||||
};
|
||||
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
_ => unreachable!(
|
||||
"Unexpected mathematical UnaryOrBinary function {:?}",
|
||||
math_func
|
||||
),
|
||||
},
|
||||
},
|
||||
crate::function::Func::Agg(_) => {
|
||||
unreachable!("Aggregate functions should not be handled here")
|
||||
@@ -3699,6 +3716,27 @@ fn exec_math_binary(lhs: &OwnedValue, rhs: &OwnedValue, function: &MathFunc) ->
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_math_log(arg: &OwnedValue, base: Option<&OwnedValue>) -> OwnedValue {
|
||||
let f = match to_f64(arg) {
|
||||
Some(f) => f,
|
||||
None => return OwnedValue::Null,
|
||||
};
|
||||
|
||||
let base = match base {
|
||||
Some(base) => match to_f64(base) {
|
||||
Some(f) => f,
|
||||
None => return OwnedValue::Null,
|
||||
},
|
||||
None => 10.0,
|
||||
};
|
||||
|
||||
if f <= 0.0 || base <= 0.0 || base == 1.0 {
|
||||
return OwnedValue::Null;
|
||||
}
|
||||
|
||||
OwnedValue::Float(f.log(base))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
||||
@@ -976,3 +976,68 @@ do_execsql_test power-null-int {
|
||||
do_execsql_test power-int-null {
|
||||
SELECT power(5, null)
|
||||
} {}
|
||||
|
||||
|
||||
do_execsql_test_tolerance log-int {
|
||||
SELECT log(1)
|
||||
} {0.0} $tolerance
|
||||
|
||||
do_execsql_test_tolerance log-float {
|
||||
SELECT log(1.5)
|
||||
} {0.176091259055681} $tolerance
|
||||
|
||||
do_execsql_test_tolerance log-str {
|
||||
SELECT log('1.5')
|
||||
} {0.176091259055681} $tolerance
|
||||
|
||||
do_execsql_test log-negative {
|
||||
SELECT log(-1.5)
|
||||
} {}
|
||||
|
||||
do_execsql_test log-null {
|
||||
SELECT log(null)
|
||||
} {}
|
||||
|
||||
do_execsql_test_tolerance log-int-int {
|
||||
SELECT log(5, 1)
|
||||
} {0.0} $tolerance
|
||||
|
||||
do_execsql_test_tolerance log-int-float {
|
||||
SELECT log(5, 1.5)
|
||||
} {0.251929636412592} $tolerance
|
||||
|
||||
do_execsql_test_tolerance log-int-str {
|
||||
SELECT log(5, '1.5')
|
||||
} {0.251929636412592} $tolerance
|
||||
|
||||
do_execsql_test_tolerance log-float-int {
|
||||
SELECT log(5.5, 10)
|
||||
} {1.35068935021985} $tolerance
|
||||
|
||||
do_execsql_test_tolerance log-float-float {
|
||||
SELECT log(5.5, 1.5)
|
||||
} {0.237844588273313} $tolerance
|
||||
|
||||
do_execsql_test_tolerance log-float-str {
|
||||
SELECT log(5.5, '1.5')
|
||||
} {0.237844588273313} $tolerance
|
||||
|
||||
do_execsql_test_tolerance log-str-str {
|
||||
SELECT log('5.5', '1.5')
|
||||
} {0.237844588273313} $tolerance
|
||||
|
||||
do_execsql_test log-negative-negative {
|
||||
SELECT log(-1.5, -1.5)
|
||||
} {}
|
||||
|
||||
do_execsql_test log-float-negative {
|
||||
SELECT log(1.5, -1.5)
|
||||
} {}
|
||||
|
||||
do_execsql_test log-null-int {
|
||||
SELECT log(null, 5)
|
||||
} {}
|
||||
|
||||
do_execsql_test log-int-null {
|
||||
SELECT log(5, null)
|
||||
} {}
|
||||
|
||||
Reference in New Issue
Block a user