datafusion_functions/math/
log.rs

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