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 is_strict(&self) -> bool {
207 true
208 }
209
210 fn output_ordering(&self, input: &[ExprProperties]) -> Result<SortProperties> {
211 let (base_sort_properties, num_sort_properties) = if input.len() == 1 {
212 (SortProperties::Singleton, input[0].sort_properties)
214 } else {
215 (input[0].sort_properties, input[1].sort_properties)
216 };
217 match (num_sort_properties, base_sort_properties) {
218 (first @ SortProperties::Ordered(num), SortProperties::Ordered(base))
219 if num.descending != base.descending
220 && num.nulls_first == base.nulls_first =>
221 {
222 Ok(first)
223 }
224 (
225 first @ (SortProperties::Ordered(_) | SortProperties::Singleton),
226 SortProperties::Singleton,
227 ) => Ok(first),
228 (SortProperties::Singleton, second @ SortProperties::Ordered(_)) => {
229 Ok(-second)
230 }
231 _ => Ok(SortProperties::Unordered),
232 }
233 }
234
235 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
237 if args.arg_fields.iter().any(|a| a.data_type().is_null()) {
238 return ColumnarValue::Scalar(ScalarValue::Null)
239 .cast_to(args.return_type(), None);
240 }
241
242 let (base, value) = if args.args.len() == 2 {
243 (args.args[0].clone(), &args.args[1])
244 } else {
245 (
247 ColumnarValue::Scalar(ScalarValue::new_ten(args.return_type())?),
248 &args.args[0],
249 )
250 };
251 let value = value.to_array(args.number_rows)?;
252
253 let output: ArrayRef = match value.data_type() {
254 DataType::Float16 => {
255 calculate_binary_math::<Float16Type, Float16Type, Float16Type, _>(
256 &value,
257 &base,
258 |value, base| Ok(value.log(base)),
259 )?
260 }
261 DataType::Float32 => {
262 calculate_binary_math::<Float32Type, Float32Type, Float32Type, _>(
263 &value,
264 &base,
265 |value, base| Ok(value.log(base)),
266 )?
267 }
268 DataType::Float64 => {
269 calculate_binary_math::<Float64Type, Float64Type, Float64Type, _>(
270 &value,
271 &base,
272 |value, base| Ok(value.log(base)),
273 )?
274 }
275 DataType::Decimal32(_, scale) => {
276 calculate_binary_math::<Decimal32Type, Float64Type, Float64Type, _>(
277 &value,
278 &base,
279 |value, base| log_decimal32(value, *scale, base),
280 )?
281 }
282 DataType::Decimal64(_, scale) => {
283 calculate_binary_math::<Decimal64Type, Float64Type, Float64Type, _>(
284 &value,
285 &base,
286 |value, base| log_decimal64(value, *scale, base),
287 )?
288 }
289 DataType::Decimal128(_, scale) => {
290 calculate_binary_math::<Decimal128Type, Float64Type, Float64Type, _>(
291 &value,
292 &base,
293 |value, base| log_decimal128(value, *scale, base),
294 )?
295 }
296 DataType::Decimal256(_, scale) => {
297 calculate_binary_math::<Decimal256Type, Float64Type, Float64Type, _>(
298 &value,
299 &base,
300 |value, base| log_decimal256(value, *scale, base),
301 )?
302 }
303 other => {
304 return exec_err!("Unsupported data type {other:?} for function log");
305 }
306 };
307
308 Ok(ColumnarValue::Array(output))
309 }
310
311 fn documentation(&self) -> Option<&Documentation> {
312 self.doc()
313 }
314
315 fn simplify(
320 &self,
321 mut args: Vec<Expr>,
322 info: &SimplifyContext,
323 ) -> Result<ExprSimplifyResult> {
324 let mut arg_types = args
325 .iter()
326 .map(|arg| info.get_data_type(arg))
327 .collect::<Result<Vec<_>>>()?;
328 let return_type = self.return_type(&arg_types)?;
329
330 if arg_types.iter().any(|dt| dt.is_null()) {
332 return Ok(ExprSimplifyResult::Simplified(lit(
333 ScalarValue::Null.cast_to(&return_type)?
334 )));
335 }
336
337 let num_args = args.len();
341 if num_args != 1 && num_args != 2 {
342 return plan_err!("Expected log to have 1 or 2 arguments, got {num_args}");
343 }
344
345 match arg_types.last().unwrap() {
346 DataType::Decimal32(_, scale)
347 | DataType::Decimal64(_, scale)
348 | DataType::Decimal128(_, scale)
349 | DataType::Decimal256(_, scale)
350 if *scale < 0 =>
351 {
352 return Ok(ExprSimplifyResult::Original(args));
353 }
354 _ => (),
355 };
356
357 let number = args.pop().unwrap();
358 let number_datatype = arg_types.pop().unwrap();
359 let base = if let Some(base) = args.pop() {
361 base
362 } else {
363 lit(ScalarValue::new_ten(&number_datatype)?)
364 };
365 let base_nullable = info.nullable(&base)?;
366
367 match number {
368 Expr::Literal(value, _)
369 if value == ScalarValue::new_one(&number_datatype)? && !base_nullable =>
370 {
371 Ok(ExprSimplifyResult::Simplified(lit(ScalarValue::new_zero(
372 &info.get_data_type(&base)?,
373 )?)))
374 }
375 Expr::ScalarFunction(ScalarFunction { func, mut args })
376 if is_pow(&func)
377 && args.len() == 2
378 && base == args[0]
379 && !base_nullable =>
380 {
381 let b = args.pop().unwrap(); Ok(ExprSimplifyResult::Simplified(b))
383 }
384 number => {
385 if number == base && !base_nullable {
386 Ok(ExprSimplifyResult::Simplified(lit(ScalarValue::new_one(
387 &number_datatype,
388 )?)))
389 } else {
390 let args = match num_args {
391 1 => vec![number],
392 2 => vec![base, number],
393 _ => {
394 return internal_err!(
395 "Unexpected number of arguments in log::simplify"
396 );
397 }
398 };
399 Ok(ExprSimplifyResult::Original(args))
400 }
401 }
402 }
403 }
404}
405
406fn is_pow(func: &ScalarUDF) -> bool {
408 func.inner().is::<PowerFunc>()
409}
410
411#[cfg(test)]
412mod tests {
413 use std::sync::Arc;
414
415 use super::*;
416
417 use arrow::array::{
418 Date32Array, Decimal128Array, Decimal256Array, Float32Array, Float64Array,
419 };
420 use arrow::compute::SortOptions;
421 use arrow::datatypes::{DECIMAL256_MAX_PRECISION, Field};
422 use datafusion_common::cast::{as_float32_array, as_float64_array};
423 use datafusion_common::config::ConfigOptions;
424
425 #[test]
426 fn test_log_decimal_native() {
427 let value = 10_i128.pow(35);
428 let expected = (value as f64).log2();
429 let actual = log_decimal128(value, 0, 2.0).unwrap();
430 assert!((actual - expected).abs() < 1e-10);
431 }
432
433 #[test]
434 fn test_log_invalid_base_type() {
435 let arg_fields = vec![
436 Field::new("b", DataType::Date32, false).into(),
437 Field::new("n", DataType::Float64, false).into(),
438 ];
439 let args = ScalarFunctionArgs {
440 args: vec![
441 ColumnarValue::Array(Arc::new(Date32Array::from(vec![5, 10, 15, 20]))), ColumnarValue::Array(Arc::new(Float64Array::from(vec![
443 10.0, 100.0, 1000.0, 10000.0,
444 ]))), ],
446 arg_fields,
447 number_rows: 4,
448 return_field: Field::new("f", DataType::Float64, true).into(),
449 config_options: Arc::new(ConfigOptions::default()),
450 };
451 let result = LogFunc::new().invoke_with_args(args);
452 assert!(result.is_err());
453 assert_eq!(
454 result.unwrap_err().to_string().lines().next().unwrap(),
455 "Arrow error: Cast error: Casting from Date32 to Float64 not supported"
456 );
457 }
458
459 #[test]
460 fn test_log_invalid_value() {
461 let arg_field = Field::new("a", DataType::Date32, false).into();
462 let args = ScalarFunctionArgs {
463 args: vec![
464 ColumnarValue::Array(Arc::new(Date32Array::from(vec![10]))), ],
466 arg_fields: vec![arg_field],
467 number_rows: 1,
468 return_field: Field::new("f", DataType::Float64, true).into(),
469 config_options: Arc::new(ConfigOptions::default()),
470 };
471
472 let result = LogFunc::new().invoke_with_args(args);
473 result.expect_err("expected error");
474 }
475
476 #[test]
477 fn test_log_scalar_f32_unary() {
478 let arg_field = Field::new("a", DataType::Float32, false).into();
479 let args = ScalarFunctionArgs {
480 args: vec![
481 ColumnarValue::Scalar(ScalarValue::Float32(Some(10.0))), ],
483 arg_fields: vec![arg_field],
484 number_rows: 1,
485 return_field: Field::new("f", DataType::Float32, true).into(),
486 config_options: Arc::new(ConfigOptions::default()),
487 };
488 let result = LogFunc::new()
489 .invoke_with_args(args)
490 .expect("failed to initialize function log");
491
492 match result {
493 ColumnarValue::Array(arr) => {
494 let floats = as_float32_array(&arr)
495 .expect("failed to convert result to a Float32Array");
496
497 assert_eq!(floats.len(), 1);
498 assert!((floats.value(0) - 1.0).abs() < 1e-10);
499 }
500 ColumnarValue::Scalar(_) => {
501 panic!("Expected an array value")
502 }
503 }
504 }
505
506 #[test]
507 fn test_log_scalar_f64_unary() {
508 let arg_field = Field::new("a", DataType::Float64, false).into();
509 let args = ScalarFunctionArgs {
510 args: vec![
511 ColumnarValue::Scalar(ScalarValue::Float64(Some(10.0))), ],
513 arg_fields: vec![arg_field],
514 number_rows: 1,
515 return_field: Field::new("f", DataType::Float64, true).into(),
516 config_options: Arc::new(ConfigOptions::default()),
517 };
518 let result = LogFunc::new()
519 .invoke_with_args(args)
520 .expect("failed to initialize function log");
521
522 match result {
523 ColumnarValue::Array(arr) => {
524 let floats = as_float64_array(&arr)
525 .expect("failed to convert result to a Float64Array");
526
527 assert_eq!(floats.len(), 1);
528 assert!((floats.value(0) - 1.0).abs() < 1e-10);
529 }
530 ColumnarValue::Scalar(_) => {
531 panic!("Expected an array value")
532 }
533 }
534 }
535
536 #[test]
537 fn test_log_scalar_f32() {
538 let arg_fields = vec![
539 Field::new("a", DataType::Float32, false).into(),
540 Field::new("a", DataType::Float32, false).into(),
541 ];
542 let args = ScalarFunctionArgs {
543 args: vec![
544 ColumnarValue::Scalar(ScalarValue::Float32(Some(2.0))), ColumnarValue::Scalar(ScalarValue::Float32(Some(32.0))), ],
547 arg_fields,
548 number_rows: 1,
549 return_field: Field::new("f", DataType::Float32, true).into(),
550 config_options: Arc::new(ConfigOptions::default()),
551 };
552 let result = LogFunc::new()
553 .invoke_with_args(args)
554 .expect("failed to initialize function log");
555
556 match result {
557 ColumnarValue::Array(arr) => {
558 let floats = as_float32_array(&arr)
559 .expect("failed to convert result to a Float32Array");
560
561 assert_eq!(floats.len(), 1);
562 assert!((floats.value(0) - 5.0).abs() < 1e-10);
563 }
564 ColumnarValue::Scalar(_) => {
565 panic!("Expected an array value")
566 }
567 }
568 }
569
570 #[test]
571 fn test_log_scalar_f64() {
572 let arg_fields = vec![
573 Field::new("a", DataType::Float64, false).into(),
574 Field::new("a", DataType::Float64, false).into(),
575 ];
576 let args = ScalarFunctionArgs {
577 args: vec![
578 ColumnarValue::Scalar(ScalarValue::Float64(Some(2.0))), ColumnarValue::Scalar(ScalarValue::Float64(Some(64.0))), ],
581 arg_fields,
582 number_rows: 1,
583 return_field: Field::new("f", DataType::Float64, true).into(),
584 config_options: Arc::new(ConfigOptions::default()),
585 };
586 let result = LogFunc::new()
587 .invoke_with_args(args)
588 .expect("failed to initialize function log");
589
590 match result {
591 ColumnarValue::Array(arr) => {
592 let floats = as_float64_array(&arr)
593 .expect("failed to convert result to a Float64Array");
594
595 assert_eq!(floats.len(), 1);
596 assert!((floats.value(0) - 6.0).abs() < 1e-10);
597 }
598 ColumnarValue::Scalar(_) => {
599 panic!("Expected an array value")
600 }
601 }
602 }
603
604 #[test]
605 fn test_log_f64_unary() {
606 let arg_field = Field::new("a", DataType::Float64, false).into();
607 let args = ScalarFunctionArgs {
608 args: vec![
609 ColumnarValue::Array(Arc::new(Float64Array::from(vec![
610 10.0, 100.0, 1000.0, 10000.0,
611 ]))), ],
613 arg_fields: vec![arg_field],
614 number_rows: 4,
615 return_field: Field::new("f", DataType::Float64, true).into(),
616 config_options: Arc::new(ConfigOptions::default()),
617 };
618 let result = LogFunc::new()
619 .invoke_with_args(args)
620 .expect("failed to initialize function log");
621
622 match result {
623 ColumnarValue::Array(arr) => {
624 let floats = as_float64_array(&arr)
625 .expect("failed to convert result to a Float64Array");
626
627 assert_eq!(floats.len(), 4);
628 assert!((floats.value(0) - 1.0).abs() < 1e-10);
629 assert!((floats.value(1) - 2.0).abs() < 1e-10);
630 assert!((floats.value(2) - 3.0).abs() < 1e-10);
631 assert!((floats.value(3) - 4.0).abs() < 1e-10);
632 }
633 ColumnarValue::Scalar(_) => {
634 panic!("Expected an array value")
635 }
636 }
637 }
638
639 #[test]
640 fn test_log_f32_unary() {
641 let arg_field = Field::new("a", DataType::Float32, false).into();
642 let args = ScalarFunctionArgs {
643 args: vec![
644 ColumnarValue::Array(Arc::new(Float32Array::from(vec![
645 10.0, 100.0, 1000.0, 10000.0,
646 ]))), ],
648 arg_fields: vec![arg_field],
649 number_rows: 4,
650 return_field: Field::new("f", DataType::Float32, true).into(),
651 config_options: Arc::new(ConfigOptions::default()),
652 };
653 let result = LogFunc::new()
654 .invoke_with_args(args)
655 .expect("failed to initialize function log");
656
657 match result {
658 ColumnarValue::Array(arr) => {
659 let floats = as_float32_array(&arr)
660 .expect("failed to convert result to a Float64Array");
661
662 assert_eq!(floats.len(), 4);
663 assert!((floats.value(0) - 1.0).abs() < 1e-10);
664 assert!((floats.value(1) - 2.0).abs() < 1e-10);
665 assert!((floats.value(2) - 3.0).abs() < 1e-10);
666 assert!((floats.value(3) - 4.0).abs() < 1e-10);
667 }
668 ColumnarValue::Scalar(_) => {
669 panic!("Expected an array value")
670 }
671 }
672 }
673
674 #[test]
675 fn test_log_f64() {
676 let arg_fields = vec![
677 Field::new("a", DataType::Float64, false).into(),
678 Field::new("a", DataType::Float64, false).into(),
679 ];
680 let args = ScalarFunctionArgs {
681 args: vec![
682 ColumnarValue::Array(Arc::new(Float64Array::from(vec![
683 2.0, 2.0, 3.0, 5.0, 5.0,
684 ]))), ColumnarValue::Array(Arc::new(Float64Array::from(vec![
686 8.0, 4.0, 81.0, 625.0, -123.0,
687 ]))), ],
689 arg_fields,
690 number_rows: 5,
691 return_field: Field::new("f", DataType::Float64, true).into(),
692 config_options: Arc::new(ConfigOptions::default()),
693 };
694 let result = LogFunc::new()
695 .invoke_with_args(args)
696 .expect("failed to initialize function log");
697
698 match result {
699 ColumnarValue::Array(arr) => {
700 let floats = as_float64_array(&arr)
701 .expect("failed to convert result to a Float64Array");
702
703 assert_eq!(floats.len(), 5);
704 assert!((floats.value(0) - 3.0).abs() < 1e-10);
705 assert!((floats.value(1) - 2.0).abs() < 1e-10);
706 assert!((floats.value(2) - 4.0).abs() < 1e-10);
707 assert!((floats.value(3) - 4.0).abs() < 1e-10);
708 assert!(floats.value(4).is_nan());
709 }
710 ColumnarValue::Scalar(_) => {
711 panic!("Expected an array value")
712 }
713 }
714 }
715
716 #[test]
717 fn test_log_f32() {
718 let arg_fields = vec![
719 Field::new("a", DataType::Float32, false).into(),
720 Field::new("a", DataType::Float32, false).into(),
721 ];
722 let args = ScalarFunctionArgs {
723 args: vec![
724 ColumnarValue::Array(Arc::new(Float32Array::from(vec![
725 2.0, 2.0, 3.0, 5.0,
726 ]))), ColumnarValue::Array(Arc::new(Float32Array::from(vec![
728 8.0, 4.0, 81.0, 625.0,
729 ]))), ],
731 arg_fields,
732 number_rows: 4,
733 return_field: Field::new("f", DataType::Float32, true).into(),
734 config_options: Arc::new(ConfigOptions::default()),
735 };
736 let result = LogFunc::new()
737 .invoke_with_args(args)
738 .expect("failed to initialize function log");
739
740 match result {
741 ColumnarValue::Array(arr) => {
742 let floats = as_float32_array(&arr)
743 .expect("failed to convert result to a Float32Array");
744
745 assert_eq!(floats.len(), 4);
746 assert!((floats.value(0) - 3.0).abs() < f32::EPSILON);
747 assert!((floats.value(1) - 2.0).abs() < f32::EPSILON);
748 assert!((floats.value(2) - 4.0).abs() < f32::EPSILON);
749 assert!((floats.value(3) - 4.0).abs() < f32::EPSILON);
750 }
751 ColumnarValue::Scalar(_) => {
752 panic!("Expected an array value")
753 }
754 }
755 }
756 #[test]
757 fn test_log_simplify_errors() {
759 let context = SimplifyContext::default();
760 let _ = LogFunc::new().simplify(vec![], &context).unwrap_err();
762 let _ = LogFunc::new()
764 .simplify(vec![lit(1), lit(2), lit(3)], &context)
765 .unwrap_err();
766 }
767
768 #[test]
769 fn test_log_simplify_original() {
771 let context = SimplifyContext::default();
772 let result = LogFunc::new().simplify(vec![lit(2)], &context).unwrap();
774 let ExprSimplifyResult::Original(args) = result else {
775 panic!("Expected ExprSimplifyResult::Original")
776 };
777 assert_eq!(args.len(), 1);
778 assert_eq!(args[0], lit(2));
779 let result = LogFunc::new()
781 .simplify(vec![lit(2), lit(3)], &context)
782 .unwrap();
783 let ExprSimplifyResult::Original(args) = result else {
784 panic!("Expected ExprSimplifyResult::Original")
785 };
786 assert_eq!(args.len(), 2);
787 assert_eq!(args[0], lit(2));
788 assert_eq!(args[1], lit(3));
789 }
790
791 #[test]
792 fn test_log_output_ordering() {
793 let orders = [
795 ExprProperties::new_unknown(),
796 ExprProperties::new_unknown().with_order(SortProperties::Ordered(
797 SortOptions {
798 descending: false,
799 nulls_first: true,
800 },
801 )),
802 ExprProperties::new_unknown().with_order(SortProperties::Ordered(
803 SortOptions {
804 descending: true,
805 nulls_first: true,
806 },
807 )),
808 ExprProperties::new_unknown().with_order(SortProperties::Singleton),
809 ];
810
811 let log = LogFunc::new();
812
813 for order in orders.iter().cloned() {
815 let result = log.output_ordering(std::slice::from_ref(&order)).unwrap();
816 assert_eq!(result, order.sort_properties);
817 }
818
819 let mut results = Vec::with_capacity(orders.len() * orders.len());
821 for base_order in orders.iter() {
822 for num_order in orders.iter().cloned() {
823 let result = log
824 .output_ordering(&[base_order.clone(), num_order])
825 .unwrap();
826 results.push(result);
827 }
828 }
829 let expected = [
830 SortProperties::Unordered,
832 SortProperties::Unordered,
833 SortProperties::Unordered,
834 SortProperties::Unordered,
835 SortProperties::Unordered,
837 SortProperties::Unordered,
839 SortProperties::Ordered(SortOptions {
841 descending: true,
842 nulls_first: true,
843 }),
844 SortProperties::Ordered(SortOptions {
846 descending: true,
847 nulls_first: true,
848 }),
849 SortProperties::Unordered,
851 SortProperties::Ordered(SortOptions {
853 descending: false,
854 nulls_first: true,
855 }),
856 SortProperties::Unordered,
858 SortProperties::Ordered(SortOptions {
860 descending: false,
861 nulls_first: true,
862 }),
863 SortProperties::Unordered,
865 SortProperties::Ordered(SortOptions {
867 descending: false,
868 nulls_first: true,
869 }),
870 SortProperties::Ordered(SortOptions {
872 descending: true,
873 nulls_first: true,
874 }),
875 SortProperties::Singleton,
877 ];
878 assert_eq!(results, expected);
879
880 let base_order = ExprProperties::new_unknown().with_order(
882 SortProperties::Ordered(SortOptions {
883 descending: true,
884 nulls_first: true,
885 }),
886 );
887 let num_order = ExprProperties::new_unknown().with_order(
888 SortProperties::Ordered(SortOptions {
889 descending: false,
890 nulls_first: false,
891 }),
892 );
893 assert_eq!(
894 log.output_ordering(&[base_order, num_order]).unwrap(),
895 SortProperties::Unordered
896 );
897 }
898
899 #[test]
900 fn test_log_scalar_decimal128_unary() {
901 let arg_field = Field::new("a", DataType::Decimal128(38, 0), false).into();
902 let args = ScalarFunctionArgs {
903 args: vec![
904 ColumnarValue::Scalar(ScalarValue::Decimal128(Some(10), 38, 0)), ],
906 arg_fields: vec![arg_field],
907 number_rows: 1,
908 return_field: Field::new("f", DataType::Decimal128(38, 0), true).into(),
909 config_options: Arc::new(ConfigOptions::default()),
910 };
911 let result = LogFunc::new()
912 .invoke_with_args(args)
913 .expect("failed to initialize function log");
914
915 match result {
916 ColumnarValue::Array(arr) => {
917 let floats = as_float64_array(&arr)
918 .expect("failed to convert result to a Decimal128Array");
919 assert_eq!(floats.len(), 1);
920 assert!((floats.value(0) - 1.0).abs() < 1e-10);
921 }
922 ColumnarValue::Scalar(_) => {
923 panic!("Expected an array value")
924 }
925 }
926 }
927
928 #[test]
929 fn test_log_scalar_decimal128() {
930 let arg_fields = vec![
931 Field::new("b", DataType::Float64, false).into(),
932 Field::new("x", DataType::Decimal128(38, 0), false).into(),
933 ];
934 let args = ScalarFunctionArgs {
935 args: vec![
936 ColumnarValue::Scalar(ScalarValue::Float64(Some(2.0))), ColumnarValue::Scalar(ScalarValue::Decimal128(Some(64), 38, 0)), ],
939 arg_fields,
940 number_rows: 1,
941 return_field: Field::new("f", DataType::Float64, true).into(),
942 config_options: Arc::new(ConfigOptions::default()),
943 };
944 let result = LogFunc::new()
945 .invoke_with_args(args)
946 .expect("failed to initialize function log");
947
948 match result {
949 ColumnarValue::Array(arr) => {
950 let floats = as_float64_array(&arr)
951 .expect("failed to convert result to a Float64Array");
952
953 assert_eq!(floats.len(), 1);
954 assert!((floats.value(0) - 6.0).abs() < 1e-10);
955 }
956 ColumnarValue::Scalar(_) => {
957 panic!("Expected an array value")
958 }
959 }
960 }
961
962 #[test]
963 fn test_log_decimal128_unary() {
964 let arg_field = Field::new("a", DataType::Decimal128(38, 0), false).into();
965 let args = ScalarFunctionArgs {
966 args: vec![
967 ColumnarValue::Array(Arc::new(
968 Decimal128Array::from(vec![10, 100, 1000, 10000, 12600, -123])
969 .with_precision_and_scale(38, 0)
970 .unwrap(),
971 )), ],
973 arg_fields: vec![arg_field],
974 number_rows: 6,
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(), 6);
988 assert!((floats.value(0) - 1.0).abs() < 1e-10);
989 assert!((floats.value(1) - 2.0).abs() < 1e-10);
990 assert!((floats.value(2) - 3.0).abs() < 1e-10);
991 assert!((floats.value(3) - 4.0).abs() < 1e-10);
992 let expected = 12600_f64.log(10.0);
993 assert!((floats.value(4) - expected).abs() < 1e-10);
994 assert!(floats.value(5).is_nan());
995 }
996 ColumnarValue::Scalar(_) => {
997 panic!("Expected an array value")
998 }
999 }
1000 }
1001
1002 #[test]
1003 fn test_log_decimal128_base_decimal() {
1004 for base in [
1006 ScalarValue::Decimal128(Some(i128::from(2)), 38, 0),
1007 ScalarValue::Decimal128(Some(i128::from(2000)), 38, 3),
1008 ] {
1009 let arg_fields = vec![
1010 Field::new("b", DataType::Decimal128(38, 0), false).into(),
1011 Field::new("x", DataType::Decimal128(38, 0), false).into(),
1012 ];
1013 let args = ScalarFunctionArgs {
1014 args: vec![
1015 ColumnarValue::Scalar(base), ColumnarValue::Scalar(ScalarValue::Decimal128(Some(64), 38, 0)), ],
1018 arg_fields,
1019 number_rows: 1,
1020 return_field: Field::new("f", DataType::Float64, true).into(),
1021 config_options: Arc::new(ConfigOptions::default()),
1022 };
1023 let result = LogFunc::new()
1024 .invoke_with_args(args)
1025 .expect("failed to initialize function log");
1026
1027 match result {
1028 ColumnarValue::Array(arr) => {
1029 let floats = as_float64_array(&arr)
1030 .expect("failed to convert result to a Float64Array");
1031
1032 assert_eq!(floats.len(), 1);
1033 assert!((floats.value(0) - 6.0).abs() < 1e-10);
1034 }
1035 ColumnarValue::Scalar(_) => {
1036 panic!("Expected an array value")
1037 }
1038 }
1039 }
1040 }
1041
1042 #[test]
1043 fn test_log_decimal128_value_scale() {
1044 for value in [
1046 ScalarValue::Decimal128(Some(i128::from(1000)), 38, 0),
1047 ScalarValue::Decimal128(Some(i128::from(10000)), 38, 1),
1048 ScalarValue::Decimal128(Some(i128::from(1000000)), 38, 3),
1049 ] {
1050 let arg_fields = vec![
1051 Field::new("b", DataType::Decimal128(38, 0), false).into(),
1052 Field::new("x", DataType::Decimal128(38, 0), false).into(),
1053 ];
1054 let args = ScalarFunctionArgs {
1055 args: vec![
1056 ColumnarValue::Scalar(value), ],
1058 arg_fields,
1059 number_rows: 1,
1060 return_field: Field::new("f", DataType::Float64, true).into(),
1061 config_options: Arc::new(ConfigOptions::default()),
1062 };
1063 let result = LogFunc::new()
1064 .invoke_with_args(args)
1065 .expect("failed to initialize function log");
1066
1067 match result {
1068 ColumnarValue::Array(arr) => {
1069 let floats = as_float64_array(&arr)
1070 .expect("failed to convert result to a Float64Array");
1071
1072 assert_eq!(floats.len(), 1);
1073 assert!((floats.value(0) - 3.0).abs() < 1e-10);
1074 }
1075 ColumnarValue::Scalar(_) => {
1076 panic!("Expected an array value")
1077 }
1078 }
1079 }
1080 }
1081
1082 #[test]
1083 fn test_log_decimal256_unary() {
1084 let arg_field = Field::new(
1085 "a",
1086 DataType::Decimal256(DECIMAL256_MAX_PRECISION, 0),
1087 false,
1088 )
1089 .into();
1090 let args = ScalarFunctionArgs {
1091 args: vec![
1092 ColumnarValue::Array(Arc::new(
1093 Decimal256Array::from(vec![
1094 Some(i256::from(10)),
1095 Some(i256::from(100)),
1096 Some(i256::from(1000)),
1097 Some(i256::from(10000)),
1098 Some(i256::from(12600)),
1099 Some(i256::from_i128(i128::MAX) - i256::from(1000)),
1101 Some(i256::from(-123)),
1103 ])
1104 .with_precision_and_scale(DECIMAL256_MAX_PRECISION, 0)
1105 .unwrap(),
1106 )), ],
1108 arg_fields: vec![arg_field],
1109 number_rows: 7,
1110 return_field: Field::new("f", DataType::Float64, true).into(),
1111 config_options: Arc::new(ConfigOptions::default()),
1112 };
1113 let result = LogFunc::new()
1114 .invoke_with_args(args)
1115 .expect("failed to initialize function log");
1116
1117 match result {
1118 ColumnarValue::Array(arr) => {
1119 let floats = as_float64_array(&arr)
1120 .expect("failed to convert result to a Float64Array");
1121
1122 assert_eq!(floats.len(), 7);
1123 assert!((floats.value(0) - 1.0).abs() < 1e-10);
1124 assert!((floats.value(1) - 2.0).abs() < 1e-10);
1125 assert!((floats.value(2) - 3.0).abs() < 1e-10);
1126 assert!((floats.value(3) - 4.0).abs() < 1e-10);
1127 let expected = 12600_f64.log(10.0);
1128 assert!((floats.value(4) - expected).abs() < 1e-10);
1129 let expected = ((i128::MAX - 1000) as f64).log(10.0);
1130 assert!((floats.value(5) - expected).abs() < 1e-10);
1131 assert!(floats.value(6).is_nan());
1132 }
1133 ColumnarValue::Scalar(_) => {
1134 panic!("Expected an array value")
1135 }
1136 }
1137 }
1138
1139 #[test]
1140 fn test_log_decimal128_invalid_base() {
1141 let arg_fields = vec![
1143 Field::new("b", DataType::Float64, false).into(),
1144 Field::new("x", DataType::Decimal128(38, 0), false).into(),
1145 ];
1146 let args = ScalarFunctionArgs {
1147 args: vec![
1148 ColumnarValue::Scalar(ScalarValue::Float64(Some(-2.0))), ColumnarValue::Scalar(ScalarValue::Decimal128(Some(64), 38, 0)), ],
1151 arg_fields,
1152 number_rows: 1,
1153 return_field: Field::new("f", DataType::Float64, true).into(),
1154 config_options: Arc::new(ConfigOptions::default()),
1155 };
1156 let result = LogFunc::new()
1157 .invoke_with_args(args)
1158 .expect("should not error on invalid base");
1159
1160 match result {
1161 ColumnarValue::Array(arr) => {
1162 let floats = as_float64_array(&arr)
1163 .expect("failed to convert result to a Float64Array");
1164 assert_eq!(floats.len(), 1);
1165 assert!(floats.value(0).is_nan());
1166 }
1167 ColumnarValue::Scalar(_) => {
1168 panic!("Expected an array value")
1169 }
1170 }
1171 }
1172
1173 #[test]
1174 fn test_log_decimal256_large() {
1175 let arg_field = Field::new(
1177 "a",
1178 DataType::Decimal256(DECIMAL256_MAX_PRECISION, 0),
1179 false,
1180 )
1181 .into();
1182 let args = ScalarFunctionArgs {
1183 args: vec![
1184 ColumnarValue::Array(Arc::new(Decimal256Array::from(vec![
1185 Some(i256::from_i128(i128::MAX) + i256::from(1000)),
1187 ]))), ],
1189 arg_fields: vec![arg_field],
1190 number_rows: 1,
1191 return_field: Field::new("f", DataType::Float64, true).into(),
1192 config_options: Arc::new(ConfigOptions::default()),
1193 };
1194 let result = LogFunc::new()
1195 .invoke_with_args(args)
1196 .expect("should handle large Decimal256 via f64 fallback");
1197
1198 match result {
1199 ColumnarValue::Array(arr) => {
1200 let floats = as_float64_array(&arr)
1201 .expect("failed to convert result to a Float64Array");
1202 assert_eq!(floats.len(), 1);
1203 let log_result = floats.value(0);
1206 assert!(
1207 log_result.is_finite() && log_result > 0.0,
1208 "Expected positive finite log result, got {log_result}"
1209 );
1210 }
1211 ColumnarValue::Scalar(_) => {
1212 panic!("Expected an array value")
1213 }
1214 }
1215 }
1216}