Skip to main content

datafusion_physical_expr/
aggregate.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
18pub(crate) mod groups_accumulator {
19    #[expect(unused_imports)]
20    pub(crate) mod accumulate {
21        pub use datafusion_functions_aggregate_common::aggregate::groups_accumulator::accumulate::NullState;
22    }
23    pub use datafusion_functions_aggregate_common::aggregate::groups_accumulator::{
24        GroupsAccumulatorAdapter, accumulate::NullState,
25    };
26}
27pub(crate) mod stats {
28    pub use datafusion_functions_aggregate_common::stats::StatsType;
29}
30pub mod utils {
31    pub use datafusion_functions_aggregate_common::utils::{
32        DecimalAverager, Hashable, get_accum_scalar_values_as_arrays, get_sort_options,
33        ordering_fields,
34    };
35}
36
37use std::fmt::Debug;
38use std::sync::Arc;
39
40use crate::expressions::Column;
41use crate::physical_expr::create_physical_sort_exprs;
42use crate::planner::{create_physical_expr, create_physical_exprs};
43
44use arrow::compute::SortOptions;
45use arrow::datatypes::{DataType, FieldRef, Schema, SchemaRef};
46use datafusion_common::metadata::FieldMetadata;
47use datafusion_common::{
48    DFSchema, Result, ScalarValue, assert_or_internal_err, internal_err, not_impl_err,
49};
50use datafusion_expr::execution_props::ExecutionProps;
51use datafusion_expr::expr::{
52    AggregateFunction, AggregateFunctionParams, NullTreatment, physical_name,
53};
54use datafusion_expr::physical_planning_context::PhysicalPlanningContext;
55use datafusion_expr::{AggregateUDF, Expr, ReversedUDAF, SetMonotonicity};
56use datafusion_expr_common::accumulator::Accumulator;
57use datafusion_expr_common::groups_accumulator::GroupsAccumulator;
58use datafusion_expr_common::type_coercion::aggregates::check_arg_count;
59use datafusion_functions_aggregate_common::accumulator::{
60    AccumulatorArgs, StateFieldsArgs,
61};
62use datafusion_functions_aggregate_common::order::AggregateOrderSensitivity;
63use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
64use datafusion_physical_expr_common::sort_expr::PhysicalSortExpr;
65
66#[derive(Debug, Clone)]
67struct AggregateHumanDisplay {
68    expression: String,
69    alias: Option<String>,
70}
71
72impl AggregateHumanDisplay {
73    fn try_new(
74        expression: Option<String>,
75        alias: Option<String>,
76        name: &str,
77    ) -> Result<Option<Self>> {
78        let alias = alias.filter(|alias| !alias.is_empty());
79        let Some(expression) = expression else {
80            if alias.is_some() {
81                return internal_err!(
82                    "AggregateExprBuilder::human_display must be provided when human_display_alias is set"
83                );
84            }
85            return Ok(None);
86        };
87
88        if expression.is_empty() {
89            if alias.is_some() {
90                return internal_err!(
91                    "AggregateExprBuilder::human_display must be non-empty when human_display_alias is set"
92                );
93            }
94            return Ok(None);
95        }
96
97        if let Some(alias) = alias.as_deref()
98            && alias != name
99        {
100            return internal_err!(
101                "aggregate human_display_alias must match aggregate name `{name}`: {alias}"
102            );
103        }
104
105        Ok(Some(Self { expression, alias }))
106    }
107
108    fn expression(&self) -> &str {
109        &self.expression
110    }
111
112    fn alias(&self) -> Option<&str> {
113        self.alias.as_deref()
114    }
115}
116
117/// Builder for physical [`AggregateFunctionExpr`]
118///
119/// `AggregateFunctionExpr` contains the information necessary to call
120/// an aggregate expression.
121#[derive(Debug, Clone)]
122pub struct AggregateExprBuilder {
123    fun: Arc<AggregateUDF>,
124    /// Physical expressions of the aggregate function
125    args: Vec<Arc<dyn PhysicalExpr>>,
126    alias: Option<String>,
127    output_metadata: Option<FieldMetadata>,
128    /// A human readable name
129    human_display: Option<String>,
130    /// Optional visible output alias for `human_display`.
131    human_display_alias: Option<String>,
132    /// Arrow Schema for the aggregate function
133    schema: SchemaRef,
134    /// The physical order by expressions
135    order_bys: Vec<PhysicalSortExpr>,
136    /// Whether to ignore null values
137    ignore_nulls: bool,
138    /// Whether is distinct aggregate function
139    is_distinct: bool,
140    /// Whether the expression is reversed
141    is_reversed: bool,
142}
143
144impl AggregateExprBuilder {
145    pub fn new(fun: Arc<AggregateUDF>, args: Vec<Arc<dyn PhysicalExpr>>) -> Self {
146        Self {
147            fun,
148            args,
149            alias: None,
150            output_metadata: None,
151            human_display: None,
152            human_display_alias: None,
153            schema: Arc::new(Schema::empty()),
154            order_bys: vec![],
155            ignore_nulls: false,
156            is_distinct: false,
157            is_reversed: false,
158        }
159    }
160
161    /// Constructs an `AggregateFunctionExpr` from the builder
162    ///
163    /// Note that an [`Self::alias`] must be provided before calling this method.
164    ///
165    /// # Example: Create an [`AggregateUDF`]
166    ///
167    /// In the following example, [`AggregateFunctionExpr`] will be built using [`AggregateExprBuilder`]
168    /// which provides a build function. Full example could be accessed from the source file.
169    ///
170    /// ```
171    /// # use std::any::Any;
172    /// # use std::sync::Arc;
173    /// # use arrow::datatypes::{DataType, FieldRef};
174    /// # use datafusion_common::{Result, ScalarValue};
175    /// # use datafusion_expr::{col, ColumnarValue, Documentation, Signature, Volatility, Expr};
176    /// # use datafusion_expr::{AggregateUDFImpl, AggregateUDF, Accumulator, function::{AccumulatorArgs, StateFieldsArgs}};
177    /// # use arrow::datatypes::Field;
178    /// #
179    /// # #[derive(Debug, Clone, PartialEq, Eq, Hash)]
180    /// # struct FirstValueUdf {
181    /// #     signature: Signature,
182    /// # }
183    /// #
184    /// # impl FirstValueUdf {
185    /// #     fn new() -> Self {
186    /// #         Self {
187    /// #             signature: Signature::any(1, Volatility::Immutable),
188    /// #         }
189    /// #     }
190    /// # }
191    /// #
192    /// # impl AggregateUDFImpl for FirstValueUdf {
193    /// #     fn name(&self) -> &str {
194    /// #         unimplemented!()
195    /// #     }
196    /// #
197    /// #     fn signature(&self) -> &Signature {
198    /// #         unimplemented!()
199    /// #     }
200    /// #
201    /// #     fn return_type(&self, args: &[DataType]) -> Result<DataType> {
202    /// #         unimplemented!()
203    /// #     }
204    /// #
205    /// #     fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
206    /// #         unimplemented!()
207    /// #         }
208    /// #
209    /// #     fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
210    /// #         unimplemented!()
211    /// #     }
212    /// #
213    /// #     fn documentation(&self) -> Option<&Documentation> {
214    /// #         unimplemented!()
215    /// #     }
216    /// # }
217    /// #
218    /// # let first_value = AggregateUDF::from(FirstValueUdf::new());
219    /// # let expr = first_value.call(vec![col("a")]);
220    /// #
221    /// # use datafusion_physical_expr::expressions::Column;
222    /// # use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
223    /// # use datafusion_physical_expr::aggregate::AggregateExprBuilder;
224    /// # use datafusion_physical_expr::expressions::PhysicalSortExpr;
225    /// # use datafusion_physical_expr::PhysicalSortRequirement;
226    /// #
227    /// fn build_aggregate_expr() -> Result<()> {
228    ///     let args = vec![Arc::new(Column::new("a", 0)) as Arc<dyn PhysicalExpr>];
229    ///     let order_by = vec![PhysicalSortExpr {
230    ///         expr: Arc::new(Column::new("x", 1)) as Arc<dyn PhysicalExpr>,
231    ///         options: Default::default(),
232    ///     }];
233    ///
234    ///     let first_value = AggregateUDF::from(FirstValueUdf::new());
235    ///
236    ///     let aggregate_expr = AggregateExprBuilder::new(
237    ///         Arc::new(first_value),
238    ///         args
239    ///     )
240    ///     .order_by(order_by)
241    ///     .alias("first_a_by_x")
242    ///     .ignore_nulls()
243    ///     .build()?;
244    ///
245    ///     Ok(())
246    /// }
247    /// ```
248    ///
249    /// This creates a physical expression equivalent to SQL:
250    /// `first_value(a ORDER BY x) IGNORE NULLS AS first_a_by_x`
251    pub fn build(self) -> Result<AggregateFunctionExpr> {
252        let Self {
253            fun,
254            args,
255            alias,
256            output_metadata,
257            human_display,
258            human_display_alias,
259            schema,
260            order_bys,
261            ignore_nulls,
262            is_distinct,
263            is_reversed,
264        } = self;
265        assert_or_internal_err!(!args.is_empty(), "args should not be empty");
266
267        let ordering_types = order_bys
268            .iter()
269            .map(|e| e.expr.data_type(&schema))
270            .collect::<Result<Vec<_>>>()?;
271
272        let ordering_fields = utils::ordering_fields(&order_bys, &ordering_types);
273
274        let input_exprs_fields = args
275            .iter()
276            .map(|arg| arg.return_field(&schema))
277            .collect::<Result<Vec<_>>>()?;
278
279        check_arg_count(
280            fun.name(),
281            &input_exprs_fields,
282            &fun.signature().type_signature,
283        )?;
284
285        let mut return_field = fun.return_field(&input_exprs_fields)?;
286        if let Some(output_metadata) = output_metadata {
287            return_field = output_metadata.add_to_field_ref(return_field);
288        }
289        let is_nullable = fun.is_nullable();
290        let name = match alias {
291            None => {
292                return internal_err!(
293                    "AggregateExprBuilder::alias must be provided prior to calling build"
294                );
295            }
296            Some(alias) => alias,
297        };
298
299        let human_display =
300            AggregateHumanDisplay::try_new(human_display, human_display_alias, &name)?;
301
302        let arg_fields = args
303            .iter()
304            .map(|e| e.return_field(schema.as_ref()))
305            .collect::<Result<Vec<_>>>()?;
306
307        Ok(AggregateFunctionExpr {
308            fun: Arc::unwrap_or_clone(fun),
309            args,
310            arg_fields,
311            return_field,
312            name,
313            human_display,
314            schema: Arc::unwrap_or_clone(schema),
315            order_bys,
316            ignore_nulls,
317            ordering_fields,
318            is_distinct,
319            input_fields: input_exprs_fields,
320            is_reversed,
321            is_nullable,
322        })
323    }
324
325    pub fn alias(mut self, alias: impl Into<String>) -> Self {
326        self.alias = Some(alias.into());
327        self
328    }
329
330    fn output_metadata(mut self, metadata: Option<FieldMetadata>) -> Self {
331        self.output_metadata = metadata;
332        self
333    }
334
335    pub fn human_display(mut self, name: impl Into<String>) -> Self {
336        let name = name.into();
337        self.human_display = (!name.is_empty()).then_some(name);
338        if self.human_display.is_none() {
339            self.human_display_alias = None;
340        }
341        self
342    }
343
344    #[doc(hidden)]
345    pub fn human_display_alias(mut self, alias: impl Into<String>) -> Self {
346        let alias = alias.into();
347        self.human_display_alias = (!alias.is_empty()).then_some(alias);
348        self
349    }
350
351    pub fn schema(mut self, schema: SchemaRef) -> Self {
352        self.schema = schema;
353        self
354    }
355
356    pub fn order_by(mut self, order_bys: Vec<PhysicalSortExpr>) -> Self {
357        self.order_bys = order_bys;
358        self
359    }
360
361    pub fn reversed(mut self) -> Self {
362        self.is_reversed = true;
363        self
364    }
365
366    pub fn with_reversed(mut self, is_reversed: bool) -> Self {
367        self.is_reversed = is_reversed;
368        self
369    }
370
371    pub fn distinct(mut self) -> Self {
372        self.is_distinct = true;
373        self
374    }
375
376    pub fn with_distinct(mut self, is_distinct: bool) -> Self {
377        self.is_distinct = is_distinct;
378        self
379    }
380
381    pub fn ignore_nulls(mut self) -> Self {
382        self.ignore_nulls = true;
383        self
384    }
385
386    pub fn with_ignore_nulls(mut self, ignore_nulls: bool) -> Self {
387        self.ignore_nulls = ignore_nulls;
388        self
389    }
390}
391
392#[derive(Debug, Clone)]
393struct LoweredAggregateHumanDisplay {
394    expression: String,
395    alias: Option<String>,
396}
397
398/// Result of lowering a logical aggregate expression into physical aggregate
399/// planning pieces.
400#[derive(Debug, Clone)]
401pub struct LoweredAggregate {
402    /// Physical aggregate expression that can be used by an aggregate execution
403    /// plan.
404    pub aggregate: Arc<AggregateFunctionExpr>,
405    /// Optional physical filter expression for `FILTER (WHERE ...)`.
406    pub filter: Option<Arc<dyn PhysicalExpr>>,
407    /// Physical ordering expressions from aggregate `ORDER BY`.
408    pub order_bys: Vec<PhysicalSortExpr>,
409}
410
411/// Builder for converting a logical aggregate [`Expr`] into physical aggregate
412/// planning pieces.
413///
414/// This builder handles the logical-to-physical work needed for aggregate
415/// planning: unwrapping aggregate aliases, choosing the output name, preserving
416/// user-facing display text, lowering aggregate arguments, lowering the optional
417/// filter, and lowering aggregate `ORDER BY` expressions.
418pub struct LoweredAggregateBuilder<'a> {
419    expr: &'a Expr,
420    name: Option<String>,
421    human_display: Option<LoweredAggregateHumanDisplay>,
422    output_metadata: Option<FieldMetadata>,
423    preserve_alias_metadata: bool,
424    logical_input_schema: &'a DFSchema,
425    physical_input_schema: &'a Schema,
426    execution_props: &'a ExecutionProps,
427    planning_ctx: &'a PhysicalPlanningContext,
428}
429
430impl<'a> LoweredAggregateBuilder<'a> {
431    /// Create a builder for lowering `expr`.
432    ///
433    /// `logical_input_schema` is used to resolve logical expressions such as
434    /// columns, while `physical_input_schema` is the input schema used by the
435    /// physical aggregate expression. `planning_ctx` is used when creating
436    /// physical expressions that reference uncorrelated scalar subqueries.
437    /// Callers creating physical aggregates outside of physical planning should
438    /// pass `&PhysicalPlanningContext::default()`, in which case converting a
439    /// scalar-subquery expression returns a planning error.
440    pub fn new(
441        expr: &'a Expr,
442        logical_input_schema: &'a DFSchema,
443        physical_input_schema: &'a Schema,
444        execution_props: &'a ExecutionProps,
445        planning_ctx: &'a PhysicalPlanningContext,
446    ) -> Self {
447        Self {
448            expr,
449            name: None,
450            human_display: None,
451            output_metadata: None,
452            preserve_alias_metadata: true,
453            logical_input_schema,
454            physical_input_schema,
455            execution_props,
456            planning_ctx,
457        }
458    }
459
460    /// Override the output column name for the aggregate.
461    ///
462    /// If this is not set, the builder uses the alias from `expr` when present,
463    /// or derives the physical name from the aggregate expression.
464    pub fn with_name(mut self, name: impl Into<String>) -> Self {
465        self.name = Some(name.into());
466        self
467    }
468
469    /// Override the human-readable display text for the aggregate.
470    ///
471    /// This is useful when a caller has already computed the exact display text
472    /// it wants to preserve. When this override is used, aliases with metadata
473    /// are still unwrapped for planning, but alias metadata is not copied to the
474    /// aggregate output field.
475    pub fn with_human_display(mut self, human_display: impl Into<String>) -> Self {
476        self.human_display = Some(LoweredAggregateHumanDisplay {
477            expression: human_display.into(),
478            alias: None,
479        });
480        self.preserve_alias_metadata = false;
481        self
482    }
483
484    /// Lower the logical aggregate expression into physical aggregate pieces.
485    pub fn build(self) -> Result<LoweredAggregate> {
486        let Self {
487            expr,
488            name,
489            human_display,
490            output_metadata,
491            preserve_alias_metadata,
492            logical_input_schema,
493            physical_input_schema,
494            execution_props,
495            planning_ctx,
496        } = self;
497
498        let (name, human_display, output_metadata, expr) = lower_aggregate_display(
499            expr,
500            name,
501            human_display,
502            output_metadata,
503            preserve_alias_metadata,
504        );
505
506        let Expr::AggregateFunction(AggregateFunction {
507            func,
508            params:
509                AggregateFunctionParams {
510                    args,
511                    distinct,
512                    filter,
513                    order_by,
514                    null_treatment,
515                },
516        }) = &expr
517        else {
518            return internal_err!("Invalid aggregate expression '{expr:?}'");
519        };
520
521        let name = if let Some(name) = name {
522            name
523        } else {
524            physical_name(&expr)?
525        };
526
527        let physical_args = create_physical_exprs(
528            args,
529            logical_input_schema,
530            execution_props,
531            planning_ctx,
532        )?;
533        let filter = filter
534            .as_ref()
535            .map(|filter| {
536                create_physical_expr(
537                    filter,
538                    logical_input_schema,
539                    execution_props,
540                    planning_ctx,
541                )
542            })
543            .transpose()?;
544        let order_bys = create_physical_sort_exprs(
545            order_by,
546            logical_input_schema,
547            execution_props,
548            planning_ctx,
549        )?;
550        let ignore_nulls = null_treatment.unwrap_or(NullTreatment::RespectNulls)
551            == NullTreatment::IgnoreNulls;
552
553        let mut builder = AggregateExprBuilder::new(func.to_owned(), physical_args)
554            .order_by(order_bys.clone())
555            .schema(Arc::new(physical_input_schema.to_owned()))
556            .alias(name)
557            .output_metadata(output_metadata)
558            .with_ignore_nulls(ignore_nulls)
559            .with_distinct(*distinct);
560
561        if let Some(human_display) = human_display {
562            builder = builder.human_display(human_display.expression);
563            if let Some(alias) = human_display.alias {
564                builder = builder.human_display_alias(alias);
565            }
566        }
567
568        Ok(LoweredAggregate {
569            aggregate: Arc::new(builder.build()?),
570            filter,
571            order_bys,
572        })
573    }
574}
575
576fn lower_aggregate_display(
577    expr: &Expr,
578    name: Option<String>,
579    human_display: Option<LoweredAggregateHumanDisplay>,
580    output_metadata: Option<FieldMetadata>,
581    preserve_alias_metadata: bool,
582) -> (
583    Option<String>,
584    Option<LoweredAggregateHumanDisplay>,
585    Option<FieldMetadata>,
586    Expr,
587) {
588    let mut expr = expr.clone();
589    let mut alias_name = None;
590    let mut alias_metadata = None;
591    while let Expr::Alias(alias) = expr {
592        if alias_name.is_none() {
593            alias_name = Some(alias.name);
594            alias_metadata = alias.metadata;
595        }
596        expr = *alias.expr;
597    }
598
599    let output_metadata = if preserve_alias_metadata {
600        output_metadata.or(alias_metadata)
601    } else {
602        output_metadata
603    };
604
605    if human_display.is_some() {
606        return (name.or(alias_name), human_display, output_metadata, expr);
607    }
608
609    match &expr {
610        Expr::AggregateFunction(_) => {
611            if let Some(alias_name) = alias_name {
612                let name = name.unwrap_or(alias_name);
613                let expression = expr.human_display().to_string();
614                let human_display = if expression.is_empty() || expression == name {
615                    LoweredAggregateHumanDisplay {
616                        expression: name.clone(),
617                        alias: None,
618                    }
619                } else {
620                    LoweredAggregateHumanDisplay {
621                        expression,
622                        alias: Some(name.clone()),
623                    }
624                };
625
626                return (Some(name), Some(human_display), output_metadata, expr);
627            }
628
629            let name = name.unwrap_or_else(|| expr.schema_name().to_string());
630            let human_display = LoweredAggregateHumanDisplay {
631                expression: expr.human_display().to_string(),
632                alias: None,
633            };
634
635            (Some(name), Some(human_display), output_metadata, expr)
636        }
637        _ => (name.or(alias_name), None, output_metadata, expr),
638    }
639}
640
641/// Physical aggregate expression of a UDAF.
642///
643/// Instances are constructed via [`AggregateExprBuilder`].
644#[derive(Debug, Clone)]
645pub struct AggregateFunctionExpr {
646    fun: AggregateUDF,
647    args: Vec<Arc<dyn PhysicalExpr>>,
648    /// Fields corresponding to args (same order & length)
649    arg_fields: Vec<FieldRef>,
650    /// Output / return field of this aggregate
651    return_field: FieldRef,
652    /// Output column name that this expression creates
653    name: String,
654    /// Simplified name for `tree` explain.
655    human_display: Option<AggregateHumanDisplay>,
656    schema: Schema,
657    // The physical order by expressions
658    order_bys: Vec<PhysicalSortExpr>,
659    // Whether to ignore null values
660    ignore_nulls: bool,
661    // fields used for order sensitive aggregation functions
662    ordering_fields: Vec<FieldRef>,
663    is_distinct: bool,
664    is_reversed: bool,
665    input_fields: Vec<FieldRef>,
666    is_nullable: bool,
667}
668
669impl AggregateFunctionExpr {
670    /// Return the `AggregateUDF` used by this `AggregateFunctionExpr`
671    pub fn fun(&self) -> &AggregateUDF {
672        &self.fun
673    }
674
675    /// expressions that are passed to the Accumulator.
676    /// Single-column aggregations such as `sum` return a single value, others (e.g. `cov`) return many.
677    pub fn expressions(&self) -> Vec<Arc<dyn PhysicalExpr>> {
678        self.args.clone()
679    }
680
681    /// Human readable name such as `"MIN(c2)"`.
682    pub fn name(&self) -> &str {
683        &self.name
684    }
685
686    /// Simplified name for `tree` explain.
687    pub fn human_display(&self) -> Option<&str> {
688        self.human_display
689            .as_ref()
690            .map(AggregateHumanDisplay::expression)
691    }
692
693    #[doc(hidden)]
694    pub fn human_display_alias(&self) -> Option<&str> {
695        self.human_display
696            .as_ref()
697            .and_then(AggregateHumanDisplay::alias)
698    }
699
700    fn return_field_metadata(&self) -> Option<FieldMetadata> {
701        let metadata = FieldMetadata::from(self.return_field.as_ref());
702        (!metadata.is_empty()).then_some(metadata)
703    }
704
705    /// Return if the aggregation is distinct
706    pub fn is_distinct(&self) -> bool {
707        self.is_distinct
708    }
709
710    /// Return if the aggregation ignores nulls
711    pub fn ignore_nulls(&self) -> bool {
712        self.ignore_nulls
713    }
714
715    /// Return if the aggregation is reversed
716    pub fn is_reversed(&self) -> bool {
717        self.is_reversed
718    }
719
720    /// Return if the aggregation is nullable
721    pub fn is_nullable(&self) -> bool {
722        self.is_nullable
723    }
724
725    /// the field of the final result of this aggregation.
726    pub fn field(&self) -> FieldRef {
727        self.return_field
728            .as_ref()
729            .clone()
730            .with_name(&self.name)
731            .into()
732    }
733
734    /// the accumulator used to accumulate values from the expressions.
735    /// the accumulator expects the same number of arguments as `expressions` and must
736    /// return states with the same description as `state_fields`
737    pub fn create_accumulator(&self) -> Result<Box<dyn Accumulator>> {
738        let acc_args = AccumulatorArgs {
739            return_field: Arc::clone(&self.return_field),
740            schema: &self.schema,
741            expr_fields: &self.arg_fields,
742            ignore_nulls: self.ignore_nulls,
743            order_bys: self.order_bys.as_ref(),
744            is_distinct: self.is_distinct,
745            name: &self.name,
746            is_reversed: self.is_reversed,
747            exprs: &self.args,
748        };
749
750        self.fun.accumulator(acc_args)
751    }
752
753    /// the field of the final result of this aggregation.
754    pub fn state_fields(&self) -> Result<Vec<FieldRef>> {
755        let args = StateFieldsArgs {
756            name: &self.name,
757            input_fields: &self.input_fields,
758            return_field: Arc::clone(&self.return_field),
759            ordering_fields: &self.ordering_fields,
760            is_distinct: self.is_distinct,
761        };
762
763        self.fun.state_fields(args)
764    }
765
766    /// Returns the ORDER BY expressions for the aggregate function.
767    pub fn order_bys(&self) -> &[PhysicalSortExpr] {
768        if self.order_sensitivity().is_insensitive() {
769            &[]
770        } else {
771            &self.order_bys
772        }
773    }
774
775    /// Indicates whether aggregator can produce the correct result with any
776    /// arbitrary input ordering. By default, we assume that aggregate expressions
777    /// are order insensitive.
778    pub fn order_sensitivity(&self) -> AggregateOrderSensitivity {
779        if self.order_bys.is_empty() {
780            AggregateOrderSensitivity::Insensitive
781        } else {
782            // If there is an ORDER BY clause, use the sensitivity of the implementation:
783            self.fun.order_sensitivity()
784        }
785    }
786
787    /// Sets the indicator whether ordering requirements of the aggregator is
788    /// satisfied by its input. If this is not the case, aggregators with order
789    /// sensitivity `AggregateOrderSensitivity::Beneficial` can still produce
790    /// the correct result with possibly more work internally.
791    ///
792    /// # Returns
793    ///
794    /// Returns `Ok(Some(updated_expr))` if the process completes successfully.
795    /// If the expression can benefit from existing input ordering, but does
796    /// not implement the method, returns an error. Order insensitive and hard
797    /// requirement aggregators return `Ok(None)`.
798    pub fn with_beneficial_ordering(
799        self: Arc<Self>,
800        beneficial_ordering: bool,
801    ) -> Result<Option<AggregateFunctionExpr>> {
802        let Some(updated_fn) = self
803            .fun
804            .clone()
805            .with_beneficial_ordering(beneficial_ordering)?
806        else {
807            return Ok(None);
808        };
809
810        let mut builder =
811            AggregateExprBuilder::new(Arc::new(updated_fn), self.args.to_vec())
812                .order_by(self.order_bys.clone())
813                .schema(Arc::new(self.schema.clone()))
814                .alias(self.name().to_string())
815                .output_metadata(self.return_field_metadata())
816                .with_ignore_nulls(self.ignore_nulls)
817                .with_distinct(self.is_distinct)
818                .with_reversed(self.is_reversed);
819        if let Some(human_display) = self.human_display() {
820            builder = builder.human_display(human_display);
821        }
822        if let Some(alias) = self.human_display_alias() {
823            builder = builder.human_display_alias(alias);
824        }
825        builder.build().map(Some)
826    }
827
828    /// Creates accumulator implementation that supports retract
829    pub fn create_sliding_accumulator(&self) -> Result<Box<dyn Accumulator>> {
830        let args = AccumulatorArgs {
831            return_field: Arc::clone(&self.return_field),
832            schema: &self.schema,
833            expr_fields: &self.arg_fields,
834            ignore_nulls: self.ignore_nulls,
835            order_bys: self.order_bys.as_ref(),
836            is_distinct: self.is_distinct,
837            name: &self.name,
838            is_reversed: self.is_reversed,
839            exprs: &self.args,
840        };
841
842        let accumulator = self.fun.create_sliding_accumulator(args)?;
843
844        // Accumulators that have window frame startings different
845        // than `UNBOUNDED PRECEDING`, such as `1 PRECEDING`, need to
846        // implement retract_batch method in order to run correctly
847        // currently in DataFusion.
848        //
849        // If this `retract_batches` is not present, there is no way
850        // to calculate result correctly. For example, the query
851        //
852        // ```sql
853        // SELECT
854        //  SUM(a) OVER(ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS sum_a
855        // FROM
856        //  t
857        // ```
858        //
859        // 1. First sum value will be the sum of rows between `[0, 1)`,
860        //
861        // 2. Second sum value will be the sum of rows between `[0, 2)`
862        //
863        // 3. Third sum value will be the sum of rows between `[1, 3)`, etc.
864        //
865        // Since the accumulator keeps the running sum:
866        //
867        // 1. First sum we add to the state sum value between `[0, 1)`
868        //
869        // 2. Second sum we add to the state sum value between `[1, 2)`
870        // (`[0, 1)` is already in the state sum, hence running sum will
871        // cover `[0, 2)` range)
872        //
873        // 3. Third sum we add to the state sum value between `[2, 3)`
874        // (`[0, 2)` is already in the state sum).  Also we need to
875        // retract values between `[0, 1)` by this way we can obtain sum
876        // between [1, 3) which is indeed the appropriate range.
877        //
878        // When we use `UNBOUNDED PRECEDING` in the query starting
879        // index will always be 0 for the desired range, and hence the
880        // `retract_batch` method will not be called. In this case
881        // having retract_batch is not a requirement.
882        //
883        // This approach is a bit different than window function
884        // approach. In window function (when they use a window frame)
885        // they get all the desired range during evaluation.
886        if !accumulator.supports_retract_batch() {
887            return not_impl_err!(
888                "Aggregate can not be used as a sliding accumulator because \
889                     `retract_batch` is not implemented: {}",
890                self.name
891            );
892        }
893        Ok(accumulator)
894    }
895
896    /// If the aggregate expression has a specialized
897    /// [`GroupsAccumulator`] implementation. If this returns true,
898    /// `[Self::create_groups_accumulator`] will be called.
899    pub fn groups_accumulator_supported(&self) -> bool {
900        let args = AccumulatorArgs {
901            return_field: Arc::clone(&self.return_field),
902            schema: &self.schema,
903            expr_fields: &self.arg_fields,
904            ignore_nulls: self.ignore_nulls,
905            order_bys: self.order_bys.as_ref(),
906            is_distinct: self.is_distinct,
907            name: &self.name,
908            is_reversed: self.is_reversed,
909            exprs: &self.args,
910        };
911        self.fun.groups_accumulator_supported(args)
912    }
913
914    /// Return a specialized [`GroupsAccumulator`] that manages state
915    /// for all groups.
916    ///
917    /// For maximum performance, a [`GroupsAccumulator`] should be
918    /// implemented in addition to [`Accumulator`].
919    pub fn create_groups_accumulator(&self) -> Result<Box<dyn GroupsAccumulator>> {
920        let args = AccumulatorArgs {
921            return_field: Arc::clone(&self.return_field),
922            schema: &self.schema,
923            expr_fields: &self.arg_fields,
924            ignore_nulls: self.ignore_nulls,
925            order_bys: self.order_bys.as_ref(),
926            is_distinct: self.is_distinct,
927            name: &self.name,
928            is_reversed: self.is_reversed,
929            exprs: &self.args,
930        };
931        self.fun.create_groups_accumulator(args)
932    }
933
934    /// Construct an expression that calculates the aggregate in reverse.
935    /// Typically the "reverse" expression is itself (e.g. SUM, COUNT).
936    /// For aggregates that do not support calculation in reverse,
937    /// returns None (which is the default value).
938    pub fn reverse_expr(&self) -> Option<AggregateFunctionExpr> {
939        match self.fun.reverse_udf() {
940            ReversedUDAF::NotSupported => None,
941            ReversedUDAF::Identical => Some(self.clone()),
942            ReversedUDAF::Reversed(reverse_udf) => {
943                let was_aliased = self.human_display_alias().is_some();
944                let mut name = self.name().to_string();
945                let mut human_display = self.human_display.clone();
946                // Reversing display follows two paths:
947                // - aliased display keeps the output `name` unchanged and rewrites only
948                //   the lowered expression in `human_display`.
949                // - non-aliased display rewrites the canonical `name`, and rewrites
950                //   `human_display` only when present.
951                // If the function is changed, we need to reverse order_by clause as well
952                // i.e. First(a order by b asc null first) -> Last(a order by b desc null last)
953                if !was_aliased && self.fun().name() != reverse_udf.name() {
954                    replace_order_by_clause(&mut name);
955                }
956                if !was_aliased {
957                    replace_fn_name_clause(
958                        &mut name,
959                        self.fun.name(),
960                        reverse_udf.name(),
961                    );
962                }
963
964                if let Some(human_display) = human_display.as_mut() {
965                    if self.fun().name() != reverse_udf.name() {
966                        replace_order_by_clause(&mut human_display.expression);
967                    }
968                    replace_fn_name_clause(
969                        &mut human_display.expression,
970                        self.fun.name(),
971                        reverse_udf.name(),
972                    );
973                }
974
975                let mut builder =
976                    AggregateExprBuilder::new(reverse_udf, self.args.to_vec())
977                        .order_by(self.order_bys.iter().map(|e| e.reverse()).collect())
978                        .schema(Arc::new(self.schema.clone()))
979                        .alias(name)
980                        .output_metadata(self.return_field_metadata())
981                        .with_ignore_nulls(self.ignore_nulls)
982                        .with_distinct(self.is_distinct)
983                        .with_reversed(!self.is_reversed);
984                if let Some(human_display) = human_display {
985                    builder = builder.human_display(human_display.expression);
986                    if let Some(alias) = human_display.alias {
987                        builder = builder.human_display_alias(alias);
988                    }
989                }
990                builder.build().ok()
991            }
992        }
993    }
994
995    /// Returns all expressions used in the [`AggregateFunctionExpr`].
996    /// These expressions are  (1)function arguments, (2) order by expressions.
997    pub fn all_expressions(&self) -> AggregatePhysicalExpressions {
998        let args = self.expressions();
999        let order_by_exprs = self
1000            .order_bys()
1001            .iter()
1002            .map(|sort_expr| Arc::clone(&sort_expr.expr))
1003            .collect();
1004        AggregatePhysicalExpressions {
1005            args,
1006            order_by_exprs,
1007        }
1008    }
1009
1010    /// Rewrites [`AggregateFunctionExpr`], with new expressions given. The argument should be consistent
1011    /// with the return value of the [`AggregateFunctionExpr::all_expressions`] method.
1012    /// Returns `Some(Arc<dyn AggregateExpr>)` if re-write is supported, otherwise returns `None`.
1013    pub fn with_new_expressions(
1014        &self,
1015        args: Vec<Arc<dyn PhysicalExpr>>,
1016        order_by_exprs: Vec<Arc<dyn PhysicalExpr>>,
1017    ) -> Option<AggregateFunctionExpr> {
1018        if args.len() != self.args.len()
1019            || (self.order_sensitivity() != AggregateOrderSensitivity::Insensitive
1020                && order_by_exprs.len() != self.order_bys.len())
1021        {
1022            return None;
1023        }
1024
1025        let new_order_bys = self
1026            .order_bys
1027            .iter()
1028            .zip(order_by_exprs)
1029            .map(|(req, new_expr)| PhysicalSortExpr {
1030                expr: new_expr,
1031                options: req.options,
1032            })
1033            .collect();
1034
1035        Some(AggregateFunctionExpr {
1036            fun: self.fun.clone(),
1037            args,
1038            // TODO: need to align arg_fields here with new args
1039            //       https://github.com/apache/datafusion/issues/18149
1040            arg_fields: self.arg_fields.clone(),
1041            return_field: Arc::clone(&self.return_field),
1042            name: self.name.clone(),
1043            // TODO: Human name should be updated after re-write to not mislead
1044            human_display: self.human_display.clone(),
1045            schema: self.schema.clone(),
1046            order_bys: new_order_bys,
1047            ignore_nulls: self.ignore_nulls,
1048            ordering_fields: self.ordering_fields.clone(),
1049            is_distinct: self.is_distinct,
1050            is_reversed: false,
1051            input_fields: self.input_fields.clone(),
1052            is_nullable: self.is_nullable,
1053        })
1054    }
1055
1056    /// If this function is max, return (output_field, true)
1057    /// if the function is min, return (output_field, false)
1058    /// otherwise return None (the default)
1059    ///
1060    /// output_field is the name of the column produced by this aggregate
1061    ///
1062    /// Note: this is used to use special aggregate implementations in certain conditions
1063    pub fn get_minmax_desc(&self) -> Option<(FieldRef, bool)> {
1064        self.fun.is_descending().map(|flag| (self.field(), flag))
1065    }
1066
1067    /// Returns default value of the function given the input is Null
1068    /// Most of the aggregate function return Null if input is Null,
1069    /// while `count` returns 0 if input is Null
1070    pub fn default_value(&self, data_type: &DataType) -> Result<ScalarValue> {
1071        self.fun.default_value(data_type)
1072    }
1073
1074    /// Indicates whether the aggregation function is monotonic as a set
1075    /// function. See [`SetMonotonicity`] for details.
1076    pub fn set_monotonicity(&self) -> SetMonotonicity {
1077        let field = self.field();
1078        let data_type = field.data_type();
1079        self.fun.inner().set_monotonicity(data_type)
1080    }
1081
1082    /// Returns `PhysicalSortExpr` based on the set monotonicity of the function.
1083    pub fn get_result_ordering(&self, aggr_func_idx: usize) -> Option<PhysicalSortExpr> {
1084        // If the aggregate expressions are set-monotonic, the output data is
1085        // naturally ordered with it per group or partition.
1086        let monotonicity = self.set_monotonicity();
1087        if monotonicity == SetMonotonicity::NotMonotonic {
1088            return None;
1089        }
1090        let expr = Arc::new(Column::new(self.name(), aggr_func_idx));
1091        let options =
1092            SortOptions::new(monotonicity == SetMonotonicity::Decreasing, false);
1093        Some(PhysicalSortExpr { expr, options })
1094    }
1095}
1096
1097/// Stores the physical expressions used inside the `AggregateExpr`.
1098pub struct AggregatePhysicalExpressions {
1099    /// Aggregate function arguments
1100    pub args: Vec<Arc<dyn PhysicalExpr>>,
1101    /// Order by expressions
1102    pub order_by_exprs: Vec<Arc<dyn PhysicalExpr>>,
1103}
1104
1105impl PartialEq for AggregateFunctionExpr {
1106    fn eq(&self, other: &Self) -> bool {
1107        self.name == other.name
1108            && self.return_field == other.return_field
1109            && self.fun == other.fun
1110            && self.args.len() == other.args.len()
1111            && self
1112                .args
1113                .iter()
1114                .zip(other.args.iter())
1115                .all(|(this_arg, other_arg)| this_arg.eq(other_arg))
1116    }
1117}
1118
1119fn replace_order_by_clause(order_by: &mut String) {
1120    let suffixes = [
1121        (" DESC NULLS FIRST]", " ASC NULLS LAST]"),
1122        (" ASC NULLS FIRST]", " DESC NULLS LAST]"),
1123        (" DESC NULLS LAST]", " ASC NULLS FIRST]"),
1124        (" ASC NULLS LAST]", " DESC NULLS FIRST]"),
1125    ];
1126
1127    if let Some(start) = order_by.find("ORDER BY [")
1128        && let Some(end) = order_by[start..].find(']')
1129    {
1130        let order_by_start = start + 9;
1131        let order_by_end = start + end;
1132
1133        let column_order = &order_by[order_by_start..=order_by_end];
1134        for (suffix, replacement) in suffixes {
1135            if column_order.ends_with(suffix) {
1136                let new_order = column_order.replace(suffix, replacement);
1137                order_by.replace_range(order_by_start..=order_by_end, &new_order);
1138                break;
1139            }
1140        }
1141    }
1142}
1143
1144fn replace_fn_name_clause(aggr_name: &mut String, fn_name_old: &str, fn_name_new: &str) {
1145    if let Some(rest) = aggr_name.strip_prefix(fn_name_old) {
1146        *aggr_name = format!("{fn_name_new}{rest}");
1147    }
1148}
1149
1150#[cfg(test)]
1151mod tests {
1152    use super::*;
1153
1154    use std::collections::HashMap;
1155
1156    use arrow::datatypes::Field;
1157    use datafusion_common::metadata::FieldMetadata;
1158    use datafusion_expr::{col, test::function_stub::sum};
1159
1160    fn aggregate_test_schema() -> Result<(Schema, DFSchema)> {
1161        let schema = Schema::new(vec![Field::new("column1", DataType::Int64, true)]);
1162        let logical_schema = DFSchema::try_from(schema.clone())?;
1163        Ok((schema, logical_schema))
1164    }
1165
1166    fn test_metadata() -> FieldMetadata {
1167        FieldMetadata::from(HashMap::from([(
1168            "some_key".to_string(),
1169            "some_value".to_string(),
1170        )]))
1171    }
1172
1173    fn aggregate_alias_with_metadata() -> Expr {
1174        sum(col("column1")).alias_with_metadata("agg", Some(test_metadata()))
1175    }
1176
1177    #[test]
1178    fn lowered_aggregate_builder_unwraps_alias_with_metadata() -> Result<()> {
1179        let (schema, logical_schema) = aggregate_test_schema()?;
1180        let expr = aggregate_alias_with_metadata();
1181
1182        let lowered = LoweredAggregateBuilder::new(
1183            &expr,
1184            &logical_schema,
1185            &schema,
1186            &ExecutionProps::new(),
1187            &PhysicalPlanningContext::default(),
1188        )
1189        .build()?;
1190
1191        assert_eq!(lowered.aggregate.name(), "agg");
1192        assert_eq!(lowered.aggregate.human_display_alias(), Some("agg"));
1193        assert_eq!(
1194            lowered.aggregate.field().metadata().get("some_key"),
1195            Some(&"some_value".to_string())
1196        );
1197
1198        Ok(())
1199    }
1200
1201    #[test]
1202    fn lowered_aggregate_builder_display_override_skips_alias_metadata() -> Result<()> {
1203        let (schema, logical_schema) = aggregate_test_schema()?;
1204        let expr = aggregate_alias_with_metadata();
1205
1206        let lowered = LoweredAggregateBuilder::new(
1207            &expr,
1208            &logical_schema,
1209            &schema,
1210            &ExecutionProps::new(),
1211            &PhysicalPlanningContext::default(),
1212        )
1213        .with_human_display(expr.human_display().to_string())
1214        .build()?;
1215
1216        assert_eq!(lowered.aggregate.name(), "agg");
1217        assert_eq!(lowered.aggregate.human_display_alias(), None);
1218        assert!(
1219            lowered
1220                .aggregate
1221                .field()
1222                .metadata()
1223                .get("some_key")
1224                .is_none()
1225        );
1226
1227        Ok(())
1228    }
1229}