## 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/expr/src/udwf.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
    //! [`WindowUDF`]: User Defined Window Functions
    19
    20
    use arrow::compute::SortOptions;
    21
    use std::cmp::Ordering;
    22
    use std::hash::{Hash, Hasher};
    23
    use std::{
    24
        any::Any,
    25
        fmt::{self, Debug, Display, Formatter},
    26
        sync::Arc,
    27
    };
    28
    29
    use arrow::datatypes::{DataType, FieldRef};
    30
    31
    use crate::expr::WindowFunction;
    32
    use crate::udf_eq::UdfEq;
    33
    use crate::{
    34
        function::WindowFunctionSimplification, Expr, PartitionEvaluator, Signature,
    35
    };
    36
    use datafusion_common::{not_impl_err, Result};
    37
    use datafusion_doc::Documentation;
    38
    use datafusion_expr_common::dyn_eq::{DynEq, DynHash};
    39
    use datafusion_functions_window_common::expr::ExpressionArgs;
    40
    use datafusion_functions_window_common::field::WindowUDFFieldArgs;
    41
    use datafusion_functions_window_common::partition::PartitionEvaluatorArgs;
    42
    use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
    43
    44
    /// Logical representation of a user-defined window function (UDWF).
    45
    ///
    46
    /// A Window Function is called via the SQL `OVER` clause:
    47
    ///
    48
    /// ```sql
    49
    /// SELECT first_value(col) OVER (PARTITION BY a, b ORDER BY c) FROM foo;
    50
    /// ```
    51
    ///
    52
    /// A UDWF is different from a user defined function (UDF) in that it is
    53
    /// stateful across batches.
    54
    ///
    55
    /// See the documentation on [`PartitionEvaluator`] for more details
    56
    ///
    57
    /// 1. For simple use cases, use [`create_udwf`] (examples in
    58
    ///    [`simple_udwf.rs`]).
    59
    ///
    60
    /// 2. For advanced use cases, use [`WindowUDFImpl`] which provides full API
    61
    ///    access (examples in [`advanced_udwf.rs`]).
    62
    ///
    63
    /// # API Note
    64
    /// This is a separate struct from `WindowUDFImpl` to maintain backwards
    65
    /// compatibility with the older API.
    66
    ///
    67
    /// [`PartitionEvaluator`]: crate::PartitionEvaluator
    68
    /// [`create_udwf`]: crate::expr_fn::create_udwf
    69
    /// [`simple_udwf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/simple_udwf.rs
    70
    /// [`advanced_udwf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/advanced_udwf.rs
    71
    #[derive(Debug, Clone, PartialOrd)]
    72
    pub struct WindowUDF {
    73
        inner: Arc<dyn WindowUDFImpl>,
    74
    }
    75
    76
    /// Defines how the WindowUDF is shown to users
    77
    impl Display for WindowUDF {
    78
    0
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
    79
    0
            write!(f, "{}", self.name())
    80
    0
        }
    81
    }
    82
    83
    impl PartialEq for WindowUDF {
    84
    0
        fn eq(&self, other: &Self) -> bool {
    85
    0
            self.inner.dyn_eq(other.inner.as_any())
    86
    0
        }
    87
    }
    88
    89
    impl Eq for WindowUDF {}
    90
    91
    impl Hash for WindowUDF {
    92
    0
        fn hash<H: Hasher>(&self, state: &mut H) {
    93
    0
            self.inner.dyn_hash(state)
    94
    0
        }
    95
    }
    96
    97
    impl WindowUDF {
    98
        /// Create a new `WindowUDF` from a `[WindowUDFImpl]` trait object
    99
        ///
    100
        /// Note this is the same as using the `From` impl (`WindowUDF::from`)
    101
    0
        pub fn new_from_impl<F>(fun: F) -> WindowUDF
    102
    0
        where
    103
    0
            F: WindowUDFImpl + 'static,
    104
        {
    105
    0
            Self::new_from_shared_impl(Arc::new(fun))
    106
    0
        }
    107
    108
        /// Create a new `WindowUDF` from a `[WindowUDFImpl]` trait object
    109
    0
        pub fn new_from_shared_impl(fun: Arc<dyn WindowUDFImpl>) -> WindowUDF {
    110
    0
            Self { inner: fun }
    111
    0
        }
    112
    113
        /// Return the underlying [`WindowUDFImpl`] trait object for this function
    114
    0
        pub fn inner(&self) -> &Arc<dyn WindowUDFImpl> {
    115
    0
            &self.inner
    116
    0
        }
    117
    118
        /// Adds additional names that can be used to invoke this function, in
    119
        /// addition to `name`
    120
        ///
    121
        /// If you implement [`WindowUDFImpl`] directly you should return aliases directly.
    122
    0
        pub fn with_aliases(self, aliases: impl IntoIterator<Item = &'static str>) -> Self {
    123
    0
            Self::new_from_impl(AliasedWindowUDFImpl::new(Arc::clone(&self.inner), aliases))
    124
    0
        }
    125
    126
        /// creates a [`Expr`] that calls the window function with default
    127
        /// values for `order_by`, `partition_by`, `window_frame`.
    128
        ///
    129
        /// See [`ExprFunctionExt`] for details on setting these values.
    130
        ///
    131
        /// This utility allows using a user defined window function without
    132
        /// requiring access to the registry, such as with the DataFrame API.
    133
        ///
    134
        /// [`ExprFunctionExt`]: crate::expr_fn::ExprFunctionExt
    135
    0
        pub fn call(&self, args: Vec<Expr>) -> Expr {
    136
    0
            let fun = crate::WindowFunctionDefinition::WindowUDF(Arc::new(self.clone()));
    137
    138
    0
            Expr::from(WindowFunction::new(fun, args))
    139
    0
        }
    140
    141
        /// Returns this function's name
    142
        ///
    143
        /// See [`WindowUDFImpl::name`] for more details.
    144
    0
        pub fn name(&self) -> &str {
    145
    0
            self.inner.name()
    146
    0
        }
    147
    148
        /// Returns the aliases for this function.
    149
    0
        pub fn aliases(&self) -> &[String] {
    150
    0
            self.inner.aliases()
    151
    0
        }
    152
    153
        /// Returns this function's signature (what input types are accepted)
    154
        ///
    155
        /// See [`WindowUDFImpl::signature`] for more details.
    156
    0
        pub fn signature(&self) -> &Signature {
    157
    0
            self.inner.signature()
    158
    0
        }
    159
    160
        /// Do the function rewrite
    161
        ///
    162
        /// See [`WindowUDFImpl::simplify`] for more details.
    163
    0
        pub fn simplify(&self) -> Option<WindowFunctionSimplification> {
    164
    0
            self.inner.simplify()
    165
    0
        }
    166
    167
        /// Expressions that are passed to the [`PartitionEvaluator`].
    168
        ///
    169
        /// See [`WindowUDFImpl::expressions`] for more details.
    170
    0
        pub fn expressions(&self, expr_args: ExpressionArgs) -> Vec<Arc<dyn PhysicalExpr>> {
    171
    0
            self.inner.expressions(expr_args)
    172
    0
        }
    173
        /// Return a `PartitionEvaluator` for evaluating this window function
    174
    0
        pub fn partition_evaluator_factory(
    175
    0
            &self,
    176
    0
            partition_evaluator_args: PartitionEvaluatorArgs,
    177
    0
        ) -> Result<Box<dyn PartitionEvaluator>> {
    178
    0
            self.inner.partition_evaluator(partition_evaluator_args)
    179
    0
        }
    180
    181
        /// Returns the field of the final result of evaluating this window function.
    182
        ///
    183
        /// See [`WindowUDFImpl::field`] for more details.
    184
    0
        pub fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
    185
    0
            self.inner.field(field_args)
    186
    0
        }
    187
    188
        /// Returns custom result ordering introduced by this window function
    189
        /// which is used to update ordering equivalences.
    190
        ///
    191
        /// See [`WindowUDFImpl::sort_options`] for more details.
    192
    0
        pub fn sort_options(&self) -> Option<SortOptions> {
    193
    0
            self.inner.sort_options()
    194
    0
        }
    195
    196
        /// See [`WindowUDFImpl::coerce_types`] for more details.
    197
    0
        pub fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
    198
    0
            self.inner.coerce_types(arg_types)
    199
    0
        }
    200
    201
        /// Returns the reversed user-defined window function when the
    202
        /// order of evaluation is reversed.
    203
        ///
    204
        /// See [`WindowUDFImpl::reverse_expr`] for more details.
    205
    0
        pub fn reverse_expr(&self) -> ReversedUDWF {
    206
    0
            self.inner.reverse_expr()
    207
    0
        }
    208
    209
        /// Returns the documentation for this Window UDF.
    210
        ///
    211
        /// Documentation can be accessed programmatically as well as
    212
        /// generating publicly facing documentation.
    213
    0
        pub fn documentation(&self) -> Option<&Documentation> {
    214
    0
            self.inner.documentation()
    215
    0
        }
    216
    }
    217
    218
    impl<F> From<F> for WindowUDF
    219
    where
    220
        F: WindowUDFImpl + Send + Sync + 'static,
    221
    {
    222
    0
        fn from(fun: F) -> Self {
    223
    0
            Self::new_from_impl(fun)
    224
    0
        }
    225
    }
    226
    227
    /// Trait for implementing [`WindowUDF`].
    228
    ///
    229
    /// This trait exposes the full API for implementing user defined window functions and
    230
    /// can be used to implement any function.
    231
    ///
    232
    /// While the trait depends on [`DynEq`] and [`DynHash`] traits, these should not be
    233
    /// implemented directly. Instead, implement [`Eq`] and [`Hash`] and leverage the
    234
    /// blanket implementations of [`DynEq`] and [`DynHash`].
    235
    ///
    236
    /// See [`advanced_udwf.rs`] for a full example with complete implementation and
    237
    /// [`WindowUDF`] for other available options.
    238
    ///
    239
    ///
    240
    /// [`advanced_udwf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/advanced_udwf.rs
    241
    /// # Basic Example
    242
    /// ```
    243
    /// # use std::any::Any;
    244
    /// # use std::sync::LazyLock;
    245
    /// # use arrow::datatypes::{DataType, Field, FieldRef};
    246
    /// # use datafusion_common::{DataFusionError, plan_err, Result};
    247
    /// # use datafusion_expr::{col, Signature, Volatility, PartitionEvaluator, WindowFrame, ExprFunctionExt, Documentation, LimitEffect};
    248
    /// # use datafusion_expr::{WindowUDFImpl, WindowUDF};
    249
    /// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
    250
    /// # use datafusion_functions_window_common::partition::PartitionEvaluatorArgs;
    251
    /// # use datafusion_expr::window_doc_sections::DOC_SECTION_ANALYTICAL;
    252
    /// # use datafusion_physical_expr_common::physical_expr;
    253
    /// # use std::sync::Arc;
    254
    ///
    255
    /// #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    256
    /// struct SmoothIt {
    257
    ///   signature: Signature,
    258
    /// }
    259
    ///
    260
    /// impl SmoothIt {
    261
    ///   fn new() -> Self {
    262
    ///     Self {
    263
    ///       signature: Signature::uniform(1, vec![DataType::Int32], Volatility::Immutable),
    264
    ///      }
    265
    ///   }
    266
    /// }
    267
    ///
    268
    /// static DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
    269
    ///     Documentation::builder(DOC_SECTION_ANALYTICAL, "smooths the windows", "smooth_it(2)")
    270
    ///         .with_argument("arg1", "The int32 number to smooth by")
    271
    ///         .build()
    272
    /// });
    273
    ///
    274
    /// fn get_doc() -> &'static Documentation {
    275
    ///     &DOCUMENTATION
    276
    /// }
    277
    ///
    278
    /// /// Implement the WindowUDFImpl trait for SmoothIt
    279
    /// impl WindowUDFImpl for SmoothIt {
    280
    ///    fn as_any(&self) -> &dyn Any { self }
    281
    ///    fn name(&self) -> &str { "smooth_it" }
    282
    ///    fn signature(&self) -> &Signature { &self.signature }
    283
    ///    // The actual implementation would smooth the window
    284
    ///    fn partition_evaluator(
    285
    ///        &self,
    286
    ///        _partition_evaluator_args: PartitionEvaluatorArgs,
    287
    ///    ) -> Result<Box<dyn PartitionEvaluator>> {
    288
    ///        unimplemented!()
    289
    ///    }
    290
    ///    fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
    291
    ///      if let Some(DataType::Int32) = field_args.get_input_field(0).map(|f| f.data_type().clone()) {
    292
    ///        Ok(Field::new(field_args.name(), DataType::Int32, false).into())
    293
    ///      } else {
    294
    ///        plan_err!("smooth_it only accepts Int32 arguments")
    295
    ///      }
    296
    ///    }
    297
    ///    fn documentation(&self) -> Option<&Documentation> {
    298
    ///      Some(get_doc())
    299
    ///    }
    300
    ///     fn limit_effect(&self, _args: &[Arc<dyn physical_expr::PhysicalExpr>]) -> LimitEffect {
    301
    ///         LimitEffect::Unknown
    302
    ///     }
    303
    /// }
    304
    ///
    305
    /// // Create a new WindowUDF from the implementation
    306
    /// let smooth_it = WindowUDF::from(SmoothIt::new());
    307
    ///
    308
    /// // Call the function `add_one(col)`
    309
    /// // smooth_it(speed) OVER (PARTITION BY car ORDER BY time ASC)
    310
    /// let expr = smooth_it.call(vec![col("speed")])
    311
    ///     .partition_by(vec![col("car")])
    312
    ///     .order_by(vec![col("time").sort(true, true)])
    313
    ///     .window_frame(WindowFrame::new(None))
    314
    ///     .build()
    315
    ///     .unwrap();
    316
    /// ```
    317
    pub trait WindowUDFImpl: Debug + DynEq + DynHash + Send + Sync {
    318
        /// Returns this object as an [`Any`] trait object
    319
        fn as_any(&self) -> &dyn Any;
    320
    321
        /// Returns this function's name
    322
        fn name(&self) -> &str;
    323
    324
        /// Returns any aliases (alternate names) for this function.
    325
        ///
    326
        /// Note: `aliases` should only include names other than [`Self::name`].
    327
        /// Defaults to `[]` (no aliases)
    328
    0
        fn aliases(&self) -> &[String] {
    329
    0
            &[]
    330
    0
        }
    331
    332
        /// Returns the function's [`Signature`] for information about what input
    333
        /// types are accepted and the function's Volatility.
    334
        fn signature(&self) -> &Signature;
    335
    336
        /// Returns the expressions that are passed to the [`PartitionEvaluator`].
    337
    0
        fn expressions(&self, expr_args: ExpressionArgs) -> Vec<Arc<dyn PhysicalExpr>> {
    338
    0
            expr_args.input_exprs().into()
    339
    0
        }
    340
    341
        /// Invoke the function, returning the [`PartitionEvaluator`] instance
    342
        fn partition_evaluator(
    343
            &self,
    344
            partition_evaluator_args: PartitionEvaluatorArgs,
    345
        ) -> Result<Box<dyn PartitionEvaluator>>;
    346
    347
        /// Optionally apply per-UDWF simplification / rewrite rules.
    348
        ///
    349
        /// This can be used to apply function specific simplification rules during
    350
        /// optimization. The default implementation does nothing.
    351
        ///
    352
        /// Note that DataFusion handles simplifying arguments and  "constant
    353
        /// folding" (replacing a function call with constant arguments such as
    354
        /// `my_add(1,2) --> 3` ). Thus, there is no need to implement such
    355
        /// optimizations manually for specific UDFs.
    356
        ///
    357
        /// Example:
    358
        /// `advanced_udwf.rs`: <https://github.com/apache/arrow-datafusion/blob/main/datafusion-examples/examples/advanced_udwf.rs>
    359
        ///
    360
        /// # Returns
    361
        /// [None] if simplify is not defined or,
    362
        ///
    363
        /// Or, a closure with two arguments:
    364
        /// * 'window_function': [crate::expr::WindowFunction] for which simplified has been invoked
    365
        /// * 'info': [crate::simplify::SimplifyInfo]
    366
        ///
    367
        /// # Notes
    368
        /// The returned expression must have the same schema as the original
    369
        /// expression, including both the data type and nullability. For example,
    370
        /// if the original expression is nullable, the returned expression must
    371
        /// also be nullable, otherwise it may lead to schema verification errors
    372
        /// later in query planning.
    373
    0
        fn simplify(&self) -> Option<WindowFunctionSimplification> {
    374
    0
            None
    375
    0
        }
    376
    377
        /// The [`FieldRef`] of the final result of evaluating this window function.
    378
        ///
    379
        /// Call `field_args.name()` to get the fully qualified name for defining
    380
        /// the [`FieldRef`]. For a complete example see the implementation in the
    381
        /// [Basic Example](WindowUDFImpl#basic-example) section.
    382
        fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef>;
    383
    384
        /// Allows the window UDF to define a custom result ordering.
    385
        ///
    386
        /// By default, a window UDF doesn't introduce an ordering.
    387
        /// But when specified by a window UDF this is used to update
    388
        /// ordering equivalences.
    389
    0
        fn sort_options(&self) -> Option<SortOptions> {
    390
    0
            None
    391
    0
        }
    392
    393
        /// Coerce arguments of a function call to types that the function can evaluate.
    394
        ///
    395
        /// This function is only called if [`WindowUDFImpl::signature`] returns [`crate::TypeSignature::UserDefined`]. Most
    396
        /// UDWFs should return one of the other variants of `TypeSignature` which handle common
    397
        /// cases
    398
        ///
    399
        /// See the [type coercion module](crate::type_coercion)
    400
        /// documentation for more details on type coercion
    401
        ///
    402
        /// For example, if your function requires a floating point arguments, but the user calls
    403
        /// it like `my_func(1::int)` (aka with `1` as an integer), coerce_types could return `[DataType::Float64]`
    404
        /// to ensure the argument was cast to `1::double`
    405
        ///
    406
        /// # Parameters
    407
        /// * `arg_types`: The argument types of the arguments  this function with
    408
        ///
    409
        /// # Return value
    410
        /// A Vec the same length as `arg_types`. DataFusion will `CAST` the function call
    411
        /// arguments to these specific types.
    412
    0
        fn coerce_types(&self, _arg_types: &[DataType]) -> Result<Vec<DataType>> {
    413
    0
            not_impl_err!("Function {} does not implement coerce_types", self.name())
    414
    0
        }
    415
    416
        /// Allows customizing the behavior of the user-defined window
    417
        /// function when it is evaluated in reverse order.
    418
    0
        fn reverse_expr(&self) -> ReversedUDWF {
    419
    0
            ReversedUDWF::NotSupported
    420
    0
        }
    421
    422
        /// Returns the documentation for this Window UDF.
    423
        ///
    424
        /// Documentation can be accessed programmatically as well as
    425
        /// generating publicly facing documentation.
    426
    0
        fn documentation(&self) -> Option<&Documentation> {
    427
    0
            None
    428
    0
        }
    429
    430
        /// If not causal, returns the effect this function will have on the window
    431
    0
        fn limit_effect(&self, _args: &[Arc<dyn PhysicalExpr>]) -> LimitEffect {
    432
    0
            LimitEffect::Unknown
    433
    0
        }
    434
    }
    435
    436
    /// the effect this function will have on the limit pushdown
    437
    pub enum LimitEffect {
    438
        /// Does not affect the limit (i.e. this is causal)
    439
        None,
    440
        /// Either undeclared, or dynamic (only evaluatable at run time)
    441
        Unknown,
    442
        /// Grow the limit by N rows
    443
        Relative(usize),
    444
        /// Limit needs to be at least N rows
    445
        Absolute(usize),
    446
    }
    447
    448
    pub enum ReversedUDWF {
    449
        /// The result of evaluating the user-defined window function
    450
        /// remains identical when reversed.
    451
        Identical,
    452
        /// A window function which does not support evaluating the result
    453
        /// in reverse order.
    454
        NotSupported,
    455
        /// Customize the user-defined window function for evaluating the
    456
        /// result in reverse order.
    457
        Reversed(Arc<WindowUDF>),
    458
    }
    459
    460
    impl PartialEq for dyn WindowUDFImpl {
    461
    0
        fn eq(&self, other: &Self) -> bool {
    462
    0
            self.dyn_eq(other.as_any())
    463
    0
        }
    464
    }
    465
    466
    impl PartialOrd for dyn WindowUDFImpl {
    467
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    468
    0
            match self.name().partial_cmp(other.name()) {
    469
    0
                Some(Ordering::Equal) => self.signature().partial_cmp(other.signature()),
    470
    0
                cmp => cmp,
    471
            }
    472
            // TODO (https://github.com/apache/datafusion/issues/17477) avoid recomparing all fields
    473
    0
            .filter(|cmp| *cmp != Ordering::Equal || self == other)
    474
    0
        }
    475
    }
    476
    477
    /// WindowUDF that adds an alias to the underlying function. It is better to
    478
    /// implement [`WindowUDFImpl`], which supports aliases, directly if possible.
    479
    #[derive(Debug, PartialEq, Eq, Hash)]
    480
    struct AliasedWindowUDFImpl {
    481
        inner: UdfEq<Arc<dyn WindowUDFImpl>>,
    482
        aliases: Vec<String>,
    483
    }
    484
    485
    impl AliasedWindowUDFImpl {
    486
    0
        pub fn new(
    487
    0
            inner: Arc<dyn WindowUDFImpl>,
    488
    0
            new_aliases: impl IntoIterator<Item = &'static str>,
    489
    0
        ) -> Self {
    490
    0
            let mut aliases = inner.aliases().to_vec();
    491
    0
            aliases.extend(new_aliases.into_iter().map(|s| s.to_string()));
    492
    493
    0
            Self {
    494
    0
                inner: inner.into(),
    495
    0
                aliases,
    496
    0
            }
    497
    0
        }
    498
    }
    499
    500
    #[warn(clippy::missing_trait_methods)] // Delegates, so it should implement every single trait method
    501
    impl WindowUDFImpl for AliasedWindowUDFImpl {
    502
    0
        fn as_any(&self) -> &dyn Any {
    503
    0
            self
    504
    0
        }
    505
    506
    0
        fn name(&self) -> &str {
    507
    0
            self.inner.name()
    508
    0
        }
    509
    510
    0
        fn signature(&self) -> &Signature {
    511
    0
            self.inner.signature()
    512
    0
        }
    513
    514
    0
        fn expressions(&self, expr_args: ExpressionArgs) -> Vec<Arc<dyn PhysicalExpr>> {
    515
    0
            expr_args
    516
    0
                .input_exprs()
    517
    0
                .first()
    518
    0
                .map_or(vec![], |expr| vec![Arc::clone(expr)])
    519
    0
        }
    520
    521
    0
        fn partition_evaluator(
    522
    0
            &self,
    523
    0
            partition_evaluator_args: PartitionEvaluatorArgs,
    524
    0
        ) -> Result<Box<dyn PartitionEvaluator>> {
    525
    0
            self.inner.partition_evaluator(partition_evaluator_args)
    526
    0
        }
    527
    528
    0
        fn aliases(&self) -> &[String] {
    529
    0
            &self.aliases
    530
    0
        }
    531
    532
    0
        fn simplify(&self) -> Option<WindowFunctionSimplification> {
    533
    0
            self.inner.simplify()
    534
    0
        }
    535
    536
    0
        fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
    537
    0
            self.inner.field(field_args)
    538
    0
        }
    539
    540
    0
        fn sort_options(&self) -> Option<SortOptions> {
    541
    0
            self.inner.sort_options()
    542
    0
        }
    543
    544
    0
        fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
    545
    0
            self.inner.coerce_types(arg_types)
    546
    0
        }
    547
    548
    0
        fn reverse_expr(&self) -> ReversedUDWF {
    549
    0
            self.inner.reverse_expr()
    550
    0
        }
    551
    552
    0
        fn documentation(&self) -> Option<&Documentation> {
    553
    0
            self.inner.documentation()
    554
    0
        }
    555
    556
    0
        fn limit_effect(&self, args: &[Arc<dyn PhysicalExpr>]) -> LimitEffect {
    557
    0
            self.inner.limit_effect(args)
    558
    0
        }
    559
    }
    560
    561
    #[cfg(test)]
    562
    mod test {
    563
        use crate::{LimitEffect, PartitionEvaluator, WindowUDF, WindowUDFImpl};
    564
        use arrow::datatypes::{DataType, FieldRef};
    565
        use datafusion_common::Result;
    566
        use datafusion_expr_common::signature::{Signature, Volatility};
    567
        use datafusion_functions_window_common::field::WindowUDFFieldArgs;
    568
        use datafusion_functions_window_common::partition::PartitionEvaluatorArgs;
    569
        use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
    570
        use std::any::Any;
    571
        use std::cmp::Ordering;
    572
        use std::hash::{DefaultHasher, Hash, Hasher};
    573
        use std::sync::Arc;
    574
    575
        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    576
        struct AWindowUDF {
    577
            signature: Signature,
    578
        }
    579
    580
        impl AWindowUDF {
    581
            fn new() -> Self {
    582
                Self {
    583
                    signature: Signature::uniform(
    584
                        1,
    585
                        vec![DataType::Int32],
    586
                        Volatility::Immutable,
    587
                    ),
    588
                }
    589
            }
    590
        }
    591
    592
        /// Implement the WindowUDFImpl trait for AddOne
    593
        impl WindowUDFImpl for AWindowUDF {
    594
            fn as_any(&self) -> &dyn Any {
    595
                self
    596
            }
    597
            fn name(&self) -> &str {
    598
                "a"
    599
            }
    600
            fn signature(&self) -> &Signature {
    601
                &self.signature
    602
            }
    603
            fn partition_evaluator(
    604
                &self,
    605
                _partition_evaluator_args: PartitionEvaluatorArgs,
    606
            ) -> Result<Box<dyn PartitionEvaluator>> {
    607
                unimplemented!()
    608
            }
    609
            fn field(&self, _field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
    610
                unimplemented!()
    611
            }
    612
    613
            fn limit_effect(&self, _args: &[Arc<dyn PhysicalExpr>]) -> LimitEffect {
    614
                LimitEffect::Unknown
    615
            }
    616
        }
    617
    618
        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    619
        struct BWindowUDF {
    620
            signature: Signature,
    621
        }
    622
    623
        impl BWindowUDF {
    624
            fn new() -> Self {
    625
                Self {
    626
                    signature: Signature::uniform(
    627
                        1,
    628
                        vec![DataType::Int32],
    629
                        Volatility::Immutable,
    630
                    ),
    631
                }
    632
            }
    633
        }
    634
    635
        /// Implement the WindowUDFImpl trait for AddOne
    636
        impl WindowUDFImpl for BWindowUDF {
    637
            fn as_any(&self) -> &dyn Any {
    638
                self
    639
            }
    640
            fn name(&self) -> &str {
    641
                "b"
    642
            }
    643
            fn signature(&self) -> &Signature {
    644
                &self.signature
    645
            }
    646
            fn partition_evaluator(
    647
                &self,
    648
                _partition_evaluator_args: PartitionEvaluatorArgs,
    649
            ) -> Result<Box<dyn PartitionEvaluator>> {
    650
                unimplemented!()
    651
            }
    652
            fn field(&self, _field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
    653
                unimplemented!()
    654
            }
    655
    656
            fn limit_effect(&self, _args: &[Arc<dyn PhysicalExpr>]) -> LimitEffect {
    657
                LimitEffect::Unknown
    658
            }
    659
        }
    660
    661
        #[test]
    662
        fn test_partial_eq() {
    663
            let a1 = WindowUDF::from(AWindowUDF::new());
    664
            let a2 = WindowUDF::from(AWindowUDF::new());
    665
            let eq = a1 == a2;
    666
            assert!(eq);
    667
            assert_eq!(a1, a2);
    668
            assert_eq!(hash(a1), hash(a2));
    669
        }
    670
    671
        #[test]
    672
        fn test_partial_ord() {
    673
            let a1 = WindowUDF::from(AWindowUDF::new());
    674
            let a2 = WindowUDF::from(AWindowUDF::new());
    675
            assert_eq!(a1.partial_cmp(&a2), Some(Ordering::Equal));
    676
    677
            let b1 = WindowUDF::from(BWindowUDF::new());
    678
            assert!(a1 < b1);
    679
            assert!(!(a1 == b1));
    680
        }
    681
    682
        fn hash<T: Hash>(value: T) -> u64 {
    683
            let hasher = &mut DefaultHasher::new();
    684
            value.hash(hasher);
    685
            hasher.finish()
    686
        }
    687
    }