Skip to main content

datafusion_expr/
higher_order_function.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//! [`HigherOrderUDF`]: User Defined Higher Order Functions
19
20use crate::expr::{
21    HigherOrderFunction, display_comma_separated,
22    schema_name_from_exprs_comma_separated_without_space,
23};
24use crate::type_coercion::functions::value_fields_with_higher_order_udf;
25use crate::udf_eq::UdfEq;
26use crate::{ColumnarValue, Documentation, Expr, ExprSchemable};
27use arrow::array::{ArrayRef, RecordBatch, RecordBatchOptions};
28use arrow::datatypes::{DataType, FieldRef, Schema};
29use arrow_schema::SchemaRef;
30use datafusion_common::config::ConfigOptions;
31use datafusion_common::datatype::FieldExt;
32use datafusion_common::hash_map::EntryRef;
33use datafusion_common::tree_node::{
34    Transformed, TreeNode, TreeNodeContainer, TreeNodeRecursion,
35};
36use datafusion_common::{
37    DFSchema, HashMap, HashSet, Result, ScalarValue, exec_err, internal_datafusion_err,
38    internal_err, not_impl_err, plan_datafusion_err, plan_err,
39};
40use datafusion_expr_common::dyn_eq::{DynEq, DynHash};
41use datafusion_expr_common::signature::Volatility;
42use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
43use std::any::Any;
44use std::cmp::Ordering;
45use std::fmt::Debug;
46use std::hash::{Hash, Hasher};
47use std::mem;
48use std::sync::Arc;
49
50/// The types of arguments for which a function has implementations.
51///
52/// [`HigherOrderTypeSignature`] **DOES NOT** define the types that a user query could call the
53/// function with. DataFusion will automatically coerce (cast) argument types to
54/// one of the supported function signatures, if possible.
55///
56/// # Overview
57/// Functions typically provide implementations for a small number of different
58/// argument [`DataType`]s, rather than all possible combinations. If a user
59/// calls a function with arguments that do not match any of the declared types,
60/// DataFusion will attempt to automatically coerce (add casts to) function
61/// arguments so they match the [`HigherOrderTypeSignature`]. See the [`type_coercion`] module
62/// for more details
63///
64/// [`type_coercion`]: crate::type_coercion
65#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
66pub enum HigherOrderTypeSignature {
67    /// The acceptable signature and coercions rules are special for this
68    /// function.
69    ///
70    /// If this signature is specified,
71    /// DataFusion will call [`HigherOrderUDFImpl::coerce_value_types`] to prepare argument types.
72    UserDefined,
73    /// One or more lambdas or arguments with arbitrary types
74    VariadicAny,
75    /// The specified number of lambdas or arguments with arbitrary types.
76    Any(usize),
77    /// Exactly the specified arguments in the given order, with arbitrary types.
78    /// DataFusion will call [`HigherOrderUDFImpl::coerce_value_types`] to prepare the value
79    /// argument types.
80    Exact(Vec<ValueOrLambda<(), ()>>),
81}
82
83/// Provides information necessary for calling a higher order function.
84///
85/// - [`HigherOrderTypeSignature`] defines the argument types that a function has implementations
86///   for.
87///
88/// - [`Volatility`] defines how the output of the function changes with the input.
89#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
90pub struct HigherOrderSignature {
91    /// The data types that the function accepts. See [HigherOrderTypeSignature] for more information.
92    pub type_signature: HigherOrderTypeSignature,
93    /// The volatility of the function. See [Volatility] for more information.
94    pub volatility: Volatility,
95    /// The max number of times to call [HigherOrderUDFImpl::lambda_parameters] before raising an error.
96    /// Used to guard against implementations that causes an infinite loop by endlessly returning
97    /// [LambdaParametersProgress::Partial]. Defaults to 256
98    pub lambda_parameters_max_iterations: usize,
99}
100
101const LAMBDA_PARAMETERS_MAX_ITERATIONS: usize = 256;
102
103impl HigherOrderSignature {
104    /// Creates a new `HigherOrderSignature` from a given type signature and volatility.
105    pub fn new(type_signature: HigherOrderTypeSignature, volatility: Volatility) -> Self {
106        HigherOrderSignature {
107            type_signature,
108            volatility,
109            lambda_parameters_max_iterations: LAMBDA_PARAMETERS_MAX_ITERATIONS,
110        }
111    }
112
113    /// User-defined coercion rules for the function.
114    pub fn user_defined(volatility: Volatility) -> Self {
115        Self {
116            type_signature: HigherOrderTypeSignature::UserDefined,
117            volatility,
118            lambda_parameters_max_iterations: LAMBDA_PARAMETERS_MAX_ITERATIONS,
119        }
120    }
121
122    /// An arbitrary number of lambdas or arguments of any type.
123    pub fn variadic_any(volatility: Volatility) -> Self {
124        Self {
125            type_signature: HigherOrderTypeSignature::VariadicAny,
126            volatility,
127            lambda_parameters_max_iterations: LAMBDA_PARAMETERS_MAX_ITERATIONS,
128        }
129    }
130
131    /// A specified number of arguments of any type
132    pub fn any(arg_count: usize, volatility: Volatility) -> Self {
133        Self {
134            type_signature: HigherOrderTypeSignature::Any(arg_count),
135            volatility,
136            lambda_parameters_max_iterations: LAMBDA_PARAMETERS_MAX_ITERATIONS,
137        }
138    }
139
140    /// Exactly the specified arguments in the given order, with arbitrary types.
141    /// DataFusion will call [`HigherOrderUDFImpl::coerce_value_types`] to prepare the value
142    /// argument types.
143    ///
144    /// # Example
145    /// A function that takes one value argument followed by one lambda:
146    /// ```
147    /// # use datafusion_expr::{HigherOrderSignature, ValueOrLambda, Volatility};
148    /// let sig = HigherOrderSignature::exact(
149    ///     vec![ValueOrLambda::Value(()), ValueOrLambda::Lambda(())],
150    ///     Volatility::Immutable,
151    /// );
152    /// ```
153    pub fn exact(args: Vec<ValueOrLambda<(), ()>>, volatility: Volatility) -> Self {
154        Self {
155            type_signature: HigherOrderTypeSignature::Exact(args),
156            volatility,
157            lambda_parameters_max_iterations: LAMBDA_PARAMETERS_MAX_ITERATIONS,
158        }
159    }
160}
161
162impl PartialEq for dyn HigherOrderUDFImpl {
163    fn eq(&self, other: &Self) -> bool {
164        self.dyn_eq(other as _)
165    }
166}
167
168impl PartialOrd for dyn HigherOrderUDFImpl {
169    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
170        let mut cmp = self.name().cmp(other.name());
171        if cmp == Ordering::Equal {
172            cmp = self.signature().partial_cmp(other.signature())?;
173        }
174        if cmp == Ordering::Equal {
175            cmp = self.aliases().partial_cmp(other.aliases())?;
176        }
177        // Contract for PartialOrd and PartialEq consistency requires that
178        // a == b if and only if partial_cmp(a, b) == Some(Equal).
179        if cmp == Ordering::Equal && self != other {
180            // Functions may have other properties besides name and signature
181            // that differentiate two instances (e.g. type, or arbitrary parameters).
182            // We cannot return Some(Equal) in such case.
183            return None;
184        }
185        debug_assert!(
186            cmp == Ordering::Equal || self != other,
187            "Detected incorrect implementation of PartialEq when comparing functions: '{}' and '{}'. \
188            The functions compare as equal, but they are not equal based on general properties that \
189            the PartialOrd implementation observes,",
190            self.name(),
191            other.name()
192        );
193        Some(cmp)
194    }
195}
196
197impl Eq for dyn HigherOrderUDFImpl {}
198
199impl Hash for dyn HigherOrderUDFImpl {
200    fn hash<H: Hasher>(&self, state: &mut H) {
201        self.dyn_hash(state)
202    }
203}
204
205/// Arguments passed to [`HigherOrderUDFImpl::invoke_with_args`] when invoking a
206/// higher order function.
207#[derive(Debug, Clone)]
208pub struct HigherOrderFunctionArgs {
209    /// The evaluated arguments and lambdas to the function
210    pub args: Vec<ValueOrLambda<ColumnarValue, LambdaArgument>>,
211    /// Field associated with each arg, if it exists
212    /// For lambdas, it will be the field of the result of
213    /// the lambda if evaluated with the parameters
214    /// returned from [`HigherOrderUDFImpl::lambda_parameters`]
215    pub arg_fields: Vec<ValueOrLambda<FieldRef, FieldRef>>,
216    /// The number of rows in record batch being evaluated
217    pub number_rows: usize,
218    /// The return field of the higher order function returned
219    /// (from `return_field_from_args`) when creating the
220    /// physical expression from the logical expression
221    pub return_field: FieldRef,
222    /// The config options at execution time
223    pub config_options: Arc<ConfigOptions>,
224}
225
226impl HigherOrderFunctionArgs {
227    /// The return type of the function. See [`Self::return_field`] for more
228    /// details.
229    pub fn return_type(&self) -> &DataType {
230        self.return_field.data_type()
231    }
232}
233
234/// A lambda argument to a HigherOrderFunction
235#[derive(Clone, Debug)]
236pub struct LambdaArgument {
237    /// The parameters defined in this lambda
238    ///
239    /// For example, for `array_transform([2], v -> -v)`,
240    /// this will be `vec![Field::new("v", DataType::Int32, true)]`
241    params: Vec<FieldRef>,
242    /// Indices into [`Self::params`] of the parameters that are actually
243    /// referenced by [`Self::body`] (taking nested-lambda shadowing into
244    /// account), in the original declaration order of `params`.
245    ///
246    /// [`Self::evaluate`] only evaluates and pushes the closures whose
247    /// corresponding parameter index appears here, so unused declared
248    /// parameters leave no slot in the merged batch and the body's compressed
249    /// column indices line up directly with what the evaluator built.
250    ///
251    /// Callers who already have a `LambdaExpr` should pass
252    /// `LambdaExpr::used_param_indices()` directly to [`Self::new`] — both
253    /// are indices into the same positionally-aligned `params` list.
254    ///
255    /// Every index here must be `< params.len()`; see the precondition on
256    /// [`Self::new`].
257    ///
258    /// Relies on captures sorting before this lambda's own params in the
259    /// planner's (un-projected) index space, which is what makes
260    /// `captures ++ used_params` below line up with the projected body.
261    used_param_indices: Vec<usize>,
262    /// The body of the lambda
263    ///
264    /// For example, for `array_transform([2], v -> -v)`,
265    /// this will be the physical expression of `-v`
266    body: Arc<dyn PhysicalExpr>,
267    /// Cached schema built from `params`. Reused across every `evaluate` call
268    /// (and across every nested-list iteration when the lambda is called once
269    /// per outer sublist), avoiding the per-call `Schema::new` build that
270    /// includes constructing the internal name -> index map.
271    schema: SchemaRef,
272    /// A RecordBatch containing the captured columns inside this lambda body, if any
273    ///
274    /// For example, for `array_transform([2], v -> v + a + b)`,
275    /// this will be a `RecordBatch` with two columns, `a` and `b`
276    captures: Option<RecordBatch>,
277}
278
279impl LambdaArgument {
280    /// # Preconditions
281    ///
282    /// Every index in `used_param_indices` must be `< params.len()`;
283    /// violating this panics on out-of-bounds indexing below. Callers should
284    /// pass `LambdaExpr::used_param_indices()`, which always indexes into the
285    /// same `params` list, rather than constructing indices by hand.
286    pub fn new(
287        params: Vec<FieldRef>,
288        body: Arc<dyn PhysicalExpr>,
289        captures: Option<RecordBatch>,
290        used_param_indices: &[usize],
291    ) -> Self {
292        debug_assert!(
293            used_param_indices.iter().all(|i| *i < params.len()),
294            "used_param_indices contains an index out of bounds for params \
295             (len {}): {:?}",
296            params.len(),
297            used_param_indices
298        );
299
300        let used_param_indices = used_param_indices.to_vec();
301        let effective_params = used_param_indices.iter().map(|i| Arc::clone(&params[*i]));
302
303        let fields: Vec<FieldRef> = match &captures {
304            Some(batch) => batch
305                .schema_ref()
306                .fields()
307                .iter()
308                .cloned()
309                .chain(effective_params)
310                .collect(),
311            None => effective_params.collect(),
312        };
313
314        let schema = Arc::new(Schema::new(fields));
315
316        Self {
317            params,
318            used_param_indices,
319            body,
320            schema,
321            captures,
322        }
323    }
324
325    /// Evaluate this lambda
326    /// `args` should evaluate to the value of each parameter
327    /// of the correspondent lambda returned in [HigherOrderUDFImpl::lambda_parameters].
328    ///
329    /// Only the closures in `args` for parameters the lambda body actually
330    /// references are called; closures for declared-but-unused parameters
331    /// are skipped entirely. Callers should not rely on every closure in
332    /// `args` being invoked.
333    ///
334    /// `spread_captures` is responsible for transforming the captured column arrays
335    /// so they align with the evaluation batch. Captures are snapshotted from the
336    /// outer batch at construction time, giving one value per outer row, but the
337    /// function may evaluate the lambda body over a batch with a different number
338    /// of rows. It is the function's responsibility to provide the appropriate
339    /// `spread_captures` closure to expand (or otherwise reshape) the captures
340    /// to match.
341    ///
342    /// Taking as an example the following table:
343    ///
344    /// ```sql
345    /// CREATE TABLE t (arr INT[], a INT) AS VALUES
346    ///   ([1, 2, 3], 10),
347    ///   ([],        20),
348    ///   ([4],       30);
349    /// ```
350    ///
351    /// `SELECT array_transform(arr, v -> v + a) from t` would execute over three outer rows:
352    ///
353    /// ```text
354    /// arr (ListArray):  [[1, 2, 3], [], [4]]   -- 3 outer rows, 4 total elements
355    /// a   (captured):   [10,        20,  30]   -- one value per outer row
356    /// ```
357    ///
358    /// `array_transform` flattens the list elements into a single batch of 4 rows,
359    /// so `spread_captures` must repeat/drop captured values to match:
360    ///
361    /// ```text
362    /// v (flattened args): [1,  2,  3,  4]
363    /// a (spread):         [10, 10, 10, 30]  -- 10 repeated for 3 elements in row 0,
364    ///                                        -- 20 dropped for the empty sublist in row 1,
365    ///                                        -- 30 once for the single element in row 2
366    /// ```
367    ///
368    /// The lambda body `v + a` then evaluates element-wise over these 4-row arrays,
369    /// producing `[11, 12, 13, 34]`, which `array_transform` reassembles into `[[11, 12, 13], [], [34]]`.
370    ///
371    /// If the lambda has no captures, `spread_captures` is never called.
372    pub fn evaluate(
373        &self,
374        args: &[&dyn Fn() -> Result<ArrayRef>],
375        spread_captures: impl FnOnce(&[ArrayRef]) -> Result<Vec<ArrayRef>>,
376    ) -> Result<ColumnarValue> {
377        let spread_captures = self
378            .captures
379            .as_ref()
380            .map(|captures| {
381                let spread_columns = spread_captures(captures.columns())?;
382
383                RecordBatch::try_new(captures.schema(), spread_columns)
384            })
385            .transpose()?;
386
387        let merged = merge_captures_with_variables(
388            spread_captures.as_ref(),
389            Arc::clone(&self.schema),
390            &self.params,
391            &self.used_param_indices,
392            args,
393        )?;
394
395        self.body.evaluate(&merged)
396    }
397}
398
399fn merge_captures_with_variables(
400    captures: Option<&RecordBatch>,
401    schema: SchemaRef,
402    params: &[FieldRef],
403    used_param_indices: &[usize],
404    variables: &[&dyn Fn() -> Result<ArrayRef>],
405) -> Result<RecordBatch> {
406    if variables.len() < params.len() {
407        return exec_err!(
408            "expected at least {} lambda arguments to merge with captures, got {}",
409            params.len(),
410            variables.len()
411        );
412    }
413
414    let push_param_arrays = |columns: &mut Vec<ArrayRef>| -> Result<()> {
415        for &i in used_param_indices {
416            columns.push(variables[i]()?);
417        }
418        Ok(())
419    };
420
421    let columns = match captures {
422        Some(captures) => {
423            let mut columns = captures.columns().to_vec();
424            push_param_arrays(&mut columns)?;
425            columns
426        }
427        None => {
428            let mut columns = Vec::with_capacity(used_param_indices.len());
429            push_param_arrays(&mut columns)?;
430            columns
431        }
432    };
433
434    if columns.is_empty() {
435        // No columns to derive a row count from, so borrow one variable's
436        // array length instead (all variables have the same length).
437        let row_count = variables.first().ok_or_else(|| {
438            internal_datafusion_err!(
439                "merge_captures_with_variables: no variables to derive a row count from"
440            )
441        })?()?
442        .len();
443        return Ok(RecordBatch::try_new_with_options(
444            schema,
445            vec![],
446            &RecordBatchOptions::new().with_row_count(Some(row_count)),
447        )?);
448    }
449
450    Ok(RecordBatch::try_new(schema, columns)?)
451}
452
453/// Information about arguments passed to the function
454///
455/// This structure contains metadata about how the function was called
456/// such as the type of the arguments, any scalar arguments and if the
457/// arguments can (ever) be null
458///
459/// See [`HigherOrderUDFImpl::return_field_from_args`] for more information
460#[derive(Clone, Debug)]
461pub struct HigherOrderReturnFieldArgs<'a> {
462    /// The data types of the arguments to the function
463    ///
464    /// If argument `i` to the function is a lambda, it will be the field of the result of the
465    /// lambda if evaluated with the parameters returned from [`HigherOrderUDFImpl::lambda_parameters`]
466    ///
467    /// For example, with `array_transform([1], v -> v == 5)`
468    /// this field will be
469    /// ```ignore
470    /// [
471    ///     ValueOrLambda::Value(Field::new("", DataType::new_list(DataType::Int32, true), true)),
472    ///     ValueOrLambda::Lambda(Field::new("", DataType::Boolean, true))
473    /// ]
474    /// ```
475    pub arg_fields: &'a [ValueOrLambda<FieldRef, FieldRef>],
476    /// Is argument `i` to the function a scalar (constant)?
477    ///
478    /// If the argument `i` is not a scalar, it will be None
479    ///
480    /// For example, if a function is called like `array_transform([1], v -> v == 5)`
481    /// this field will be `[Some(ScalarValue::List(...), None]`
482    pub scalar_arguments: &'a [Option<&'a ScalarValue>],
483}
484
485/// An argument to a higher order function
486#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Hash)]
487pub enum ValueOrLambda<V, L> {
488    /// A value with associated data
489    Value(V),
490    /// A lambda with associated data
491    Lambda(L),
492}
493
494/// Represents a step during the resolution of the parameters of all lambdas of a given
495/// higher-order function via [HigherOrderUDFImpl::lambda_parameters]. It's valid that the
496/// fields of a given lambda changes between steps, and is up to the implementation to
497/// provide during the function evaluation the parameters that matches the fields returned
498/// at the [LambdaParametersProgress::Complete] step. See [HigherOrderUDFImpl::lambda_parameters]
499/// docs for more details
500pub enum LambdaParametersProgress {
501    /// The parameters of some lambdas are unknown due to a dependency on another lambda output field
502    /// or are placeholders due to a dependency on it's own output field. It's perfectly valid to
503    /// contain only `Some`'s and not a single `None`, representing lambdas that depends only on itself
504    /// and not on others. [HigherOrderUDFImpl::lambda_parameters] will be called again with the output
505    /// field of all lambdas with known parameters.
506    Partial(Vec<Option<Vec<FieldRef>>>),
507    /// There are no unmet dependencies and all parameters are known, [HigherOrderUDFImpl::lambda_parameters]
508    /// will not be called again
509    Complete(Vec<Vec<FieldRef>>),
510}
511
512/// Trait for implementing user defined higher order functions.
513///
514/// This trait exposes the full API for implementing user defined functions and
515/// can be used to implement any function.
516///
517/// New higher order functions typically implement this trait and are then
518/// wrapped in a [`HigherOrderUDF`] for registration with DataFusion.
519///
520/// See [`array_transform.rs`] for a commented complete implementation
521///
522/// [`array_transform.rs`]: https://github.com/apache/datafusion/blob/main/datafusion/functions-nested/src/array_transform.rs
523pub trait HigherOrderUDFImpl: Debug + DynEq + DynHash + Send + Sync + Any {
524    /// Returns this function's name
525    fn name(&self) -> &str;
526
527    /// Returns any aliases (alternate names) for this function.
528    ///
529    /// Aliases can be used to invoke the same function using different names.
530    /// For example in some databases `now()` and `current_timestamp()` are
531    /// aliases for the same function. This behavior can be obtained by
532    /// returning `current_timestamp` as an alias for the `now` function.
533    ///
534    /// Note: `aliases` should only include names other than [`Self::name`].
535    /// Defaults to `[]` (no aliases)
536    fn aliases(&self) -> &[String] {
537        &[]
538    }
539
540    /// Returns the name of the column this expression would create
541    ///
542    /// See [`Expr::schema_name`] for details
543    fn schema_name(&self, args: &[Expr]) -> Result<String> {
544        Ok(format!(
545            "{}({})",
546            self.name(),
547            schema_name_from_exprs_comma_separated_without_space(args)?
548        ))
549    }
550
551    /// Returns a [`HigherOrderSignature`] describing the argument types for which this
552    /// function has an implementation, and the function's [`Volatility`].
553    ///
554    /// See [`HigherOrderSignature`] for more details on argument type handling
555    /// and [`Self::return_field_from_args`] for computing the return type.
556    ///
557    /// [`Volatility`]: datafusion_expr_common::signature::Volatility
558    fn signature(&self) -> &HigherOrderSignature;
559
560    /// Return the field of all the parameters supported by the lambdas in `fields`.
561    /// If a lambda support multiple parameters, all should be returned, regardless of
562    /// whether they are used or not on a particular invocation
563    ///
564    /// Tip: If you have a [`HigherOrderFunction`] invocation, you can call the helper
565    /// [`HigherOrderFunction::lambda_parameters`] instead of this method directly
566    ///
567    /// The name of the returned fields are ignored.
568    ///
569    /// This function is repeatedelly called until [LambdaParametersProgress::Complete] is returned, with
570    /// `step` increased by one at each invocation, starting at 0.
571    ///
572    /// For functions which all lambda parameters depend only on the field of it's value arguments,
573    /// this can return [LambdaParametersProgress::Complete] at step 0. Taking as an example a strict
574    /// array_reduce with the signature `(arr: [V], initial_value: I, (I, V) -> I, (I) -> O) -> O`, which
575    /// requires it's initial value to be the exact same type of it's merge output, which is also the
576    /// parameter of it's finish lambda, the expression
577    ///
578    /// `array_reduce([1.2, 2.1], 0.0, (acc, v) -> acc + v + 1.5, v -> v > 5.1)`
579    ///
580    ///  would result in this function being called as the following:
581    ///
582    /// ```ignore
583    /// let lambda_parameters = array_reduce.lambda_parameters(
584    ///     0,
585    ///     &[
586    ///         // the Field of the literal `[1.2, 2.1]`, the array being reduced
587    ///         ValueOrLambda::Value(Arc::new(Field::new("", DataType::new_list(DataType::Float32, true), true))),
588    ///         // the Field of the literal `0.0`, the initial value
589    ///         ValueOrLambda::Value(Arc::new(Field::new("", DataType::Float32, true))),
590    ///         // the Field of the output of the merge lambda, which is unknown at this point because it depends
591    ///         // on the return of this call
592    ///         ValueOrLambda::Lambda(None),
593    ///         // the Field of the output of the finish lambda, unknown for the same reason as above
594    ///         ValueOrLambda::Lambda(None),
595    /// ])?;
596    ///
597    /// assert_eq!(
598    ///      lambda_parameters,
599    ///      LambdaParametersProgress::Complete(vec![
600    ///         // the finish lambda supported parameters, regardless of how many are actually used
601    ///         vec![
602    ///             // the accumulator which is the field of the initial value
603    ///             Arc::new(Field::new("ignored_name", DataType::Float32, true)),
604    ///             // the array values being reduced
605    ///             Arc::new(Field::new("", DataType::Float32, true)),
606    ///         ],
607    ///         // the merge lambda supported parameters
608    ///         vec![
609    ///             // the reduced value which is the field of the initial value
610    ///             Arc::new(Field::new("ignored_name", DataType::Float32, true)),
611    ///         ],
612    ///      ])
613    /// );
614    /// ```
615    ///
616    /// For functions which lambda parameters depends on the output of other lambdas, or on their own lambda,
617    /// this can return [LambdaParametersProgress::Partial] until all dependencies are met. Note that for
618    /// lambda with cyclic dependencies, you likely want to use [HigherOrderUDFImpl::coerce_values_for_lambdas] too.
619    /// Take as an example a flexible array_reduce with the signature `(arr: [V], initial_value: I, (ACC, V) -> ACC, (ACC) -> O) -> O`.
620    /// It has a cyclic dependency in the merge lambda, and a dependency of the finish lambda in the merge lambda,
621    /// and only requires the initial value to be *coercible* to the output of the merge lambda, which is defined by
622    /// it's [HigherOrderUDFImpl::coerce_values_for_lambdas] implementation. The expression
623    ///
624    /// `array_reduce([1.2, 2.1], 0, (acc, v) -> acc + v + 1.5, v -> v > 5.1)`
625    ///
626    /// would result in this function being called as the following:
627    ///
628    /// ```ignore
629    /// let lambda_parameters = array_reduce.lambda_parameters(
630    ///     0,
631    ///     &[
632    ///         // the Field of the literal `[1.2, 2.1]`, the array being reduced
633    ///         ValueOrLambda::Value(Arc::new(Field::new("", DataType::new_list(DataType::Float32, true), true))),
634    ///         // the Field of the literal `0`, the initial value
635    ///         ValueOrLambda::Value(Arc::new(Field::new("", DataType::Int32, true))),
636    ///         // the Field of the output of the merge lambda, which is unknown at this point because it depends on
637    ///         // the return this call
638    ///         ValueOrLambda::Lambda(None),
639    ///         // the Field of the output of the finish lambda, unknown for the same reason as above
640    ///         ValueOrLambda::Lambda(None),
641    /// ])?;
642    ///
643    /// assert_eq!(
644    ///      lambda_parameters,
645    ///      LambdaParametersProgress::Partial(vec![
646    ///         // the finish lambda supported parameters, regardless of how many are actually used
647    ///         Some(vec![
648    ///             // at step 0, use the field of the initial value
649    ///             Arc::new(Field::new("ignored_name", DataType::Int32, true)),
650    ///             // the array values being reduced
651    ///             Arc::new(Field::new("", DataType::Float32, true)),
652    ///         ]),
653    ///         // the merge lambda supported parameters, unknown at this point due to dependency on the merge output
654    ///         None,
655    ///      ])
656    /// );
657    ///
658    /// let lambda_parameters = array_reduce.lambda_parameters(
659    ///     1,
660    ///     &[
661    ///         // the Field of the literal `[1.2, 2.1]`, the array being reduced
662    ///         ValueOrLambda::Value(Arc::new(Field::new("", DataType::new_list(DataType::Float32, true), true))),
663    ///         // the Field of the literal `0`, the initial value
664    ///         ValueOrLambda::Value(Arc::new(Field::new("", DataType::Int32, true))),
665    ///         // the Field of the output of the merge lambda, which could be inferred to be a Float32 based on the
666    ///         // returned values of the previous step
667    ///         ValueOrLambda::Value(Arc::new(Field::new("", DataType::Float32, true))),
668    ///         // the Field of the output of the finish lambda, which is unknown at this point because it depends
669    ///         // on the return of this call
670    ///         ValueOrLambda::Lambda(None),
671    /// ])?;
672    ///
673    /// assert_eq!(
674    ///      lambda_parameters,
675    ///      LambdaParametersProgress::Complete(vec![
676    ///         // the finish lambda supported parameters, regardless of how many are actually used
677    ///         vec![
678    ///             // the finish lambda own output now used as it's accumulator
679    ///             Arc::new(Field::new("ignored_name", DataType::Float32, true)),
680    ///             // the array values being reduced
681    ///             Arc::new(Field::new("", DataType::Float32, true)),
682    ///         ],
683    ///         // the merge lambda supported parameters, which is the output of the merge lambda,
684    ///         vec![
685    ///             // the output of the merge lambda
686    ///             Arc::new(Field::new("", DataType::Float32, true)),
687    ///         ],
688    ///      ])
689    /// );
690    ///
691    /// let coerce_to = array_reduce.coerce_values_for_lambdas(&[
692    ///     // the literal `[1.2, 2.1]` data type, the array being reduced
693    ///     ValueOrLambda::Value(DataType::new_list(DataType::Float32, true)),
694    ///     // the literal `0` data type, the initial value
695    ///     ValueOrLambda::Value(DataType::Int32),
696    ///     // the output data type of the merge lambda
697    ///     ValueOrLambda::Lambda(DataType::Float32),
698    ///     // the output data type of the finish lambda
699    ///     ValueOrLambda::Lambda(DataType::Boolean),
700    /// ])?;
701    ///
702    /// assert_eq!(
703    ///     coerce_to,
704    ///     Some(vec![
705    ///         // return the same type for the array being reduced
706    ///         DataType::new_list(DataType::Float32, true),
707    ///         // coerce the initial value to the output of the merge lambda
708    ///         DataType::Float32,
709    ///     ])
710    /// );
711    ///
712    /// ```
713    ///
714    /// Note this may also be called at step 0 with all lambda outputs already set, and in that case,
715    /// [LambdaParametersProgress::Complete] must be returned
716    ///
717    /// The implementation can assume that some other part of the code has coerced
718    /// the actual argument types to match [`Self::signature`], except the coercion defined by
719    /// [Self::coerce_values_for_lambdas].
720    ///
721    /// [`HigherOrderFunction`]: crate::expr::HigherOrderFunction
722    /// [`HigherOrderFunction::lambda_parameters`]: crate::expr::HigherOrderFunction::lambda_parameters
723    fn lambda_parameters(
724        &self,
725        step: usize,
726        fields: &[ValueOrLambda<FieldRef, Option<FieldRef>>],
727    ) -> Result<LambdaParametersProgress>;
728
729    /// Coerce value arguments of a function call to types that the function can evaluate also taking into
730    /// account the *output type of it's lambdas*. This differs from [HigherOrderUDFImpl::coerce_value_types]
731    /// that only has access to the type of it's value arguments because it's called before the output type
732    /// of lambdas are known.
733    ///
734    /// See the [type coercion module](crate::type_coercion)
735    /// documentation for more details on type coercion
736    ///
737    /// # Parameters
738    /// * `fields`: The argument types of the value arguments of this function, or the output type of lambdas
739    ///
740    /// # Return value
741    /// If `Some`, contains a Vec with the same number of [ValueOrLambda::Value] in `fields`.
742    /// DataFusion will `CAST` the function call arguments to these specific types. If `None`, no
743    /// coercion will be applied beyond the one defined by the function signature.
744    ///
745    /// For example, a flexible array_reduce implementation (see [Self::lambda_parameters] docs), when working
746    /// with the expression below, may want to coerce it's initial value argument, the *integer* `0`,
747    /// to match the output of it's merge function, which is a *float*:
748    ///
749    /// `array_reduce([1.2, 2.1], 0, (acc, v) -> acc + v + 1.5, v -> v > 2.0)`
750    fn coerce_values_for_lambdas(
751        &self,
752        _fields: &[ValueOrLambda<DataType, DataType>],
753    ) -> Result<Option<Vec<DataType>>> {
754        Ok(None)
755    }
756
757    /// What type will be returned by this function, given the arguments?
758    ///
759    /// The implementation can assume that some other part of the code has coerced
760    /// the actual argument types to match [`Self::signature`], including the coercion
761    /// defined by [Self::coerce_values_for_lambdas].
762    ///
763    /// # Example creating `Field`
764    ///
765    /// Note the name of the `Field` is ignored, except for structured types such as
766    /// `DataType::Struct`.
767    ///
768    /// ```rust
769    /// # use std::sync::Arc;
770    /// # use arrow::datatypes::{DataType, Field, FieldRef};
771    /// # use datafusion_common::Result;
772    /// # use datafusion_expr::HigherOrderReturnFieldArgs;
773    /// # struct Example{}
774    /// # impl Example {
775    /// fn return_field_from_args(&self, args: HigherOrderReturnFieldArgs) -> Result<FieldRef> {
776    ///     let field = Arc::new(Field::new("ignored_name", DataType::Int32, true));
777    ///     Ok(field)
778    /// }
779    /// # }
780    /// ```
781    fn return_field_from_args(
782        &self,
783        args: HigherOrderReturnFieldArgs,
784    ) -> Result<FieldRef>;
785
786    /// Whether List or LargeList arguments should have it's non-empty null
787    /// sublists cleaned with [remove_list_null_values] before invoking this function
788    ///
789    /// The default implementation always returns true and should only be implemented
790    /// if you want to handle non-empty null sublists yourself
791    ///
792    /// [remove_list_null_values]: datafusion_common::utils::remove_list_null_values
793    // todo: extend this to listview and maps when remove_list_null_values supports it
794    fn clear_null_values(&self) -> bool {
795        true
796    }
797
798    /// Invoke the function returning the appropriate result.
799    ///
800    /// # Performance
801    ///
802    /// For the best performance, the implementations should handle the common case
803    /// when one or more of their arguments are constant values (aka
804    /// [`ColumnarValue::Scalar`]).
805    ///
806    /// [`ColumnarValue::values_to_arrays`] can be used to convert the arguments
807    /// to arrays, which will likely be simpler code, but be slower.
808    fn invoke_with_args(&self, args: HigherOrderFunctionArgs) -> Result<ColumnarValue>;
809
810    /// Returns true if some of this `exprs` subexpressions may not be evaluated
811    /// and thus any side effects (like divide by zero) may not be encountered.
812    ///
813    /// Setting this to true prevents certain optimizations such as common
814    /// subexpression elimination
815    ///
816    /// When overriding this function to return `true`, [HigherOrderUDFImpl::conditional_arguments] can also be
817    /// overridden to report more accurately which arguments are eagerly evaluated and which ones
818    /// lazily.
819    fn short_circuits(&self) -> bool {
820        false
821    }
822
823    /// Determines which of the arguments passed to *this higher-order function*
824    /// are evaluated eagerly and which may be evaluated lazily. Note that this
825    /// does *not* applies to the arguments that *lambda functions* pass to it's
826    /// body expression
827    ///
828    /// If this function returns `None`, all arguments are eagerly evaluated.
829    /// Returning `None` is a micro optimization that saves a needless `Vec`
830    /// allocation.
831    ///
832    /// If the function returns `Some`, returns (`eager`, `lazy`) where `eager`
833    /// are the arguments that are always evaluated, and `lazy` are the
834    /// arguments that may be evaluated lazily (i.e. may not be evaluated at all
835    /// in some cases).
836    ///
837    /// Implementations must ensure that the two returned `Vec`s are disjunct,
838    /// and that each argument from `args` is present in one the two `Vec`s.
839    ///
840    /// When overriding this function, [HigherOrderUDFImpl::short_circuits] must
841    /// be overridden to return `true`.
842    fn conditional_arguments<'a>(
843        &self,
844        args: &'a [Expr],
845    ) -> Option<(Vec<&'a Expr>, Vec<&'a Expr>)> {
846        if self.short_circuits() {
847            Some((vec![], args.iter().collect()))
848        } else {
849            None
850        }
851    }
852
853    /// Coerce value arguments of a function call to types that the function can evaluate.
854    /// Note that if you need to coerce values based on the output type of lambdas, you
855    /// must use [HigherOrderUDFImpl::coerce_values_for_lambdas], as this function is used before
856    /// the output type of lambdas are known
857    ///
858    /// See the [type coercion module](crate::type_coercion)
859    /// documentation for more details on type coercion
860    ///
861    /// For example, if your function requires a contiguous list argument, but the user calls
862    /// it like `my_func(c, v -> v+2)` (i.e. with `c` as a ListView), coerce_types can return `[DataType::List(..)]`
863    /// to ensure the argument is converted to a List
864    ///
865    /// # Parameters
866    /// * `arg_types`: The argument types of the value arguments of this function, excluding lambdas
867    ///
868    /// # Return value
869    /// A Vec the same length as `arg_types`. DataFusion will `CAST` the function call
870    /// arguments to these specific types.
871    fn coerce_value_types(&self, _arg_types: &[DataType]) -> Result<Vec<DataType>> {
872        not_impl_err!(
873            "Function {} does not implement coerce_value_types",
874            self.name()
875        )
876    }
877
878    /// Returns the documentation for this function.
879    ///
880    /// Documentation can be accessed programmatically as well as generating
881    /// publicly facing documentation.
882    fn documentation(&self) -> Option<&Documentation> {
883        None
884    }
885}
886
887/// Logical representation of a Higher Order User Defined Function.
888///
889/// A higher order function takes one or more lambda arguments in addition to
890/// regular value arguments. This struct contains the information DataFusion
891/// needs to plan and invoke functions you supply such as name, type signature,
892/// return type, and actual implementation.
893#[derive(Debug, Clone)]
894pub struct HigherOrderUDF {
895    inner: Arc<dyn HigherOrderUDFImpl>,
896}
897
898impl PartialEq for HigherOrderUDF {
899    fn eq(&self, other: &Self) -> bool {
900        self.inner.as_ref().dyn_eq(other.inner.as_ref())
901    }
902}
903
904impl PartialOrd for HigherOrderUDF {
905    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
906        let mut cmp = self.name().cmp(other.name());
907        if cmp == Ordering::Equal {
908            cmp = self.signature().partial_cmp(other.signature())?;
909        }
910        if cmp == Ordering::Equal {
911            cmp = self.aliases().partial_cmp(other.aliases())?;
912        }
913        // Contract for PartialOrd and PartialEq consistency requires that
914        // a == b if and only if partial_cmp(a, b) == Some(Equal).
915        if cmp == Ordering::Equal && self != other {
916            // Functions may have other properties besides name and signature
917            // that differentiate two instances (e.g. type, or arbitrary parameters).
918            // We cannot return Some(Equal) in such case.
919            return None;
920        }
921        debug_assert!(
922            cmp == Ordering::Equal || self != other,
923            "Detected incorrect implementation of PartialEq when comparing functions: '{}' and '{}'. \
924            The functions compare as equal, but they are not equal based on general properties that \
925            the PartialOrd implementation observes,",
926            self.name(),
927            other.name()
928        );
929        Some(cmp)
930    }
931}
932
933impl Eq for HigherOrderUDF {}
934
935impl Hash for HigherOrderUDF {
936    fn hash<H: Hasher>(&self, state: &mut H) {
937        self.inner.dyn_hash(state)
938    }
939}
940
941impl HigherOrderUDF {
942    /// Create a new `HigherOrderUDF` from a [`HigherOrderUDFImpl`] trait object.
943    ///
944    /// Note this is the same as using the `From` impl (`HigherOrderUDF::from`).
945    pub fn new_from_impl<F>(fun: F) -> HigherOrderUDF
946    where
947        F: HigherOrderUDFImpl + 'static,
948    {
949        Self::new_from_shared_impl(Arc::new(fun))
950    }
951
952    /// Create a new `HigherOrderUDF` from a shared [`HigherOrderUDFImpl`] trait object.
953    pub fn new_from_shared_impl(fun: Arc<dyn HigherOrderUDFImpl>) -> HigherOrderUDF {
954        Self { inner: fun }
955    }
956
957    /// Return the underlying [`HigherOrderUDFImpl`] trait object for this function.
958    pub fn inner(&self) -> &Arc<dyn HigherOrderUDFImpl> {
959        &self.inner
960    }
961
962    /// Adds additional names that can be used to invoke this function, in
963    /// addition to `name`.
964    ///
965    /// If you implement [`HigherOrderUDFImpl`] directly you should return aliases
966    /// directly.
967    pub fn with_aliases(self, aliases: impl IntoIterator<Item = &'static str>) -> Self {
968        Self::new_from_impl(AliasedHigherOrderUDFImpl::new(
969            Arc::clone(&self.inner),
970            aliases,
971        ))
972    }
973
974    /// Returns this function's name.
975    ///
976    /// See [`HigherOrderUDFImpl::name`] for more details.
977    pub fn name(&self) -> &str {
978        self.inner.name()
979    }
980
981    /// Returns the aliases for this function.
982    ///
983    /// See [`HigherOrderUDF::with_aliases`] for more details.
984    pub fn aliases(&self) -> &[String] {
985        self.inner.aliases()
986    }
987
988    /// Returns this function's schema_name.
989    ///
990    /// See [`HigherOrderUDFImpl::schema_name`] for more details.
991    pub fn schema_name(&self, args: &[Expr]) -> Result<String> {
992        self.inner.schema_name(args)
993    }
994
995    /// Returns this function's [`HigherOrderSignature`].
996    pub fn signature(&self) -> &HigherOrderSignature {
997        self.inner.signature()
998    }
999
1000    /// Returns the parameters of all lambdas of this function for the current step.
1001    ///
1002    /// See [`HigherOrderUDFImpl::lambda_parameters`] for more details.
1003    pub fn lambda_parameters(
1004        &self,
1005        step: usize,
1006        fields: &[ValueOrLambda<FieldRef, Option<FieldRef>>],
1007    ) -> Result<LambdaParametersProgress> {
1008        self.inner.lambda_parameters(step, fields)
1009    }
1010
1011    /// Coerce value arguments based on lambda output types.
1012    ///
1013    /// See [`HigherOrderUDFImpl::coerce_values_for_lambdas`] for more details.
1014    pub fn coerce_values_for_lambdas(
1015        &self,
1016        fields: &[ValueOrLambda<DataType, DataType>],
1017    ) -> Result<Option<Vec<DataType>>> {
1018        self.inner.coerce_values_for_lambdas(fields)
1019    }
1020
1021    /// Returns the return field of the function given its arguments.
1022    ///
1023    /// See [`HigherOrderUDFImpl::return_field_from_args`] for more details.
1024    pub fn return_field_from_args(
1025        &self,
1026        args: HigherOrderReturnFieldArgs,
1027    ) -> Result<FieldRef> {
1028        self.inner.return_field_from_args(args)
1029    }
1030
1031    /// Whether List or LargeList arguments should have non-empty null sublists
1032    /// cleaned before invoking this function.
1033    pub fn clear_null_values(&self) -> bool {
1034        self.inner.clear_null_values()
1035    }
1036
1037    /// Invoke the function returning the appropriate result.
1038    ///
1039    /// See [`HigherOrderUDFImpl::invoke_with_args`] for more details.
1040    pub fn invoke_with_args(
1041        &self,
1042        args: HigherOrderFunctionArgs,
1043    ) -> Result<ColumnarValue> {
1044        self.inner.invoke_with_args(args)
1045    }
1046
1047    /// Returns true if some of this function's subexpressions may not be evaluated.
1048    ///
1049    /// See [`HigherOrderUDFImpl::short_circuits`] for more details.
1050    pub fn short_circuits(&self) -> bool {
1051        self.inner.short_circuits()
1052    }
1053
1054    /// Returns which arguments are evaluated eagerly vs lazily.
1055    ///
1056    /// See [`HigherOrderUDFImpl::conditional_arguments`] for more details.
1057    pub fn conditional_arguments<'a>(
1058        &self,
1059        args: &'a [Expr],
1060    ) -> Option<(Vec<&'a Expr>, Vec<&'a Expr>)> {
1061        self.inner.conditional_arguments(args)
1062    }
1063
1064    /// Coerce value arguments of a function call to types that the function can evaluate.
1065    ///
1066    /// See [`HigherOrderUDFImpl::coerce_value_types`] for more details.
1067    pub fn coerce_value_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
1068        self.inner.coerce_value_types(arg_types)
1069    }
1070
1071    /// Returns the documentation for this function, if any.
1072    pub fn documentation(&self) -> Option<&Documentation> {
1073        self.inner.documentation()
1074    }
1075}
1076
1077impl<F> From<F> for HigherOrderUDF
1078where
1079    F: HigherOrderUDFImpl + 'static,
1080{
1081    fn from(fun: F) -> Self {
1082        Self::new_from_impl(fun)
1083    }
1084}
1085
1086/// `HigherOrderUDFImpl` that adds aliases to the underlying function. It is
1087/// better to implement [`HigherOrderUDFImpl`], which supports aliases, directly
1088/// if possible.
1089#[derive(Debug, PartialEq, Eq, Hash)]
1090struct AliasedHigherOrderUDFImpl {
1091    inner: UdfEq<Arc<dyn HigherOrderUDFImpl>>,
1092    aliases: Vec<String>,
1093}
1094
1095impl AliasedHigherOrderUDFImpl {
1096    fn new(
1097        inner: Arc<dyn HigherOrderUDFImpl>,
1098        new_aliases: impl IntoIterator<Item = &'static str>,
1099    ) -> Self {
1100        let mut aliases = inner.aliases().to_vec();
1101        aliases.extend(new_aliases.into_iter().map(|s| s.to_string()));
1102        Self {
1103            inner: inner.into(),
1104            aliases,
1105        }
1106    }
1107}
1108
1109#[warn(clippy::missing_trait_methods)] // Delegates, so it should implement every single trait method
1110impl HigherOrderUDFImpl for AliasedHigherOrderUDFImpl {
1111    fn name(&self) -> &str {
1112        self.inner.name()
1113    }
1114
1115    fn aliases(&self) -> &[String] {
1116        &self.aliases
1117    }
1118
1119    fn schema_name(&self, args: &[Expr]) -> Result<String> {
1120        self.inner.schema_name(args)
1121    }
1122
1123    fn signature(&self) -> &HigherOrderSignature {
1124        self.inner.signature()
1125    }
1126
1127    fn lambda_parameters(
1128        &self,
1129        step: usize,
1130        fields: &[ValueOrLambda<FieldRef, Option<FieldRef>>],
1131    ) -> Result<LambdaParametersProgress> {
1132        self.inner.lambda_parameters(step, fields)
1133    }
1134
1135    fn coerce_values_for_lambdas(
1136        &self,
1137        fields: &[ValueOrLambda<DataType, DataType>],
1138    ) -> Result<Option<Vec<DataType>>> {
1139        self.inner.coerce_values_for_lambdas(fields)
1140    }
1141
1142    fn return_field_from_args(
1143        &self,
1144        args: HigherOrderReturnFieldArgs,
1145    ) -> Result<FieldRef> {
1146        self.inner.return_field_from_args(args)
1147    }
1148
1149    fn clear_null_values(&self) -> bool {
1150        self.inner.clear_null_values()
1151    }
1152
1153    fn invoke_with_args(&self, args: HigherOrderFunctionArgs) -> Result<ColumnarValue> {
1154        self.inner.invoke_with_args(args)
1155    }
1156
1157    fn short_circuits(&self) -> bool {
1158        self.inner.short_circuits()
1159    }
1160
1161    fn conditional_arguments<'a>(
1162        &self,
1163        args: &'a [Expr],
1164    ) -> Option<(Vec<&'a Expr>, Vec<&'a Expr>)> {
1165        self.inner.conditional_arguments(args)
1166    }
1167
1168    fn coerce_value_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
1169        self.inner.coerce_value_types(arg_types)
1170    }
1171
1172    fn documentation(&self) -> Option<&Documentation> {
1173        self.inner.documentation()
1174    }
1175}
1176
1177pub(crate) fn resolve_lambda_variables(
1178    expr: Expr,
1179    schema: &DFSchema,
1180    // a map of lambda variable name => a never empty stack of fields [ [..shadowed], in_scope ]
1181    vars: &mut HashMap<String, Vec<FieldRef>>,
1182) -> Result<Transformed<Expr>> {
1183    expr.transform_down(|expr| match expr {
1184        Expr::HigherOrderFunction(HigherOrderFunction { func, args }) => {
1185            // not inlined to reduce nesting
1186            resolve_higher_order_function(func, args, schema, vars)
1187        }
1188        Expr::LambdaVariable(mut var) => {
1189            let field_stack = vars.get(&var.name).ok_or_else(|| {
1190                plan_datafusion_err!(
1191                    "missing field of lambda variable {} while resolving",
1192                    var.name
1193                )
1194            })?;
1195
1196            let field = field_stack.last().ok_or_else(|| {
1197                internal_datafusion_err!("every entry should have at least one field")
1198            })?;
1199
1200            let field = Arc::clone(field).renamed(&var.name);
1201
1202            let transformed = var.field.as_ref().is_none_or(|old| old != &field);
1203
1204            var.field = Some(field);
1205
1206            Ok(Transformed::new_transformed(
1207                Expr::LambdaVariable(var),
1208                transformed,
1209            ))
1210        }
1211        _ => Ok(Transformed::no(expr)),
1212    })
1213}
1214
1215fn resolve_higher_order_function(
1216    func: Arc<HigherOrderUDF>,
1217    args: Vec<Expr>,
1218    schema: &DFSchema,
1219    // a map of lambda variable name => a never empty stack of fields [ [..shadowed], in_scope ]
1220    vars: &mut HashMap<String, Vec<FieldRef>>,
1221) -> Result<Transformed<Expr>> {
1222    let args = if !vars.is_empty() {
1223        /*  if this is a nested lambda, we must resolve non-lambda args before invoking
1224            lambda_parameters because it will invoke ExprSchemable::to_field for every
1225            non-lambda parameter, and if one them contains a lambda variable, it will fail
1226            due to it being unresolved. Example query:
1227
1228            array_transform([[1, 2]], a -> array_transform(a, b -> b+1))
1229
1230            the nested array_transform's lambda_parameters will call Lambdavariable::to_field
1231            on it's first argument, the variable `a`, which must be resolved
1232        */
1233        args.map_elements(|arg| match arg {
1234            Expr::Lambda(_) => Ok(Transformed::no(arg)),
1235            _ => resolve_lambda_variables(arg, schema, vars),
1236        })?
1237    } else {
1238        Transformed::no(args)
1239    };
1240
1241    let transformed = args.transformed;
1242    let mut args = args.data;
1243
1244    let current_fields = args
1245        .iter()
1246        .map(|e| match e {
1247            Expr::Lambda(_lambda_function) => Ok(ValueOrLambda::Lambda(None)),
1248            _ => Ok(ValueOrLambda::Value(e.to_field(schema)?.1)),
1249        })
1250        .collect::<Result<Vec<_>>>()?;
1251
1252    // coerce fields because coercion may alter the lambda parameters
1253    let mut fields = value_fields_with_higher_order_udf(&current_fields, func.as_ref())?;
1254
1255    let num_lambdas = args.iter().filter(|a| matches!(a, Expr::Lambda(_))).count();
1256
1257    let mut step = 0;
1258
1259    let lambda_params = loop {
1260        match func.lambda_parameters(step, &fields)? {
1261            LambdaParametersProgress::Partial(params) => {
1262                let mut params = params.into_iter();
1263
1264                if params.len() != num_lambdas {
1265                    return plan_err!(
1266                        "{} lambda_parameters returned {} lambdas but {num_lambdas} expected",
1267                        func.name(),
1268                        params.len()
1269                    );
1270                }
1271
1272                for (arg, field) in std::iter::zip(&mut args, &mut fields) {
1273                    match (arg, field) {
1274                        (Expr::Lambda(lambda), ValueOrLambda::Lambda(field)) => {
1275                            let params = params.next().ok_or_else(|| {
1276                                internal_datafusion_err!(
1277                                    "params len should have been checked above"
1278                                )
1279                            })?;
1280
1281                            if let Some(params) = params {
1282                                for (name, field) in
1283                                    std::iter::zip(&lambda.params, params)
1284                                {
1285                                    vars.entry_ref(name)
1286                                        .or_default()
1287                                        .push(field.renamed(name.as_str()));
1288                                }
1289
1290                                let body_with_vars = resolve_lambda_variables(
1291                                    mem::take(lambda.body.as_mut()),
1292                                    schema,
1293                                    vars,
1294                                )?;
1295
1296                                remove_scope(vars, &lambda.params)?;
1297
1298                                *field = Some(body_with_vars.data.to_field(schema)?.1);
1299                                *lambda.body = body_with_vars.data;
1300                            }
1301                        }
1302                        (_, ValueOrLambda::Lambda(_)) => {
1303                            return internal_err!(
1304                                "value_fields_with_higher_order_udf returned a value for a lambda argument"
1305                            );
1306                        }
1307                        (Expr::Lambda(_), ValueOrLambda::Value(_)) => {
1308                            return internal_err!(
1309                                "value_fields_with_higher_order_udf returned a lambda for a value argument"
1310                            );
1311                        }
1312                        (_, ValueOrLambda::Value(_)) => {} // nothing to do
1313                    }
1314                }
1315            }
1316            LambdaParametersProgress::Complete(params) => break params,
1317        }
1318
1319        let limit = func.signature().lambda_parameters_max_iterations;
1320
1321        step += 1;
1322
1323        if step > limit {
1324            return plan_err!(
1325                "{} lambda_parameters called {limit} times without completion",
1326                func.name()
1327            );
1328        }
1329    };
1330
1331    let mut lambda_params = lambda_params.into_iter();
1332
1333    if num_lambdas != lambda_params.len() {
1334        return plan_err!(
1335            "{} lambda_parameters returned {} values for {num_lambdas} lambdas",
1336            func.name(),
1337            lambda_params.len()
1338        );
1339    }
1340
1341    let args = args.map_elements(|arg| match arg {
1342        Expr::Lambda(mut lambda) => {
1343            let lambda_params = lambda_params.next().ok_or_else(|| {
1344                internal_datafusion_err!(
1345                    "lambda_params len should have been checked above"
1346                )
1347            })?;
1348
1349            if lambda.params.len() > lambda_params.len() {
1350                return plan_err!(
1351                    "{} lambda defined {} params ({}), but only {} supported",
1352                    func.name(),
1353                    lambda.params.len(),
1354                    display_comma_separated(&lambda.params),
1355                    lambda_params.len()
1356                );
1357            }
1358
1359            if !all_unique(&lambda.params) {
1360                return plan_err!(
1361                    "lambda params must be unique, got ({})",
1362                    lambda.params.join(", ")
1363                );
1364            }
1365
1366            for (param, field) in std::iter::zip(&lambda.params, lambda_params) {
1367                vars.entry_ref(param)
1368                    .or_default()
1369                    .push(field.renamed(param.as_str()));
1370            }
1371
1372            let transformed =
1373                resolve_lambda_variables(mem::take(lambda.body.as_mut()), schema, vars)?;
1374
1375            *lambda.body = transformed.data;
1376
1377            remove_scope(vars, &lambda.params)?;
1378
1379            Ok(Transformed::new(
1380                Expr::Lambda(lambda),
1381                transformed.transformed,
1382                TreeNodeRecursion::Jump,
1383            ))
1384        }
1385        arg => Ok(Transformed::no(arg)), // resolved at the start of the function
1386    })?;
1387
1388    Ok(Transformed::new(
1389        Expr::HigherOrderFunction(HigherOrderFunction::new(func, args.data)),
1390        transformed || args.transformed,
1391        TreeNodeRecursion::Jump,
1392    ))
1393}
1394
1395fn remove_scope(
1396    vars: &mut HashMap<String, Vec<FieldRef>>,
1397    scope: &[String],
1398) -> Result<()> {
1399    for param in scope {
1400        match vars.entry_ref(param) {
1401            EntryRef::Occupied(mut v) => {
1402                if v.get().len() == 1 {
1403                    v.remove();
1404                } else {
1405                    v.get_mut().pop().ok_or_else(|| {
1406                        internal_datafusion_err!(
1407                            "every entry should have at least one field"
1408                        )
1409                    })?;
1410                }
1411            }
1412            EntryRef::Vacant(_v) => {
1413                return internal_err!("no empty value should be in the map");
1414            }
1415        }
1416    }
1417
1418    Ok(())
1419}
1420
1421fn all_unique(params: &[String]) -> bool {
1422    match params.len() {
1423        0 | 1 => true,
1424        2 => params[0] != params[1],
1425        _ => {
1426            let mut set = HashSet::with_capacity(params.len());
1427
1428            params.iter().all(|p| set.insert(p.as_str()))
1429        }
1430    }
1431}
1432
1433#[cfg(test)]
1434mod tests {
1435    use super::*;
1436    use std::hash::DefaultHasher;
1437    use std::sync::Arc;
1438
1439    use arrow_schema::{DataType, Field, FieldRef, Schema};
1440    use datafusion_common::{DFSchema, Result};
1441    use datafusion_expr_common::columnar_value::ColumnarValue;
1442    use datafusion_expr_common::signature::Volatility;
1443
1444    use crate::{
1445        Expr, HigherOrderSignature, HigherOrderUDF, HigherOrderUDFImpl,
1446        LambdaParametersProgress, ValueOrLambda, col,
1447        expr::{HigherOrderFunction, LambdaVariable},
1448        lambda, lambda_var, lit,
1449    };
1450
1451    #[derive(Debug, PartialEq, Eq, Hash)]
1452    struct TestHigherOrderUDF {
1453        name: &'static str,
1454        field: &'static str,
1455        signature: HigherOrderSignature,
1456    }
1457    impl HigherOrderUDFImpl for TestHigherOrderUDF {
1458        fn name(&self) -> &str {
1459            self.name
1460        }
1461
1462        fn signature(&self) -> &HigherOrderSignature {
1463            &self.signature
1464        }
1465
1466        fn lambda_parameters(
1467            &self,
1468            _step: usize,
1469            _fields: &[ValueOrLambda<FieldRef, Option<FieldRef>>],
1470        ) -> Result<LambdaParametersProgress> {
1471            unimplemented!()
1472        }
1473
1474        fn return_field_from_args(
1475            &self,
1476            _args: HigherOrderReturnFieldArgs,
1477        ) -> Result<FieldRef> {
1478            unimplemented!()
1479        }
1480
1481        fn invoke_with_args(
1482            &self,
1483            _args: HigherOrderFunctionArgs,
1484        ) -> Result<ColumnarValue> {
1485            unimplemented!()
1486        }
1487    }
1488
1489    // PartialEq and Hash must be consistent, and also PartialEq and PartialOrd
1490    // must be consistent, so they are tested together.
1491    #[test]
1492    fn test_partial_eq_hash_and_partial_ord() {
1493        // A parameterized function
1494        let f = test_func("foo", "a");
1495
1496        // Same like `f`, different instance
1497        let f2 = test_func("foo", "a");
1498        assert_eq!(&f, &f2);
1499        assert_eq!(hash(&f), hash(&f2));
1500        assert_eq!(f.partial_cmp(&f2), Some(Ordering::Equal));
1501
1502        // Different parameter
1503        let b = test_func("foo", "b");
1504        assert_ne!(&f, &b);
1505        assert_ne!(hash(&f), hash(&b)); // hash can collide for different values but does not collide in this test
1506        assert_eq!(f.partial_cmp(&b), None);
1507
1508        // Different name
1509        let o = test_func("other", "a");
1510        assert_ne!(&f, &o);
1511        assert_ne!(hash(&f), hash(&o)); // hash can collide for different values but does not collide in this test
1512        assert_eq!(f.partial_cmp(&o), Some(Ordering::Less));
1513
1514        // Different name and parameter
1515        assert_ne!(&b, &o);
1516        assert_ne!(hash(&b), hash(&o)); // hash can collide for different values but does not collide in this test
1517        assert_eq!(b.partial_cmp(&o), Some(Ordering::Less));
1518    }
1519
1520    fn test_func(name: &'static str, parameter: &'static str) -> Arc<HigherOrderUDF> {
1521        Arc::new(HigherOrderUDF::new_from_impl(TestHigherOrderUDF {
1522            name,
1523            field: parameter,
1524            signature: HigherOrderSignature::variadic_any(Volatility::Immutable),
1525        }))
1526    }
1527
1528    fn hash<T: Hash>(value: &T) -> u64 {
1529        let hasher = &mut DefaultHasher::new();
1530        value.hash(hasher);
1531        hasher.finish()
1532    }
1533
1534    #[derive(Debug, PartialEq, Eq, Hash)]
1535    struct MockArrayReduce {
1536        signature: HigherOrderSignature,
1537    }
1538
1539    impl HigherOrderUDFImpl for MockArrayReduce {
1540        fn name(&self) -> &str {
1541            "array_reduce"
1542        }
1543
1544        fn aliases(&self) -> &[String] {
1545            &[]
1546        }
1547
1548        fn signature(&self) -> &HigherOrderSignature {
1549            &self.signature
1550        }
1551
1552        fn lambda_parameters(
1553            &self,
1554            step: usize,
1555            fields: &[ValueOrLambda<FieldRef, Option<FieldRef>>],
1556        ) -> Result<LambdaParametersProgress> {
1557            // optional finish not supported for simplicity
1558            let [
1559                ValueOrLambda::Value(list),
1560                ValueOrLambda::Value(initial_value),
1561                ValueOrLambda::Lambda(merge),
1562                ValueOrLambda::Lambda(_finish),
1563            ] = fields
1564            else {
1565                unreachable!()
1566            };
1567
1568            let list_field = match list.data_type() {
1569                DataType::List(field) => field,
1570                _ => unreachable!(),
1571            };
1572
1573            Ok(match (step, merge) {
1574                (0, None) => {
1575                    // at the first step, we use the initial_value as merge accumulator,
1576                    // and return None for finish since we don't know the output of merge
1577                    LambdaParametersProgress::Partial(vec![
1578                        // merge
1579                        Some(vec![Arc::clone(initial_value), Arc::clone(list_field)]),
1580                        // finish
1581                        None,
1582                    ])
1583                }
1584                (1, Some(accumulator)) | (0, Some(accumulator)) => {
1585                    // now we can use the merge output as it's accumulator and
1586                    // as the finish parameter
1587                    LambdaParametersProgress::Complete(vec![
1588                        // merge
1589                        vec![Arc::clone(accumulator), Arc::clone(list_field)],
1590                        // finish
1591                        vec![Arc::clone(accumulator)],
1592                    ])
1593                }
1594                (1, None) => {
1595                    unreachable!()
1596                }
1597                _ => unreachable!(),
1598            })
1599        }
1600
1601        fn return_field_from_args(
1602            &self,
1603            args: HigherOrderReturnFieldArgs,
1604        ) -> Result<FieldRef> {
1605            // optional finish not supported for simplicity
1606            let [
1607                ValueOrLambda::Value(_list),
1608                ValueOrLambda::Value(_initial_value),
1609                ValueOrLambda::Lambda(_merge),
1610                ValueOrLambda::Lambda(finish),
1611            ] = args.arg_fields
1612            else {
1613                unreachable!()
1614            };
1615
1616            Ok(Arc::clone(finish))
1617        }
1618
1619        fn invoke_with_args(
1620            &self,
1621            _args: HigherOrderFunctionArgs,
1622        ) -> Result<ColumnarValue> {
1623            unreachable!()
1624        }
1625    }
1626
1627    #[test]
1628    fn test_resolve_lambda_variables() {
1629        let schema = DFSchema::try_from(Schema::new(vec![Field::new(
1630            "c",
1631            DataType::new_list(DataType::new_list(DataType::Int32, true), true),
1632            true,
1633        )]))
1634        .unwrap();
1635
1636        let func = Arc::new(HigherOrderUDF::new_from_impl(MockArrayReduce {
1637            signature: HigherOrderSignature::variadic_any(Volatility::Immutable),
1638        }));
1639
1640        /*
1641           array_reduce(
1642               c,
1643               0,
1644               (acc1, v) -> acc + array_reduce(
1645                   v,
1646                   0,
1647                   (acc2, v) -> acc2 + acc1 + v,
1648                   reduced -> reduced * 2.0
1649               ),
1650               reduced -> reduced * 2
1651           )
1652        */
1653        let expr = Expr::HigherOrderFunction(HigherOrderFunction::new(
1654            Arc::clone(&func),
1655            vec![
1656                col("c"),
1657                lit(0),
1658                lambda(
1659                    ["acc1", "v"],
1660                    lambda_var("acc1")
1661                        + Expr::HigherOrderFunction(HigherOrderFunction::new(
1662                            Arc::clone(&func),
1663                            vec![
1664                                lambda_var("v"),
1665                                lit(0),
1666                                lambda(
1667                                    ["acc2", "v"],
1668                                    lambda_var("acc2")
1669                                        + lambda_var("acc1")
1670                                        + lambda_var("v"),
1671                                ),
1672                                lambda(["reduced"], lambda_var("reduced") * lit(2.0)),
1673                            ],
1674                        )),
1675                ),
1676                lambda(["reduced"], lambda_var("reduced") * lit(2)),
1677            ],
1678        ));
1679
1680        let resolved_expr = expr.resolve_lambda_variables(&schema).unwrap().data;
1681
1682        /*
1683           array_reduce(
1684               c@[[Int32]],
1685               0@Int64,
1686               (acc1@Float64, v@[Int32]) -> acc@Float64 + array_reduce(
1687                   v@[Int32],
1688                   0@Int64,
1689                   (acc2@Float64, v@Int32) -> acc2@Float64 + acc1@Float64 + v@Int32,
1690                   reducedFloat64 -> reduced@Float64 * 2.0@Float64
1691               ),
1692               reduced@Float64 -> reduced@Float64 * 2@Int64
1693           )
1694        */
1695        let expected = Expr::HigherOrderFunction(HigherOrderFunction::new(
1696            Arc::clone(&func),
1697            vec![
1698                col("c"),
1699                lit(0),
1700                lambda(
1701                    ["acc1", "v"],
1702                    resolved_lambda_var("acc1", DataType::Float64, true)
1703                        + Expr::HigherOrderFunction(HigherOrderFunction::new(
1704                            Arc::clone(&func),
1705                            vec![
1706                                resolved_lambda_var(
1707                                    "v",
1708                                    DataType::new_list(DataType::Int32, true),
1709                                    true,
1710                                ),
1711                                lit(0),
1712                                lambda(
1713                                    ["acc2", "v"],
1714                                    resolved_lambda_var("acc2", DataType::Float64, true)
1715                                        + resolved_lambda_var(
1716                                            "acc1",
1717                                            DataType::Float64,
1718                                            true,
1719                                        )
1720                                        + resolved_lambda_var("v", DataType::Int32, true),
1721                                ),
1722                                lambda(
1723                                    ["reduced"],
1724                                    resolved_lambda_var(
1725                                        "reduced",
1726                                        DataType::Float64,
1727                                        true,
1728                                    ) * lit(2.0),
1729                                ),
1730                            ],
1731                        )),
1732                ),
1733                lambda(
1734                    ["reduced"],
1735                    resolved_lambda_var("reduced", DataType::Float64, true) * lit(2),
1736                ),
1737            ],
1738        ));
1739
1740        assert_eq!(resolved_expr, expected);
1741    }
1742
1743    fn resolved_lambda_var(name: &str, dt: DataType, nullable: bool) -> Expr {
1744        Expr::LambdaVariable(LambdaVariable::new(
1745            name.into(),
1746            Some(Arc::new(Field::new(name, dt, nullable))),
1747        ))
1748    }
1749
1750    /// A physical expression that reads the column at a fixed index of the
1751    /// batch it is evaluated against, for exercising [`LambdaArgument`]
1752    /// directly without depending on `datafusion-physical-expr`.
1753    #[derive(Debug, Eq, PartialEq, Hash)]
1754    struct ColumnAt(usize);
1755
1756    impl std::fmt::Display for ColumnAt {
1757        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1758            write!(f, "column_at({})", self.0)
1759        }
1760    }
1761
1762    impl PhysicalExpr for ColumnAt {
1763        fn evaluate(&self, batch: &RecordBatch) -> Result<ColumnarValue> {
1764            Ok(ColumnarValue::Array(Arc::clone(batch.column(self.0))))
1765        }
1766
1767        fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> {
1768            vec![]
1769        }
1770
1771        fn with_new_children(
1772            self: Arc<Self>,
1773            _children: Vec<Arc<dyn PhysicalExpr>>,
1774        ) -> Result<Arc<dyn PhysicalExpr>> {
1775            Ok(self)
1776        }
1777
1778        fn fmt_sql(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1779            write!(f, "{self}")
1780        }
1781    }
1782
1783    /// `(k, v) -> v` with only `v` used must push `v`'s array, not `k`'s.
1784    #[test]
1785    fn test_lambda_argument_evaluate_pushes_only_used_param() {
1786        use arrow::array::Int32Array;
1787
1788        let k_field = Arc::new(Field::new("k", DataType::Int32, true));
1789        let v_field = Arc::new(Field::new("v", DataType::Int32, true));
1790
1791        let body = Arc::new(ColumnAt(0)) as Arc<dyn PhysicalExpr>;
1792        let lambda_arg = LambdaArgument::new(vec![k_field, v_field], body, None, &[1]);
1793
1794        let k_values: ArrayRef = Arc::new(Int32Array::from(vec![100, 200, 300]));
1795        let v_values: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3]));
1796        let k_closure = || -> Result<ArrayRef> { Ok(Arc::clone(&k_values)) };
1797        let v_closure = || -> Result<ArrayRef> { Ok(Arc::clone(&v_values)) };
1798        let args: Vec<&dyn Fn() -> Result<ArrayRef>> = vec![&k_closure, &v_closure];
1799
1800        let result = lambda_arg
1801            .evaluate(&args, |arrays| Ok(arrays.to_vec()))
1802            .unwrap();
1803        let ColumnarValue::Array(result) = result else {
1804            unreachable!()
1805        };
1806
1807        assert_eq!(
1808            result.as_any().downcast_ref::<Int32Array>().unwrap(),
1809            &Int32Array::from(vec![1, 2, 3]),
1810            "body should read v's values, not k's"
1811        );
1812    }
1813
1814    /// Same as above, but with a capture occupying the leading slot.
1815    #[test]
1816    fn test_lambda_argument_evaluate_pushes_only_used_param_with_captures() {
1817        use arrow::array::Int32Array;
1818
1819        let cap_field = Arc::new(Field::new("cap", DataType::Int32, true));
1820        let k_field = Arc::new(Field::new("k", DataType::Int32, true));
1821        let v_field = Arc::new(Field::new("v", DataType::Int32, true));
1822
1823        let body = Arc::new(ColumnAt(1)) as Arc<dyn PhysicalExpr>;
1824
1825        let cap_values: ArrayRef = Arc::new(Int32Array::from(vec![9, 9, 9]));
1826        let captures = RecordBatch::try_new(
1827            Arc::new(Schema::new(vec![cap_field])),
1828            vec![cap_values],
1829        )
1830        .unwrap();
1831
1832        let lambda_arg =
1833            LambdaArgument::new(vec![k_field, v_field], body, Some(captures), &[1]);
1834
1835        let k_values: ArrayRef = Arc::new(Int32Array::from(vec![100, 200, 300]));
1836        let v_values: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3]));
1837        let k_closure = || -> Result<ArrayRef> { Ok(Arc::clone(&k_values)) };
1838        let v_closure = || -> Result<ArrayRef> { Ok(Arc::clone(&v_values)) };
1839        let args: Vec<&dyn Fn() -> Result<ArrayRef>> = vec![&k_closure, &v_closure];
1840
1841        let result = lambda_arg
1842            .evaluate(&args, |arrays| Ok(arrays.to_vec()))
1843            .unwrap();
1844        let ColumnarValue::Array(result) = result else {
1845            unreachable!()
1846        };
1847
1848        assert_eq!(
1849            result.as_any().downcast_ref::<Int32Array>().unwrap(),
1850            &Int32Array::from(vec![1, 2, 3]),
1851            "body should read v's values, not k's or the capture's"
1852        );
1853    }
1854}