## Coverage Report

#### Created: 2025-11-22 06:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/datafusion/datafusion/functions/src/macros.rs

    Line
    Count
    Source
    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
    /// macro that exports a list of function names as:
    19
    /// 1. individual functions in an `expr_fn` module
    20
    /// 2. a single function that returns a list of all functions
    21
    ///
    22
    /// Equivalent to
    23
    /// ```text
    24
    /// pub mod expr_fn {
    25
    ///     use super::*;
    26
    ///     /// Return encode(arg)
    27
    ///     pub fn encode(args: Vec<Expr>) -> Expr {
    28
    ///         super::encode().call(args)
    29
    ///     }
    30
    ///  ...
    31
    /// /// Return a list of all functions in this package
    32
    /// pub(crate) fn functions() -> Vec<Arc<ScalarUDF>> {
    33
    ///     vec![
    34
    ///       encode(),
    35
    ///       decode()
    36
    ///    ]
    37
    /// }
    38
    /// ```
    39
    ///
    40
    /// Exported functions accept:
    41
    /// - `Vec<Expr>` argument (single argument followed by a comma)
    42
    /// - Variable number of `Expr` arguments (zero or more arguments, must be without commas)
    43
    /// - Functions that require config (marked with `@config` prefix)
    44
    #[macro_export]
    45
    macro_rules! export_functions {
    46
        ($(($FUNC:ident, $DOC:expr, $($arg:tt)*)),*) => {
    47
            $(
    48
                // switch to single-function cases below
    49
                $crate::export_functions!(single $FUNC, $DOC, $($arg)*);
    50
            )*
    51
        };
    52
    53
        // function that requires config (marked with @config)
    54
        (single $FUNC:ident, $DOC:expr, @config) => {
    55
            #[doc = $DOC]
    56
            pub fn $FUNC() -> datafusion_expr::Expr {
    57
                use datafusion_common::config::ConfigOptions;
    58
                super::$FUNC(&ConfigOptions::default()).call(vec![])
    59
            }
    60
        };
    61
    62
        // single vector argument (a single argument followed by a comma)
    63
        (single $FUNC:ident, $DOC:expr, $arg:ident,) => {
    64
            #[doc = $DOC]
    65
    0
            pub fn $FUNC($arg: Vec<datafusion_expr::Expr>) -> datafusion_expr::Expr {
    66
    0
                super::$FUNC().call($arg)
    67
    0
            }
    68
        };
    69
    70
        // variadic arguments (zero or more arguments, without commas)
    71
        (single $FUNC:ident, $DOC:expr, $($arg:ident)*) => {
    72
            #[doc = $DOC]
    73
    0
            pub fn $FUNC($($arg: datafusion_expr::Expr),*) -> datafusion_expr::Expr {
    74
    0
                super::$FUNC().call(vec![$($arg),*])
    75
    0
            }
    76
        };
    77
    }
    78
    79
    /// Creates a singleton `ScalarUDF` of the `$UDF` function and a function
    80
    /// named `$NAME` which returns that singleton. Optionally use a custom constructor
    81
    /// `$CTOR` which defaults to `$UDF::new()` if not specified.
    82
    ///
    83
    /// This is used to ensure creating the list of `ScalarUDF` only happens once.
    84
    #[macro_export]
    85
    macro_rules! make_udf_function {
    86
        ($UDF:ty, $NAME:ident, $CTOR:expr) => {
    87
            #[allow(rustdoc::redundant_explicit_links)]
    88
            #[doc = concat!("Return a [`ScalarUDF`](datafusion_expr::ScalarUDF) implementation of ", stringify!($NAME))]
    89
    0
            pub fn $NAME() -> std::sync::Arc<datafusion_expr::ScalarUDF> {
    90
                // Singleton instance of the function
    91
                static INSTANCE: std::sync::LazyLock<
    92
                    std::sync::Arc<datafusion_expr::ScalarUDF>,
    93
    0
                > = std::sync::LazyLock::new(|| {
    94
    0
                    std::sync::Arc::new(datafusion_expr::ScalarUDF::new_from_impl(
    95
    0
                        ($CTOR)(),
    96
                    ))
    97
    0
                });
    98
    0
                std::sync::Arc::clone(&INSTANCE)
    99
    0
            }
    100
        };
    101
        ($UDF:ty, $NAME:ident) => {
    102
            make_udf_function!($UDF, $NAME, <$UDF>::new);
    103
        };
    104
    }
    105
    106
    /// Creates a singleton `ScalarUDF` of the `$UDF` function and a function
    107
    /// named `$NAME` which returns that singleton. The function takes a
    108
    /// configuration argument of type `$CONFIG_TYPE` to create the UDF.
    109
    #[macro_export]
    110
    macro_rules! make_udf_function_with_config {
    111
        ($UDF:ty, $NAME:ident) => {
    112
            #[allow(rustdoc::redundant_explicit_links)]
    113
            #[doc = concat!("Return a [`ScalarUDF`](datafusion_expr::ScalarUDF) implementation of ", stringify!($NAME))]
    114
    0
            pub fn $NAME(config: &datafusion_common::config::ConfigOptions) -> std::sync::Arc<datafusion_expr::ScalarUDF> {
    115
    0
                std::sync::Arc::new(datafusion_expr::ScalarUDF::new_from_impl(
    116
    0
                    <$UDF>::new_with_config(&config),
    117
                ))
    118
    0
            }
    119
        };
    120
    }
    121
    122
    /// Macro creates a sub module if the feature is not enabled
    123
    ///
    124
    /// The rationale for providing stub functions is to help users to configure datafusion
    125
    /// properly (so they get an error telling them why a function is not available)
    126
    /// instead of getting a cryptic "no function found" message at runtime.
    127
    macro_rules! make_stub_package {
    128
        ($name:ident, $feature:literal) => {
    129
            #[cfg(not(feature = $feature))]
    130
            #[doc = concat!("Disabled. Enable via feature flag `", $feature, "`")]
    131
            pub mod $name {
    132
                use datafusion_expr::ScalarUDF;
    133
                use log::debug;
    134
                use std::sync::Arc;
    135
    136
                /// Returns an empty list of functions when the feature is not enabled
    137
    0
                pub fn functions() -> Vec<Arc<ScalarUDF>> {
    138
    0
                    debug!("{} functions disabled", stringify!($name));
    139
    0
                    vec![]
    140
    0
                }
    141
            }
    142
        };
    143
    }
    144
    145
    /// Downcast a named argument to a specific array type, returning an internal error
    146
    /// if the cast fails
    147
    ///
    148
    /// $ARG: ArrayRef
    149
    /// $NAME: name of the argument (for error messages)
    150
    /// $ARRAY_TYPE: the type of array to cast the argument to
    151
    #[macro_export]
    152
    macro_rules! downcast_named_arg {
    153
        ($ARG:expr, $NAME:expr, $ARRAY_TYPE:ident) => {{
    154
    0
            $ARG.as_any().downcast_ref::<$ARRAY_TYPE>().ok_or_else(|| {
    155
    0
                datafusion_common::internal_datafusion_err!(
    156
    0
                    "could not cast {} to {}",
    157
                    $NAME,
    158
    0
                    std::any::type_name::<$ARRAY_TYPE>()
    159
                )
    160
    0
            })?
    161
        }};
    162
    }
    163
    164
    /// Downcast an argument to a specific array type, returning an internal error
    165
    /// if the cast fails
    166
    ///
    167
    /// $ARG: ArrayRef
    168
    /// $ARRAY_TYPE: the type of array to cast the argument to
    169
    #[macro_export]
    170
    macro_rules! downcast_arg {
    171
        ($ARG:expr, $ARRAY_TYPE:ident) => {{
    172
            $crate::downcast_named_arg!($ARG, "", $ARRAY_TYPE)
    173
        }};
    174
    }
    175
    176
    /// Macro to create a unary math UDF.
    177
    ///
    178
    /// A unary math function takes an argument of type Float32 or Float64,
    179
    /// applies a unary floating function to the argument, and returns a value of the same type.
    180
    ///
    181
    /// $UDF: the name of the UDF struct that implements `ScalarUDFImpl`
    182
    /// $NAME: the name of the function
    183
    /// $UNARY_FUNC: the unary function to apply to the argument
    184
    /// $OUTPUT_ORDERING: the output ordering calculation method of the function
    185
    /// $GET_DOC: the function to get the documentation of the UDF
    186
    macro_rules! make_math_unary_udf {
    187
        ($UDF:ident, $NAME:ident, $UNARY_FUNC:ident, $OUTPUT_ORDERING:expr, $EVALUATE_BOUNDS:expr, $GET_DOC:expr) => {
    188
            $crate::make_udf_function!($NAME::$UDF, $NAME);
    189
    190
            mod $NAME {
    191
                use std::any::Any;
    192
                use std::sync::Arc;
    193
    194
                use arrow::array::{ArrayRef, AsArray};
    195
                use arrow::datatypes::{DataType, Float32Type, Float64Type};
    196
                use datafusion_common::{exec_err, Result};
    197
                use datafusion_expr::interval_arithmetic::Interval;
    198
                use datafusion_expr::sort_properties::{ExprProperties, SortProperties};
    199
                use datafusion_expr::{
    200
                    ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl,
    201
                    Signature, Volatility,
    202
                };
    203
    204
                #[derive(Debug, PartialEq, Eq, Hash)]
    205
                pub struct $UDF {
    206
                    signature: Signature,
    207
                }
    208
    209
                impl $UDF {
    210
    0
                    pub fn new() -> Self {
    211
                        use DataType::*;
    212
    0
                        Self {
    213
    0
                            signature: Signature::uniform(
    214
    0
                                1,
    215
    0
                                vec![Float64, Float32],
    216
    0
                                Volatility::Immutable,
    217
    0
                            ),
    218
    0
                        }
    219
    0
                    }
    220
                }
    221
    222
                impl ScalarUDFImpl for $UDF {
    223
    0
                    fn as_any(&self) -> &dyn Any {
    224
    0
                        self
    225
    0
                    }
    226
    0
                    fn name(&self) -> &str {
    227
    0
                        stringify!($NAME)
    228
    0
                    }
    229
    230
    0
                    fn signature(&self) -> &Signature {
    231
    0
                        &self.signature
    232
    0
                    }
    233
    234
    0
                    fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
    235
    0
                        let arg_type = &arg_types[0];
    236
    237
    0
                        match arg_type {
    238
    0
                            DataType::Float32 => Ok(DataType::Float32),
    239
                            // For other types (possible values float64/null/int), use Float64
    240
    0
                            _ => Ok(DataType::Float64),
    241
                        }
    242
    0
                    }
    243
    244
    0
                    fn output_ordering(
    245
    0
                        &self,
    246
    0
                        input: &[ExprProperties],
    247
    0
                    ) -> Result<SortProperties> {
    248
    0
                        $OUTPUT_ORDERING(input)
    249
    0
                    }
    250
    251
    0
                    fn evaluate_bounds(&self, inputs: &[&Interval]) -> Result<Interval> {
    252
    0
                        $EVALUATE_BOUNDS(inputs)
    253
    0
                    }
    254
    255
    0
                    fn invoke_with_args(
    256
    0
                        &self,
    257
    0
                        args: ScalarFunctionArgs,
    258
    0
                    ) -> Result<ColumnarValue> {
    259
    0
                        let args = ColumnarValue::values_to_arrays(&args.args)?;
    260
    0
                        let arr: ArrayRef = match args[0].data_type() {
    261
    0
                            DataType::Float64 => Arc::new(
    262
    0
                                args[0]
    263
    0
                                    .as_primitive::<Float64Type>()
    264
    0
                                    .unary::<_, Float64Type>(|x: f64| f64::$UNARY_FUNC(x)),
    265
    0
                            ) as ArrayRef,
    266
    0
                            DataType::Float32 => Arc::new(
    267
    0
                                args[0]
    268
    0
                                    .as_primitive::<Float32Type>()
    269
    0
                                    .unary::<_, Float32Type>(|x: f32| f32::$UNARY_FUNC(x)),
    270
    0
                            ) as ArrayRef,
    271
    0
                            other => {
    272
    0
                                return exec_err!(
    273
    0
                                    "Unsupported data type {other:?} for function {}",
    274
    0
                                    self.name()
    275
                                )
    276
                            }
    277
                        };
    278
    279
    0
                        Ok(ColumnarValue::Array(arr))
    280
    0
                    }
    281
    282
    0
                    fn documentation(&self) -> Option<&Documentation> {
    283
    0
                        Some($GET_DOC())
    284
    0
                    }
    285
                }
    286
            }
    287
        };
    288
    }
    289
    290
    /// Macro to create a binary math UDF.
    291
    ///
    292
    /// A binary math function takes two arguments of types Float32 or Float64,
    293
    /// applies a binary floating function to the argument, and returns a value of the same type.
    294
    ///
    295
    /// $UDF: the name of the UDF struct that implements `ScalarUDFImpl`
    296
    /// $NAME: the name of the function
    297
    /// $BINARY_FUNC: the binary function to apply to the argument
    298
    /// $OUTPUT_ORDERING: the output ordering calculation method of the function
    299
    /// $GET_DOC: the function to get the documentation of the UDF
    300
    macro_rules! make_math_binary_udf {
    301
        ($UDF:ident, $NAME:ident, $BINARY_FUNC:ident, $OUTPUT_ORDERING:expr, $GET_DOC:expr) => {
    302
            $crate::make_udf_function!($NAME::$UDF, $NAME);
    303
    304
            mod $NAME {
    305
                use std::any::Any;
    306
                use std::sync::Arc;
    307
    308
                use arrow::array::{ArrayRef, AsArray};
    309
                use arrow::datatypes::{DataType, Float32Type, Float64Type};
    310
                use datafusion_common::{exec_err, Result};
    311
                use datafusion_expr::sort_properties::{ExprProperties, SortProperties};
    312
                use datafusion_expr::TypeSignature;
    313
                use datafusion_expr::{
    314
                    ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl,
    315
                    Signature, Volatility,
    316
                };
    317
    318
                #[derive(Debug, PartialEq, Eq, Hash)]
    319
                pub struct $UDF {
    320
                    signature: Signature,
    321
                }
    322
    323
                impl $UDF {
    324
    0
                    pub fn new() -> Self {
    325
                        use DataType::*;
    326
    0
                        Self {
    327
    0
                            signature: Signature::one_of(
    328
    0
                                vec![
    329
    0
                                    TypeSignature::Exact(vec![Float32, Float32]),
    330
    0
                                    TypeSignature::Exact(vec![Float64, Float64]),
    331
    0
                                ],
    332
    0
                                Volatility::Immutable,
    333
    0
                            ),
    334
    0
                        }
    335
    0
                    }
    336
                }
    337
    338
                impl ScalarUDFImpl for $UDF {
    339
    0
                    fn as_any(&self) -> &dyn Any {
    340
    0
                        self
    341
    0
                    }
    342
    0
                    fn name(&self) -> &str {
    343
    0
                        stringify!($NAME)
    344
    0
                    }
    345
    346
    0
                    fn signature(&self) -> &Signature {
    347
    0
                        &self.signature
    348
    0
                    }
    349
    350
    0
                    fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
    351
    0
                        let arg_type = &arg_types[0];
    352
    353
    0
                        match arg_type {
    354
    0
                            DataType::Float32 => Ok(DataType::Float32),
    355
                            // For other types (possible values float64/null/int), use Float64
    356
    0
                            _ => Ok(DataType::Float64),
    357
                        }
    358
    0
                    }
    359
    360
    0
                    fn output_ordering(
    361
    0
                        &self,
    362
    0
                        input: &[ExprProperties],
    363
    0
                    ) -> Result<SortProperties> {
    364
    0
                        $OUTPUT_ORDERING(input)
    365
    0
                    }
    366
    367
    0
                    fn invoke_with_args(
    368
    0
                        &self,
    369
    0
                        args: ScalarFunctionArgs,
    370
    0
                    ) -> Result<ColumnarValue> {
    371
    0
                        let args = ColumnarValue::values_to_arrays(&args.args)?;
    372
    0
                        let arr: ArrayRef = match args[0].data_type() {
    373
                            DataType::Float64 => {
    374
    0
                                let y = args[0].as_primitive::<Float64Type>();
    375
    0
                                let x = args[1].as_primitive::<Float64Type>();
    376
    0
                                let result = arrow::compute::binary::<_, _, _, Float64Type>(
    377
    0
                                    y,
    378
    0
                                    x,
    379
    0
                                    |y, x| f64::$BINARY_FUNC(y, x),
    380
    0
                                )?;
    381
    0
                                Arc::new(result) as _
    382
                            }
    383
                            DataType::Float32 => {
    384
    0
                                let y = args[0].as_primitive::<Float32Type>();
    385
    0
                                let x = args[1].as_primitive::<Float32Type>();
    386
    0
                                let result = arrow::compute::binary::<_, _, _, Float32Type>(
    387
    0
                                    y,
    388
    0
                                    x,
    389
    0
                                    |y, x| f32::$BINARY_FUNC(y, x),
    390
    0
                                )?;
    391
    0
                                Arc::new(result) as _
    392
                            }
    393
    0
                            other => {
    394
    0
                                return exec_err!(
    395
    0
                                    "Unsupported data type {other:?} for function {}",
    396
    0
                                    self.name()
    397
                                )
    398
                            }
    399
                        };
    400
    401
    0
                        Ok(ColumnarValue::Array(arr))
    402
    0
                    }
    403
    404
    0
                    fn documentation(&self) -> Option<&Documentation> {
    405
    0
                        Some($GET_DOC())
    406
    0
                    }
    407
                }
    408
            }
    409
        };
    410
    }