1use std::any::Any;
21
22use super::power::PowerFunc;
23
24use crate::utils::calculate_binary_math;
25use arrow::array::{Array, ArrayRef};
26use arrow::datatypes::{
27 DataType, Decimal32Type, Decimal64Type, Decimal128Type, Decimal256Type, Float16Type,
28 Float32Type, Float64Type,
29};
30use arrow::error::ArrowError;
31use arrow_buffer::i256;
32use datafusion_common::types::NativeType;
33use datafusion_common::{
34 Result, ScalarValue, exec_err, internal_err, plan_datafusion_err, plan_err,
35};
36use datafusion_expr::expr::ScalarFunction;
37use datafusion_expr::simplify::{ExprSimplifyResult, SimplifyContext};
38use datafusion_expr::sort_properties::{ExprProperties, SortProperties};
39use datafusion_expr::{
40 Coercion, ColumnarValue, Documentation, Expr, ScalarFunctionArgs, ScalarUDF,
41 TypeSignature, TypeSignatureClass, lit,
42};
43use datafusion_expr::{ScalarUDFImpl, Signature, Volatility};
44use datafusion_macros::user_doc;
45use num_traits::{Float, ToPrimitive};
46
47#[user_doc(
48 doc_section(label = "Math Functions"),
49 description = "Returns the base-x logarithm of a number. Can either provide a specified base, or if omitted then takes the base-10 of a number.",
50 syntax_example = r#"log(base, numeric_expression)
51log(numeric_expression)"#,
52 sql_example = r#"```sql
53> SELECT log(10);
54+---------+
55| log(10) |
56+---------+
57| 1.0 |
58+---------+
59```"#,
60 standard_argument(name = "base", prefix = "Base numeric"),
61 standard_argument(name = "numeric_expression", prefix = "Numeric")
62)]
63#[derive(Debug, PartialEq, Eq, Hash)]
64pub struct LogFunc {
65 signature: Signature,
66}
67
68impl Default for LogFunc {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74impl LogFunc {
75 pub fn new() -> Self {
76 let as_float = Coercion::new_implicit(
78 TypeSignatureClass::Float,
79 vec![TypeSignatureClass::Numeric],
80 NativeType::Float64,
81 );
82 Self {
83 signature: Signature::one_of(
84 vec![
87 TypeSignature::Coercible(vec![Coercion::new_exact(
89 TypeSignatureClass::Decimal,
90 )]),
91 TypeSignature::Coercible(vec![as_float.clone()]),
92 TypeSignature::Coercible(vec![
94 as_float.clone(),
95 Coercion::new_exact(TypeSignatureClass::Decimal),
96 ]),
97 TypeSignature::Coercible(vec![as_float.clone(), as_float.clone()]),
98 ],
99 Volatility::Immutable,
100 ),
101 }
102 }
103}
104
105#[inline]
107fn is_valid_integer_base(base: f64) -> bool {
108 base.trunc() == base && base >= 2.0 && base <= u32::MAX as f64
109}
110
111fn log_decimal32(value: i32, scale: i8, base: f64) -> Result<f64, ArrowError> {
115 if is_valid_integer_base(base)
116 && scale >= 0
117 && let Some(unscaled) = unscale_to_u32(value, scale)
118 {
119 return if unscaled > 0 {
120 Ok(unscaled.ilog(base as u32) as f64)
121 } else {
122 Ok(f64::NAN)
123 };
124 }
125 decimal_to_f64(value, scale).map(|v| v.log(base))
126}
127
128fn log_decimal64(value: i64, scale: i8, base: f64) -> Result<f64, ArrowError> {
132 if is_valid_integer_base(base)
133 && scale >= 0
134 && let Some(unscaled) = unscale_to_u64(value, scale)
135 {
136 return if unscaled > 0 {
137 Ok(unscaled.ilog(base as u64) as f64)
138 } else {
139 Ok(f64::NAN)
140 };
141 }
142 decimal_to_f64(value, scale).map(|v| v.log(base))
143}
144
145fn log_decimal128(value: i128, scale: i8, base: f64) -> Result<f64, ArrowError> {
149 if is_valid_integer_base(base)
150 && scale >= 0
151 && let Some(unscaled) = unscale_to_u128(value, scale)
152 {
153 return if unscaled > 0 {
154 Ok(unscaled.ilog(base as u128) as f64)
155 } else {
156 Ok(f64::NAN)
157 };
158 }
159 decimal_to_f64(value, scale).map(|v| v.log(base))
160}
161
162#[inline]
164fn unscale_to_u32(value: i32, scale: i8) -> Option<u32> {
165 let value_u32 = u32::try_from(value).ok()?;
166 let divisor = 10u32.checked_pow(scale as u32)?;
167 Some(value_u32 / divisor)
168}
169
170#[inline]
172fn unscale_to_u64(value: i64, scale: i8) -> Option<u64> {
173 let value_u64 = u64::try_from(value).ok()?;
174 let divisor = 10u64.checked_pow(scale as u32)?;
175 Some(value_u64 / divisor)
176}
177
178#[inline]
180fn unscale_to_u128(value: i128, scale: i8) -> Option<u128> {
181 let value_u128 = u128::try_from(value).ok()?;
182 let divisor = 10u128.checked_pow(scale as u32)?;
183 Some(value_u128 / divisor)
184}
185
186#[inline]
188fn decimal_to_f64<T: ToPrimitive + Copy>(value: T, scale: i8) -> Result<f64, ArrowError> {
189 let value_f64 = value.to_f64().ok_or_else(|| {
190 ArrowError::ComputeError("Cannot convert value to f64".to_string())
191 })?;
192 let scale_factor = 10f64.powi(scale as i32);
193 Ok(value_f64 / scale_factor)
194}
195
196fn log_decimal256(value: i256, scale: i8, base: f64) -> Result<f64, ArrowError> {
197 match value.to_i128() {
199 Some(v) => log_decimal128(v, scale, base),
200 None => {
201 let value_f64 = value.to_f64().ok_or_else(|| {
203 ArrowError::ComputeError(format!("Cannot convert {value} to f64"))
204 })?;
205 let scale_factor = 10f64.powi(scale as i32);
206 Ok((value_f64 / scale_factor).log(base))
207 }
208 }
209}
210
211impl ScalarUDFImpl for LogFunc {
212 fn as_any(&self) -> &dyn Any {
213 self
214 }
215 fn name(&self) -> &str {
216 "log"
217 }
218
219 fn signature(&self) -> &Signature {
220 &self.signature
221 }
222
223 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
224 match &arg_types.last().ok_or(plan_datafusion_err!("No args"))? {
226 DataType::Float16 => Ok(DataType::Float16),
227 DataType::Float32 => Ok(DataType::Float32),
228 _ => Ok(DataType::Float64),
229 }
230 }
231
232 fn output_ordering(&self, input: &[ExprProperties]) -> Result<SortProperties> {
233 let (base_sort_properties, num_sort_properties) = if input.len() == 1 {
234 (SortProperties::Singleton, input[0].sort_properties)
236 } else {
237 (input[0].sort_properties, input[1].sort_properties)
238 };
239 match (num_sort_properties, base_sort_properties) {
240 (first @ SortProperties::Ordered(num), SortProperties::Ordered(base))
241 if num.descending != base.descending
242 && num.nulls_first == base.nulls_first =>
243 {
244 Ok(first)
245 }
246 (
247 first @ (SortProperties::Ordered(_) | SortProperties::Singleton),
248 SortProperties::Singleton,
249 ) => Ok(first),
250 (SortProperties::Singleton, second @ SortProperties::Ordered(_)) => {
251 Ok(-second)
252 }
253 _ => Ok(SortProperties::Unordered),
254 }
255 }
256
257 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
259 if args.arg_fields.iter().any(|a| a.data_type().is_null()) {
260 return ColumnarValue::Scalar(ScalarValue::Null)
261 .cast_to(args.return_type(), None);
262 }
263
264 let (base, value) = if args.args.len() == 2 {
265 (args.args[0].clone(), &args.args[1])
266 } else {
267 (
269 ColumnarValue::Scalar(ScalarValue::new_ten(args.return_type())?),
270 &args.args[0],
271 )
272 };
273 let value = value.to_array(args.number_rows)?;
274
275 let output: ArrayRef = match value.data_type() {
276 DataType::Float16 => {
277 calculate_binary_math::<Float16Type, Float16Type, Float16Type, _>(
278 &value,
279 &base,
280 |value, base| Ok(value.log(base)),
281 )?
282 }
283 DataType::Float32 => {
284 calculate_binary_math::<Float32Type, Float32Type, Float32Type, _>(
285 &value,
286 &base,
287 |value, base| Ok(value.log(base)),
288 )?
289 }
290 DataType::Float64 => {
291 calculate_binary_math::<Float64Type, Float64Type, Float64Type, _>(
292 &value,
293 &base,
294 |value, base| Ok(value.log(base)),
295 )?
296 }
297 DataType::Decimal32(_, scale) => {
298 calculate_binary_math::<Decimal32Type, Float64Type, Float64Type, _>(
299 &value,
300 &base,
301 |value, base| log_decimal32(value, *scale, base),
302 )?
303 }
304 DataType::Decimal64(_, scale) => {
305 calculate_binary_math::<Decimal64Type, Float64Type, Float64Type, _>(
306 &value,
307 &base,
308 |value, base| log_decimal64(value, *scale, base),
309 )?
310 }
311 DataType::Decimal128(_, scale) => {
312 calculate_binary_math::<Decimal128Type, Float64Type, Float64Type, _>(
313 &value,
314 &base,
315 |value, base| log_decimal128(value, *scale, base),
316 )?
317 }
318 DataType::Decimal256(_, scale) => {
319 calculate_binary_math::<Decimal256Type, Float64Type, Float64Type, _>(
320 &value,
321 &base,
322 |value, base| log_decimal256(value, *scale, base),
323 )?
324 }
325 other => {
326 return exec_err!("Unsupported data type {other:?} for function log");
327 }
328 };
329
330 Ok(ColumnarValue::Array(output))
331 }
332
333 fn documentation(&self) -> Option<&Documentation> {
334 self.doc()
335 }
336
337 fn simplify(
342 &self,
343 mut args: Vec<Expr>,
344 info: &SimplifyContext,
345 ) -> Result<ExprSimplifyResult> {
346 let mut arg_types = args
347 .iter()
348 .map(|arg| info.get_data_type(arg))
349 .collect::<Result<Vec<_>>>()?;
350 let return_type = self.return_type(&arg_types)?;
351
352 if arg_types.iter().any(|dt| dt.is_null()) {
354 return Ok(ExprSimplifyResult::Simplified(lit(
355 ScalarValue::Null.cast_to(&return_type)?
356 )));
357 }
358
359 let num_args = args.len();
363 if num_args != 1 && num_args != 2 {
364 return plan_err!("Expected log to have 1 or 2 arguments, got {num_args}");
365 }
366
367 match arg_types.last().unwrap() {
368 DataType::Decimal32(_, scale)
369 | DataType::Decimal64(_, scale)
370 | DataType::Decimal128(_, scale)
371 | DataType::Decimal256(_, scale)
372 if *scale < 0 =>
373 {
374 return Ok(ExprSimplifyResult::Original(args));
375 }
376 _ => (),
377 };
378
379 let number = args.pop().unwrap();
380 let number_datatype = arg_types.pop().unwrap();
381 let base = if let Some(base) = args.pop() {
383 base
384 } else {
385 lit(ScalarValue::new_ten(&number_datatype)?)
386 };
387
388 match number {
389 Expr::Literal(value, _)
390 if value == ScalarValue::new_one(&number_datatype)? =>
391 {
392 Ok(ExprSimplifyResult::Simplified(lit(ScalarValue::new_zero(
393 &info.get_data_type(&base)?,
394 )?)))
395 }
396 Expr::ScalarFunction(ScalarFunction { func, mut args })
397 if is_pow(&func) && args.len() == 2 && base == args[0] =>
398 {
399 let b = args.pop().unwrap(); Ok(ExprSimplifyResult::Simplified(b))
401 }
402 number => {
403 if number == base {
404 Ok(ExprSimplifyResult::Simplified(lit(ScalarValue::new_one(
405 &number_datatype,
406 )?)))
407 } else {
408 let args = match num_args {
409 1 => vec![number],
410 2 => vec![base, number],
411 _ => {
412 return internal_err!(
413 "Unexpected number of arguments in log::simplify"
414 );
415 }
416 };
417 Ok(ExprSimplifyResult::Original(args))
418 }
419 }
420 }
421 }
422}
423
424fn is_pow(func: &ScalarUDF) -> bool {
426 func.inner().as_any().downcast_ref::<PowerFunc>().is_some()
427}
428
429#[cfg(test)]
430mod tests {
431 use std::sync::Arc;
432
433 use super::*;
434
435 use arrow::array::{
436 Date32Array, Decimal128Array, Decimal256Array, Float32Array, Float64Array,
437 };
438 use arrow::compute::SortOptions;
439 use arrow::datatypes::{DECIMAL256_MAX_PRECISION, Field};
440 use datafusion_common::cast::{as_float32_array, as_float64_array};
441 use datafusion_common::config::ConfigOptions;
442 use datafusion_expr::simplify::SimplifyContext;
443
444 #[test]
445 fn test_log_decimal_native() {
446 let value = 10_i128.pow(35);
447 assert_eq!((value as f64).log2(), 116.26748332105768);
448 assert_eq!(
449 log_decimal128(value, 0, 2.0).unwrap(),
450 116.0
453 );
454 }
455
456 #[test]
457 fn test_log_invalid_base_type() {
458 let arg_fields = vec![
459 Field::new("b", DataType::Date32, false).into(),
460 Field::new("n", DataType::Float64, false).into(),
461 ];
462 let args = ScalarFunctionArgs {
463 args: vec![
464 ColumnarValue::Array(Arc::new(Date32Array::from(vec![5, 10, 15, 20]))), ColumnarValue::Array(Arc::new(Float64Array::from(vec![
466 10.0, 100.0, 1000.0, 10000.0,
467 ]))), ],
469 arg_fields,
470 number_rows: 4,
471 return_field: Field::new("f", DataType::Float64, true).into(),
472 config_options: Arc::new(ConfigOptions::default()),
473 };
474 let result = LogFunc::new().invoke_with_args(args);
475 assert!(result.is_err());
476 assert_eq!(
477 result.unwrap_err().to_string().lines().next().unwrap(),
478 "Arrow error: Cast error: Casting from Date32 to Float64 not supported"
479 );
480 }
481
482 #[test]
483 fn test_log_invalid_value() {
484 let arg_field = Field::new("a", DataType::Date32, false).into();
485 let args = ScalarFunctionArgs {
486 args: vec![
487 ColumnarValue::Array(Arc::new(Date32Array::from(vec![10]))), ],
489 arg_fields: vec![arg_field],
490 number_rows: 1,
491 return_field: Field::new("f", DataType::Float64, true).into(),
492 config_options: Arc::new(ConfigOptions::default()),
493 };
494
495 let result = LogFunc::new().invoke_with_args(args);
496 result.expect_err("expected error");
497 }
498
499 #[test]
500 fn test_log_scalar_f32_unary() {
501 let arg_field = Field::new("a", DataType::Float32, false).into();
502 let args = ScalarFunctionArgs {
503 args: vec![
504 ColumnarValue::Scalar(ScalarValue::Float32(Some(10.0))), ],
506 arg_fields: vec![arg_field],
507 number_rows: 1,
508 return_field: Field::new("f", DataType::Float32, true).into(),
509 config_options: Arc::new(ConfigOptions::default()),
510 };
511 let result = LogFunc::new()
512 .invoke_with_args(args)
513 .expect("failed to initialize function log");
514
515 match result {
516 ColumnarValue::Array(arr) => {
517 let floats = as_float32_array(&arr)
518 .expect("failed to convert result to a Float32Array");
519
520 assert_eq!(floats.len(), 1);
521 assert!((floats.value(0) - 1.0).abs() < 1e-10);
522 }
523 ColumnarValue::Scalar(_) => {
524 panic!("Expected an array value")
525 }
526 }
527 }
528
529 #[test]
530 fn test_log_scalar_f64_unary() {
531 let arg_field = Field::new("a", DataType::Float64, false).into();
532 let args = ScalarFunctionArgs {
533 args: vec![
534 ColumnarValue::Scalar(ScalarValue::Float64(Some(10.0))), ],
536 arg_fields: vec![arg_field],
537 number_rows: 1,
538 return_field: Field::new("f", DataType::Float64, true).into(),
539 config_options: Arc::new(ConfigOptions::default()),
540 };
541 let result = LogFunc::new()
542 .invoke_with_args(args)
543 .expect("failed to initialize function log");
544
545 match result {
546 ColumnarValue::Array(arr) => {
547 let floats = as_float64_array(&arr)
548 .expect("failed to convert result to a Float64Array");
549
550 assert_eq!(floats.len(), 1);
551 assert!((floats.value(0) - 1.0).abs() < 1e-10);
552 }
553 ColumnarValue::Scalar(_) => {
554 panic!("Expected an array value")
555 }
556 }
557 }
558
559 #[test]
560 fn test_log_scalar_f32() {
561 let arg_fields = vec![
562 Field::new("a", DataType::Float32, false).into(),
563 Field::new("a", DataType::Float32, false).into(),
564 ];
565 let args = ScalarFunctionArgs {
566 args: vec![
567 ColumnarValue::Scalar(ScalarValue::Float32(Some(2.0))), ColumnarValue::Scalar(ScalarValue::Float32(Some(32.0))), ],
570 arg_fields,
571 number_rows: 1,
572 return_field: Field::new("f", DataType::Float32, true).into(),
573 config_options: Arc::new(ConfigOptions::default()),
574 };
575 let result = LogFunc::new()
576 .invoke_with_args(args)
577 .expect("failed to initialize function log");
578
579 match result {
580 ColumnarValue::Array(arr) => {
581 let floats = as_float32_array(&arr)
582 .expect("failed to convert result to a Float32Array");
583
584 assert_eq!(floats.len(), 1);
585 assert!((floats.value(0) - 5.0).abs() < 1e-10);
586 }
587 ColumnarValue::Scalar(_) => {
588 panic!("Expected an array value")
589 }
590 }
591 }
592
593 #[test]
594 fn test_log_scalar_f64() {
595 let arg_fields = vec![
596 Field::new("a", DataType::Float64, false).into(),
597 Field::new("a", DataType::Float64, false).into(),
598 ];
599 let args = ScalarFunctionArgs {
600 args: vec![
601 ColumnarValue::Scalar(ScalarValue::Float64(Some(2.0))), ColumnarValue::Scalar(ScalarValue::Float64(Some(64.0))), ],
604 arg_fields,
605 number_rows: 1,
606 return_field: Field::new("f", DataType::Float64, true).into(),
607 config_options: Arc::new(ConfigOptions::default()),
608 };
609 let result = LogFunc::new()
610 .invoke_with_args(args)
611 .expect("failed to initialize function log");
612
613 match result {
614 ColumnarValue::Array(arr) => {
615 let floats = as_float64_array(&arr)
616 .expect("failed to convert result to a Float64Array");
617
618 assert_eq!(floats.len(), 1);
619 assert!((floats.value(0) - 6.0).abs() < 1e-10);
620 }
621 ColumnarValue::Scalar(_) => {
622 panic!("Expected an array value")
623 }
624 }
625 }
626
627 #[test]
628 fn test_log_f64_unary() {
629 let arg_field = Field::new("a", DataType::Float64, false).into();
630 let args = ScalarFunctionArgs {
631 args: vec![
632 ColumnarValue::Array(Arc::new(Float64Array::from(vec![
633 10.0, 100.0, 1000.0, 10000.0,
634 ]))), ],
636 arg_fields: vec![arg_field],
637 number_rows: 4,
638 return_field: Field::new("f", DataType::Float64, true).into(),
639 config_options: Arc::new(ConfigOptions::default()),
640 };
641 let result = LogFunc::new()
642 .invoke_with_args(args)
643 .expect("failed to initialize function log");
644
645 match result {
646 ColumnarValue::Array(arr) => {
647 let floats = as_float64_array(&arr)
648 .expect("failed to convert result to a Float64Array");
649
650 assert_eq!(floats.len(), 4);
651 assert!((floats.value(0) - 1.0).abs() < 1e-10);
652 assert!((floats.value(1) - 2.0).abs() < 1e-10);
653 assert!((floats.value(2) - 3.0).abs() < 1e-10);
654 assert!((floats.value(3) - 4.0).abs() < 1e-10);
655 }
656 ColumnarValue::Scalar(_) => {
657 panic!("Expected an array value")
658 }
659 }
660 }
661
662 #[test]
663 fn test_log_f32_unary() {
664 let arg_field = Field::new("a", DataType::Float32, false).into();
665 let args = ScalarFunctionArgs {
666 args: vec![
667 ColumnarValue::Array(Arc::new(Float32Array::from(vec![
668 10.0, 100.0, 1000.0, 10000.0,
669 ]))), ],
671 arg_fields: vec![arg_field],
672 number_rows: 4,
673 return_field: Field::new("f", DataType::Float32, true).into(),
674 config_options: Arc::new(ConfigOptions::default()),
675 };
676 let result = LogFunc::new()
677 .invoke_with_args(args)
678 .expect("failed to initialize function log");
679
680 match result {
681 ColumnarValue::Array(arr) => {
682 let floats = as_float32_array(&arr)
683 .expect("failed to convert result to a Float64Array");
684
685 assert_eq!(floats.len(), 4);
686 assert!((floats.value(0) - 1.0).abs() < 1e-10);
687 assert!((floats.value(1) - 2.0).abs() < 1e-10);
688 assert!((floats.value(2) - 3.0).abs() < 1e-10);
689 assert!((floats.value(3) - 4.0).abs() < 1e-10);
690 }
691 ColumnarValue::Scalar(_) => {
692 panic!("Expected an array value")
693 }
694 }
695 }
696
697 #[test]
698 fn test_log_f64() {
699 let arg_fields = vec![
700 Field::new("a", DataType::Float64, false).into(),
701 Field::new("a", DataType::Float64, false).into(),
702 ];
703 let args = ScalarFunctionArgs {
704 args: vec![
705 ColumnarValue::Array(Arc::new(Float64Array::from(vec![
706 2.0, 2.0, 3.0, 5.0, 5.0,
707 ]))), ColumnarValue::Array(Arc::new(Float64Array::from(vec![
709 8.0, 4.0, 81.0, 625.0, -123.0,
710 ]))), ],
712 arg_fields,
713 number_rows: 5,
714 return_field: Field::new("f", DataType::Float64, true).into(),
715 config_options: Arc::new(ConfigOptions::default()),
716 };
717 let result = LogFunc::new()
718 .invoke_with_args(args)
719 .expect("failed to initialize function log");
720
721 match result {
722 ColumnarValue::Array(arr) => {
723 let floats = as_float64_array(&arr)
724 .expect("failed to convert result to a Float64Array");
725
726 assert_eq!(floats.len(), 5);
727 assert!((floats.value(0) - 3.0).abs() < 1e-10);
728 assert!((floats.value(1) - 2.0).abs() < 1e-10);
729 assert!((floats.value(2) - 4.0).abs() < 1e-10);
730 assert!((floats.value(3) - 4.0).abs() < 1e-10);
731 assert!(floats.value(4).is_nan());
732 }
733 ColumnarValue::Scalar(_) => {
734 panic!("Expected an array value")
735 }
736 }
737 }
738
739 #[test]
740 fn test_log_f32() {
741 let arg_fields = vec![
742 Field::new("a", DataType::Float32, false).into(),
743 Field::new("a", DataType::Float32, false).into(),
744 ];
745 let args = ScalarFunctionArgs {
746 args: vec![
747 ColumnarValue::Array(Arc::new(Float32Array::from(vec![
748 2.0, 2.0, 3.0, 5.0,
749 ]))), ColumnarValue::Array(Arc::new(Float32Array::from(vec![
751 8.0, 4.0, 81.0, 625.0,
752 ]))), ],
754 arg_fields,
755 number_rows: 4,
756 return_field: Field::new("f", DataType::Float32, true).into(),
757 config_options: Arc::new(ConfigOptions::default()),
758 };
759 let result = LogFunc::new()
760 .invoke_with_args(args)
761 .expect("failed to initialize function log");
762
763 match result {
764 ColumnarValue::Array(arr) => {
765 let floats = as_float32_array(&arr)
766 .expect("failed to convert result to a Float32Array");
767
768 assert_eq!(floats.len(), 4);
769 assert!((floats.value(0) - 3.0).abs() < f32::EPSILON);
770 assert!((floats.value(1) - 2.0).abs() < f32::EPSILON);
771 assert!((floats.value(2) - 4.0).abs() < f32::EPSILON);
772 assert!((floats.value(3) - 4.0).abs() < f32::EPSILON);
773 }
774 ColumnarValue::Scalar(_) => {
775 panic!("Expected an array value")
776 }
777 }
778 }
779 #[test]
780 fn test_log_simplify_errors() {
782 let context = SimplifyContext::default();
783 let _ = LogFunc::new().simplify(vec![], &context).unwrap_err();
785 let _ = LogFunc::new()
787 .simplify(vec![lit(1), lit(2), lit(3)], &context)
788 .unwrap_err();
789 }
790
791 #[test]
792 fn test_log_simplify_original() {
794 let context = SimplifyContext::default();
795 let result = LogFunc::new().simplify(vec![lit(2)], &context).unwrap();
797 let ExprSimplifyResult::Original(args) = result else {
798 panic!("Expected ExprSimplifyResult::Original")
799 };
800 assert_eq!(args.len(), 1);
801 assert_eq!(args[0], lit(2));
802 let result = LogFunc::new()
804 .simplify(vec![lit(2), lit(3)], &context)
805 .unwrap();
806 let ExprSimplifyResult::Original(args) = result else {
807 panic!("Expected ExprSimplifyResult::Original")
808 };
809 assert_eq!(args.len(), 2);
810 assert_eq!(args[0], lit(2));
811 assert_eq!(args[1], lit(3));
812 }
813
814 #[test]
815 fn test_log_output_ordering() {
816 let orders = [
818 ExprProperties::new_unknown(),
819 ExprProperties::new_unknown().with_order(SortProperties::Ordered(
820 SortOptions {
821 descending: false,
822 nulls_first: true,
823 },
824 )),
825 ExprProperties::new_unknown().with_order(SortProperties::Ordered(
826 SortOptions {
827 descending: true,
828 nulls_first: true,
829 },
830 )),
831 ExprProperties::new_unknown().with_order(SortProperties::Singleton),
832 ];
833
834 let log = LogFunc::new();
835
836 for order in orders.iter().cloned() {
838 let result = log.output_ordering(std::slice::from_ref(&order)).unwrap();
839 assert_eq!(result, order.sort_properties);
840 }
841
842 let mut results = Vec::with_capacity(orders.len() * orders.len());
844 for base_order in orders.iter() {
845 for num_order in orders.iter().cloned() {
846 let result = log
847 .output_ordering(&[base_order.clone(), num_order])
848 .unwrap();
849 results.push(result);
850 }
851 }
852 let expected = [
853 SortProperties::Unordered,
855 SortProperties::Unordered,
856 SortProperties::Unordered,
857 SortProperties::Unordered,
858 SortProperties::Unordered,
860 SortProperties::Unordered,
862 SortProperties::Ordered(SortOptions {
864 descending: true,
865 nulls_first: true,
866 }),
867 SortProperties::Ordered(SortOptions {
869 descending: true,
870 nulls_first: true,
871 }),
872 SortProperties::Unordered,
874 SortProperties::Ordered(SortOptions {
876 descending: false,
877 nulls_first: true,
878 }),
879 SortProperties::Unordered,
881 SortProperties::Ordered(SortOptions {
883 descending: false,
884 nulls_first: true,
885 }),
886 SortProperties::Unordered,
888 SortProperties::Ordered(SortOptions {
890 descending: false,
891 nulls_first: true,
892 }),
893 SortProperties::Ordered(SortOptions {
895 descending: true,
896 nulls_first: true,
897 }),
898 SortProperties::Singleton,
900 ];
901 assert_eq!(results, expected);
902
903 let base_order = ExprProperties::new_unknown().with_order(
905 SortProperties::Ordered(SortOptions {
906 descending: true,
907 nulls_first: true,
908 }),
909 );
910 let num_order = ExprProperties::new_unknown().with_order(
911 SortProperties::Ordered(SortOptions {
912 descending: false,
913 nulls_first: false,
914 }),
915 );
916 assert_eq!(
917 log.output_ordering(&[base_order, num_order]).unwrap(),
918 SortProperties::Unordered
919 );
920 }
921
922 #[test]
923 fn test_log_scalar_decimal128_unary() {
924 let arg_field = Field::new("a", DataType::Decimal128(38, 0), false).into();
925 let args = ScalarFunctionArgs {
926 args: vec![
927 ColumnarValue::Scalar(ScalarValue::Decimal128(Some(10), 38, 0)), ],
929 arg_fields: vec![arg_field],
930 number_rows: 1,
931 return_field: Field::new("f", DataType::Decimal128(38, 0), true).into(),
932 config_options: Arc::new(ConfigOptions::default()),
933 };
934 let result = LogFunc::new()
935 .invoke_with_args(args)
936 .expect("failed to initialize function log");
937
938 match result {
939 ColumnarValue::Array(arr) => {
940 let floats = as_float64_array(&arr)
941 .expect("failed to convert result to a Decimal128Array");
942 assert_eq!(floats.len(), 1);
943 assert!((floats.value(0) - 1.0).abs() < 1e-10);
944 }
945 ColumnarValue::Scalar(_) => {
946 panic!("Expected an array value")
947 }
948 }
949 }
950
951 #[test]
952 fn test_log_scalar_decimal128() {
953 let arg_fields = vec![
954 Field::new("b", DataType::Float64, false).into(),
955 Field::new("x", DataType::Decimal128(38, 0), false).into(),
956 ];
957 let args = ScalarFunctionArgs {
958 args: vec![
959 ColumnarValue::Scalar(ScalarValue::Float64(Some(2.0))), ColumnarValue::Scalar(ScalarValue::Decimal128(Some(64), 38, 0)), ],
962 arg_fields,
963 number_rows: 1,
964 return_field: Field::new("f", DataType::Float64, true).into(),
965 config_options: Arc::new(ConfigOptions::default()),
966 };
967 let result = LogFunc::new()
968 .invoke_with_args(args)
969 .expect("failed to initialize function log");
970
971 match result {
972 ColumnarValue::Array(arr) => {
973 let floats = as_float64_array(&arr)
974 .expect("failed to convert result to a Float64Array");
975
976 assert_eq!(floats.len(), 1);
977 assert!((floats.value(0) - 6.0).abs() < 1e-10);
978 }
979 ColumnarValue::Scalar(_) => {
980 panic!("Expected an array value")
981 }
982 }
983 }
984
985 #[test]
986 fn test_log_decimal128_unary() {
987 let arg_field = Field::new("a", DataType::Decimal128(38, 0), false).into();
988 let args = ScalarFunctionArgs {
989 args: vec![
990 ColumnarValue::Array(Arc::new(
991 Decimal128Array::from(vec![10, 100, 1000, 10000, 12600, -123])
992 .with_precision_and_scale(38, 0)
993 .unwrap(),
994 )), ],
996 arg_fields: vec![arg_field],
997 number_rows: 6,
998 return_field: Field::new("f", DataType::Float64, true).into(),
999 config_options: Arc::new(ConfigOptions::default()),
1000 };
1001 let result = LogFunc::new()
1002 .invoke_with_args(args)
1003 .expect("failed to initialize function log");
1004
1005 match result {
1006 ColumnarValue::Array(arr) => {
1007 let floats = as_float64_array(&arr)
1008 .expect("failed to convert result to a Float64Array");
1009
1010 assert_eq!(floats.len(), 6);
1011 assert!((floats.value(0) - 1.0).abs() < 1e-10);
1012 assert!((floats.value(1) - 2.0).abs() < 1e-10);
1013 assert!((floats.value(2) - 3.0).abs() < 1e-10);
1014 assert!((floats.value(3) - 4.0).abs() < 1e-10);
1015 assert!((floats.value(4) - 4.0).abs() < 1e-10); assert!(floats.value(5).is_nan());
1017 }
1018 ColumnarValue::Scalar(_) => {
1019 panic!("Expected an array value")
1020 }
1021 }
1022 }
1023
1024 #[test]
1025 fn test_log_decimal128_base_decimal() {
1026 for base in [
1028 ScalarValue::Decimal128(Some(i128::from(2)), 38, 0),
1029 ScalarValue::Decimal128(Some(i128::from(2000)), 38, 3),
1030 ] {
1031 let arg_fields = vec![
1032 Field::new("b", DataType::Decimal128(38, 0), false).into(),
1033 Field::new("x", DataType::Decimal128(38, 0), false).into(),
1034 ];
1035 let args = ScalarFunctionArgs {
1036 args: vec![
1037 ColumnarValue::Scalar(base), ColumnarValue::Scalar(ScalarValue::Decimal128(Some(64), 38, 0)), ],
1040 arg_fields,
1041 number_rows: 1,
1042 return_field: Field::new("f", DataType::Float64, true).into(),
1043 config_options: Arc::new(ConfigOptions::default()),
1044 };
1045 let result = LogFunc::new()
1046 .invoke_with_args(args)
1047 .expect("failed to initialize function log");
1048
1049 match result {
1050 ColumnarValue::Array(arr) => {
1051 let floats = as_float64_array(&arr)
1052 .expect("failed to convert result to a Float64Array");
1053
1054 assert_eq!(floats.len(), 1);
1055 assert!((floats.value(0) - 6.0).abs() < 1e-10);
1056 }
1057 ColumnarValue::Scalar(_) => {
1058 panic!("Expected an array value")
1059 }
1060 }
1061 }
1062 }
1063
1064 #[test]
1065 fn test_log_decimal128_value_scale() {
1066 for value in [
1068 ScalarValue::Decimal128(Some(i128::from(1000)), 38, 0),
1069 ScalarValue::Decimal128(Some(i128::from(10000)), 38, 1),
1070 ScalarValue::Decimal128(Some(i128::from(1000000)), 38, 3),
1071 ] {
1072 let arg_fields = vec![
1073 Field::new("b", DataType::Decimal128(38, 0), false).into(),
1074 Field::new("x", DataType::Decimal128(38, 0), false).into(),
1075 ];
1076 let args = ScalarFunctionArgs {
1077 args: vec![
1078 ColumnarValue::Scalar(value), ],
1080 arg_fields,
1081 number_rows: 1,
1082 return_field: Field::new("f", DataType::Float64, true).into(),
1083 config_options: Arc::new(ConfigOptions::default()),
1084 };
1085 let result = LogFunc::new()
1086 .invoke_with_args(args)
1087 .expect("failed to initialize function log");
1088
1089 match result {
1090 ColumnarValue::Array(arr) => {
1091 let floats = as_float64_array(&arr)
1092 .expect("failed to convert result to a Float64Array");
1093
1094 assert_eq!(floats.len(), 1);
1095 assert!((floats.value(0) - 3.0).abs() < 1e-10);
1096 }
1097 ColumnarValue::Scalar(_) => {
1098 panic!("Expected an array value")
1099 }
1100 }
1101 }
1102 }
1103
1104 #[test]
1105 fn test_log_decimal256_unary() {
1106 let arg_field = Field::new(
1107 "a",
1108 DataType::Decimal256(DECIMAL256_MAX_PRECISION, 0),
1109 false,
1110 )
1111 .into();
1112 let args = ScalarFunctionArgs {
1113 args: vec![
1114 ColumnarValue::Array(Arc::new(
1115 Decimal256Array::from(vec![
1116 Some(i256::from(10)),
1117 Some(i256::from(100)),
1118 Some(i256::from(1000)),
1119 Some(i256::from(10000)),
1120 Some(i256::from(12600)),
1121 Some(i256::from_i128(i128::MAX) - i256::from(1000)),
1123 Some(i256::from(-123)),
1125 ])
1126 .with_precision_and_scale(DECIMAL256_MAX_PRECISION, 0)
1127 .unwrap(),
1128 )), ],
1130 arg_fields: vec![arg_field],
1131 number_rows: 7,
1132 return_field: Field::new("f", DataType::Float64, true).into(),
1133 config_options: Arc::new(ConfigOptions::default()),
1134 };
1135 let result = LogFunc::new()
1136 .invoke_with_args(args)
1137 .expect("failed to initialize function log");
1138
1139 match result {
1140 ColumnarValue::Array(arr) => {
1141 let floats = as_float64_array(&arr)
1142 .expect("failed to convert result to a Float64Array");
1143
1144 assert_eq!(floats.len(), 7);
1145 eprintln!("floats {:?}", &floats);
1146 assert!((floats.value(0) - 1.0).abs() < 1e-10);
1147 assert!((floats.value(1) - 2.0).abs() < 1e-10);
1148 assert!((floats.value(2) - 3.0).abs() < 1e-10);
1149 assert!((floats.value(3) - 4.0).abs() < 1e-10);
1150 assert!((floats.value(4) - 4.0).abs() < 1e-10); assert!((floats.value(5) - 38.0).abs() < 1e-10);
1152 assert!(floats.value(6).is_nan());
1153 }
1154 ColumnarValue::Scalar(_) => {
1155 panic!("Expected an array value")
1156 }
1157 }
1158 }
1159
1160 #[test]
1161 fn test_log_decimal128_invalid_base() {
1162 let arg_fields = vec![
1164 Field::new("b", DataType::Float64, false).into(),
1165 Field::new("x", DataType::Decimal128(38, 0), false).into(),
1166 ];
1167 let args = ScalarFunctionArgs {
1168 args: vec![
1169 ColumnarValue::Scalar(ScalarValue::Float64(Some(-2.0))), ColumnarValue::Scalar(ScalarValue::Decimal128(Some(64), 38, 0)), ],
1172 arg_fields,
1173 number_rows: 1,
1174 return_field: Field::new("f", DataType::Float64, true).into(),
1175 config_options: Arc::new(ConfigOptions::default()),
1176 };
1177 let result = LogFunc::new()
1178 .invoke_with_args(args)
1179 .expect("should not error on invalid base");
1180
1181 match result {
1182 ColumnarValue::Array(arr) => {
1183 let floats = as_float64_array(&arr)
1184 .expect("failed to convert result to a Float64Array");
1185 assert_eq!(floats.len(), 1);
1186 assert!(floats.value(0).is_nan());
1187 }
1188 ColumnarValue::Scalar(_) => {
1189 panic!("Expected an array value")
1190 }
1191 }
1192 }
1193
1194 #[test]
1195 fn test_log_decimal256_large() {
1196 let arg_field = Field::new("a", DataType::Decimal256(38, 0), false).into();
1198 let args = ScalarFunctionArgs {
1199 args: vec![
1200 ColumnarValue::Array(Arc::new(Decimal256Array::from(vec![
1201 Some(i256::from_i128(i128::MAX) + i256::from(1000)),
1203 ]))), ],
1205 arg_fields: vec![arg_field],
1206 number_rows: 1,
1207 return_field: Field::new("f", DataType::Float64, true).into(),
1208 config_options: Arc::new(ConfigOptions::default()),
1209 };
1210 let result = LogFunc::new()
1211 .invoke_with_args(args)
1212 .expect("should handle large Decimal256 via f64 fallback");
1213
1214 match result {
1215 ColumnarValue::Array(arr) => {
1216 let floats = as_float64_array(&arr)
1217 .expect("failed to convert result to a Float64Array");
1218 assert_eq!(floats.len(), 1);
1219 let log_result = floats.value(0);
1222 assert!(
1223 log_result.is_finite() && log_result > 0.0,
1224 "Expected positive finite log result, got {log_result}"
1225 );
1226 }
1227 ColumnarValue::Scalar(_) => {
1228 panic!("Expected an array value")
1229 }
1230 }
1231 }
1232}