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