Skip to main content

common_function/aggrs/
aggr_wrapper.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Wrapper for making aggregate functions out of state/merge functions of original aggregate functions.
16//!
17//! i.e. for a aggregate function `foo`, we will have a state function `foo_state` and a merge function `foo_merge`.
18//!
19//! `foo_state`'s input args is the same as `foo`'s, and its output is a state object.
20//! Note that `foo_state` might have multiple output columns, so it's a struct array
21//! that each output column is a struct field.
22//! `foo_merge`'s input arg is the same as `foo_state`'s output, and its output is the same as `foo`'s input.
23//!
24
25use std::collections::HashSet;
26use std::hash::{Hash, Hasher};
27use std::sync::Arc;
28
29use arrow::array::{ArrayData, ArrayRef, BooleanArray, StructArray, make_array};
30use arrow_schema::{FieldRef, Fields};
31use common_telemetry::debug;
32use datafusion::functions_aggregate::all_default_aggregate_functions;
33use datafusion::functions_aggregate::count::Count;
34use datafusion::functions_aggregate::min_max::{Max, Min};
35use datafusion::optimizer::AnalyzerRule;
36use datafusion::optimizer::analyzer::type_coercion::TypeCoercion;
37use datafusion_common::{Column, ScalarValue};
38use datafusion_expr::expr::{AggregateFunction, AggregateFunctionParams};
39use datafusion_expr::function::StateFieldsArgs;
40use datafusion_expr::physical_planning_context::PhysicalPlanningContext;
41use datafusion_expr::{
42    Accumulator, Aggregate, AggregateUDF, AggregateUDFImpl, EmitTo, Expr, ExprSchemable,
43    GroupsAccumulator, LogicalPlan, Signature,
44};
45use datafusion_physical_expr::aggregate::{AggregateFunctionExpr, LoweredAggregateBuilder};
46use datatypes::arrow::datatypes::{DataType, Field};
47
48use crate::aggrs::aggr_wrapper::fix_order::FixStateUdafOrderingAnalyzer;
49use crate::function_registry::{FUNCTION_REGISTRY, FunctionRegistry};
50
51pub mod fix_order;
52#[cfg(test)]
53mod tests;
54
55/// Returns the name of the state function for the given aggregate function name.
56/// The state function is used to compute the state of the aggregate function.
57/// The state function's name is in the format `__<aggr_name>_state
58pub fn aggr_state_func_name(aggr_name: &str) -> String {
59    format!("__{}_state", aggr_name)
60}
61
62/// Returns the name of the merge function for the given aggregate function name.
63/// The merge function is used to merge the states of the state functions.
64/// The merge function's name is in the format `__<aggr_name>_merge
65pub fn aggr_merge_func_name(aggr_name: &str) -> String {
66    format!("__{}_merge", aggr_name)
67}
68
69/// Returns the globally registered name used to merge a delta state with a
70/// persisted state.
71pub fn aggr_delta_merge_func_name(state_aggregate_name: &str) -> String {
72    format!("__{}_delta_merge", state_aggregate_name)
73}
74
75/// Check if the given aggregate expression is steppable.
76/// As in if it can be split into multiple steps:
77/// i.e. on datanode first call `state(input)` then
78/// on frontend call `calc(merge(state))` to get the final result.
79pub fn is_all_aggr_exprs_steppable(aggr_exprs: &[Expr]) -> bool {
80    aggr_exprs.iter().all(|expr| {
81        if let Some(aggr_func) = get_aggr_func(expr) {
82            if aggr_func.params.distinct {
83                // Distinct aggregate functions are not steppable(yet).
84                // TODO(discord9): support distinct aggregate functions.
85                return false;
86            }
87
88            // DataFusion only sorts the input of an aggregate with a hard ordering requirement
89            // when the requirement is already satisfied or the aggregate has a reverse
90            // expression (apache/datafusion#25676). The state wrapper has none, so e.g.
91            // `nth_value(.. ORDER BY ..)` would read unsorted input on datanodes. Ordered-set
92            // aggregates like `approx_percentile_cont(..) WITHIN GROUP (ORDER BY ..)` are
93            // exempt: their ORDER BY names the value, and they don't need sorted input.
94            if !aggr_func.params.order_by.is_empty()
95                && aggr_func.func.order_sensitivity().hard_requires()
96                && !aggr_func.func.supports_within_group_clause()
97            {
98                return false;
99            }
100
101            // whether the corresponding state function exists in the registry
102            FUNCTION_REGISTRY.is_aggr_func_exist(&aggr_state_func_name(aggr_func.func.name()))
103        } else {
104            false
105        }
106    })
107}
108
109pub fn get_aggr_func(expr: &Expr) -> Option<&datafusion_expr::expr::AggregateFunction> {
110    let mut expr_ref = expr;
111    while let Expr::Alias(alias) = expr_ref {
112        expr_ref = &alias.expr;
113    }
114    if let Expr::AggregateFunction(aggr_func) = expr_ref {
115        Some(aggr_func)
116    } else {
117        None
118    }
119}
120
121/// A wrapper to make an aggregate function out of the state and merge functions of the original aggregate function.
122/// It contains the original aggregate function, the state functions, and the merge function.
123///
124/// Notice state functions may have multiple output columns, so it's return type is always a struct array, and the merge function is used to merge the states of the state functions.
125#[derive(Debug, Clone)]
126pub struct StateMergeHelper;
127
128/// A struct to hold the two aggregate plans, one for the state function(lower) and one for the merge function(upper).
129#[allow(unused)]
130#[derive(Debug, Clone)]
131pub struct StepAggrPlan {
132    /// Upper merge plan, which is the aggregate plan that merges the states of the state function.
133    pub upper_merge: LogicalPlan,
134    /// Lower state plan, which is the aggregate plan that computes the state of the aggregate function.
135    pub lower_state: LogicalPlan,
136}
137
138impl StateMergeHelper {
139    /// Register all the `state` function of supported aggregate functions.
140    /// Note that can't register `merge` function here, as it needs to be created from the original aggregate function with given input types.
141    pub fn register(registry: &FunctionRegistry) {
142        let all_default = all_default_aggregate_functions();
143        let greptime_custom_aggr_functions = registry.aggregate_functions();
144
145        // if our custom aggregate function have the same name as the default aggregate function, we will override it.
146        let supported = all_default
147            .into_iter()
148            .chain(greptime_custom_aggr_functions.into_iter().map(Arc::new))
149            .collect::<Vec<_>>();
150        debug!(
151            "Registering state functions for supported: {:?}",
152            supported.iter().map(|f| f.name()).collect::<Vec<_>>()
153        );
154
155        let state_func = supported.into_iter().filter_map(|f| {
156            StateWrapper::new((*f).clone())
157                .inspect_err(
158                    |e| common_telemetry::error!(e; "Failed to register state function for {:?}", f),
159                )
160                .ok()
161                .map(AggregateUDF::new_from_impl)
162        });
163
164        for func in state_func {
165            registry.register_aggr(func);
166        }
167    }
168
169    /// Split an aggregate plan into two aggregate plans, one for the state function and one for the merge function.
170    ///
171    pub fn split_aggr_node(aggr_plan: Aggregate) -> datafusion_common::Result<StepAggrPlan> {
172        let aggr = {
173            // certain aggr func need type coercion to work correctly, so we need to analyze the plan first.
174            let aggr_plan = TypeCoercion::new().analyze(
175                LogicalPlan::Aggregate(aggr_plan).clone(),
176                &Default::default(),
177            )?;
178            if let LogicalPlan::Aggregate(aggr) = aggr_plan {
179                aggr
180            } else {
181                return Err(datafusion_common::DataFusionError::Internal(format!(
182                    "Failed to coerce expressions in aggregate plan, expected Aggregate, got: {:?}",
183                    aggr_plan
184                )));
185            }
186        };
187        // (unaliased state expression, output column name)
188        let mut lower_states: Vec<(Expr, String)> = vec![];
189        let mut lower_output_names: HashSet<String> = aggr
190            .group_expr
191            .iter()
192            .map(|e| e.qualified_name().1)
193            .collect();
194        let mut upper_aggr_exprs = vec![];
195
196        // group exprs for upper plan should refer to the output group expr as column from lower plan
197        // to avoid re-compute group exprs again.
198        let upper_group_exprs = aggr
199            .group_expr
200            .iter()
201            .map(|c| c.qualified_name())
202            .map(|(r, c)| Expr::Column(Column::new(r, c)))
203            .collect();
204
205        for aggr_expr in aggr.aggr_expr.iter() {
206            let Some(aggr_func) = get_aggr_func(aggr_expr) else {
207                return Err(datafusion_common::DataFusionError::NotImplemented(format!(
208                    "Unsupported aggregate expression for step aggr optimize: {:?}",
209                    aggr_expr
210                )));
211            };
212
213            let original_input_fields = aggr_func
214                .params
215                .args
216                .iter()
217                .map(|e| e.to_field(&aggr.input.schema()).map(|(_, field)| field))
218                .collect::<Result<Vec<_>, _>>()?;
219
220            // first create the state function from the original aggregate function.
221            let state_func = StateWrapper::new((*aggr_func.func).clone())?;
222
223            let expr = AggregateFunction {
224                func: Arc::new(state_func.into()),
225                params: aggr_func.params.clone(),
226            };
227            let expr = Expr::AggregateFunction(expr);
228
229            // The state column is named after the unaliased state expression, which can
230            // repeat even though the original output names are unique: a name-preserving
231            // rewrite such as `count(*)` -> `count(ts) AS count(*)` can make two aggregates
232            // share one state expression, and schema names hide casts, so
233            // `count(CAST(ts AS Int64))` is named `count(t.ts)` too. Identical states are
234            // computed once; a different state with a taken name gets a numeric suffix.
235            let lower_state_output_col_name =
236                if let Some((_, name)) = lower_states.iter().find(|(e, _)| *e == expr) {
237                    name.clone()
238                } else {
239                    let base = expr.schema_name().to_string();
240                    let mut name = base.clone();
241                    let mut suffix = 0;
242                    while lower_output_names.contains(&name) {
243                        suffix += 1;
244                        name = format!("{base}_{suffix}");
245                    }
246                    lower_output_names.insert(name.clone());
247                    lower_states.push((expr, name.clone()));
248                    name
249                };
250
251            // then create the merge function using the physical expression of the original aggregate function
252            let (name, human_display) = match aggr_expr {
253                Expr::Alias(alias) => (alias.name.clone(), aggr_expr.human_display().to_string()),
254                Expr::AggregateFunction(_) => (
255                    aggr_expr.schema_name().to_string(),
256                    aggr_expr.human_display().to_string(),
257                ),
258                _ => unreachable!("aggregate expression was validated above"),
259            };
260            let original_phy_expr = LoweredAggregateBuilder::new(
261                aggr_expr,
262                aggr.input.schema(),
263                aggr.input.schema().as_arrow(),
264                &Default::default(),
265                &PhysicalPlanningContext::default(),
266            )
267            .with_name(name)
268            .with_human_display(human_display)
269            .build()?
270            .aggregate;
271
272            let merge_func = MergeWrapper::new(
273                (*aggr_func.func).clone(),
274                original_phy_expr,
275                original_input_fields,
276            )?;
277            let arg = Expr::Column(Column::new_unqualified(lower_state_output_col_name));
278            let expr = AggregateFunction {
279                func: Arc::new(merge_func.into()),
280                // notice filter/order_by is not supported in the merge function, as it's not meaningful to have them in the merge phase.
281                // do notice this order by is only removed in the outer logical plan, the physical plan still have order by and hence
282                // can create correct accumulator with order by.
283                params: AggregateFunctionParams {
284                    args: vec![arg],
285                    distinct: aggr_func.params.distinct,
286                    filter: None,
287                    order_by: vec![],
288                    null_treatment: aggr_func.params.null_treatment,
289                },
290            };
291
292            // alias to the original aggregate expr's schema name, so parent plan can refer to it
293            // correctly.
294            let expr = Expr::AggregateFunction(expr).alias(aggr_expr.schema_name().to_string());
295            upper_aggr_exprs.push(expr);
296        }
297
298        let mut lower = aggr.clone();
299        lower.aggr_expr = lower_states
300            .into_iter()
301            .map(|(expr, name)| {
302                if expr.schema_name().to_string() == name {
303                    expr
304                } else {
305                    expr.alias(name)
306                }
307            })
308            .collect();
309        let lower_plan = LogicalPlan::Aggregate(lower);
310
311        // update aggregate's output schema
312        let lower_plan = lower_plan.recompute_schema()?;
313
314        // should only affect two udaf `first_value/last_value`
315        // which only them have meaningful order by field
316        let fixed_lower_plan =
317            FixStateUdafOrderingAnalyzer.analyze(lower_plan, &Default::default())?;
318
319        let upper = Aggregate::try_new(
320            Arc::new(fixed_lower_plan.clone()),
321            upper_group_exprs,
322            upper_aggr_exprs.clone(),
323        )?;
324        let aggr_plan = LogicalPlan::Aggregate(aggr);
325
326        // upper schema's output schema should be the same as the original aggregate plan's output schema
327        let upper_check = upper;
328        let upper_plan = LogicalPlan::Aggregate(upper_check).recompute_schema()?;
329        if *upper_plan.schema() != *aggr_plan.schema() {
330            return Err(datafusion_common::DataFusionError::Internal(format!(
331                "Upper aggregate plan's schema is not the same as the original aggregate plan's schema: \n[transformed]:{}\n[original]:{}",
332                upper_plan.schema(),
333                aggr_plan.schema()
334            )));
335        }
336
337        Ok(StepAggrPlan {
338            lower_state: fixed_lower_plan,
339            upper_merge: upper_plan,
340        })
341    }
342}
343
344/// Wrapper to make an aggregate function out of a state function.
345#[derive(Debug, Clone, PartialEq, Eq, Hash)]
346pub struct StateWrapper {
347    inner: AggregateUDF,
348    name: String,
349    /// Default to empty, might get fixed by analyzer later
350    ordering: Vec<FieldRef>,
351    /// Default to false, might get fixed by analyzer later
352    distinct: bool,
353}
354
355impl StateWrapper {
356    /// `state_index`: The index of the state in the output of the state function.
357    pub fn new(inner: AggregateUDF) -> datafusion_common::Result<Self> {
358        let name = aggr_state_func_name(inner.name());
359        Ok(Self {
360            inner,
361            name,
362            ordering: vec![],
363            distinct: false,
364        })
365    }
366
367    pub fn inner(&self) -> &AggregateUDF {
368        &self.inner
369    }
370
371    /// Deduce the return type of the original aggregate function
372    /// based on the accumulator arguments.
373    ///
374    pub fn deduce_aggr_return_type(
375        &self,
376        acc_args: &datafusion_expr::function::AccumulatorArgs,
377    ) -> datafusion_common::Result<FieldRef> {
378        let input_fields = acc_args
379            .exprs
380            .iter()
381            .map(|e| e.return_field(acc_args.schema))
382            .collect::<Result<Vec<_>, _>>()?;
383        self.inner.return_field(&input_fields).inspect_err(|e| {
384            common_telemetry::error!(
385                "StateWrapper: {:#?}\nacc_args:{:?}\nerror:{:?}",
386                &self,
387                &acc_args,
388                e
389            );
390        })
391    }
392
393    fn fix_inner_acc_args<'b>(
394        &self,
395        mut acc_args: datafusion_expr::function::AccumulatorArgs<'b>,
396    ) -> datafusion_common::Result<datafusion_expr::function::AccumulatorArgs<'b>> {
397        acc_args.return_field = self.deduce_aggr_return_type(&acc_args)?;
398        Ok(acc_args)
399    }
400}
401
402impl AggregateUDFImpl for StateWrapper {
403    fn accumulator<'a, 'b>(
404        &'a self,
405        acc_args: datafusion_expr::function::AccumulatorArgs<'b>,
406    ) -> datafusion_common::Result<Box<dyn Accumulator>> {
407        // fix and recover proper acc args for the original aggregate function.
408        let state_type = acc_args.return_type().clone();
409        let inner = self.inner.accumulator(self.fix_inner_acc_args(acc_args)?)?;
410
411        Ok(Box::new(StateAccum::new(inner, state_type)?))
412    }
413
414    fn groups_accumulator_supported(
415        &self,
416        acc_args: datafusion_expr::function::AccumulatorArgs,
417    ) -> bool {
418        self.fix_inner_acc_args(acc_args)
419            .map(|args| self.inner.inner().groups_accumulator_supported(args))
420            .unwrap_or(false)
421    }
422
423    fn create_groups_accumulator(
424        &self,
425        acc_args: datafusion_expr::function::AccumulatorArgs,
426    ) -> datafusion_common::Result<Box<dyn GroupsAccumulator>> {
427        let state_type = acc_args.return_type().clone();
428        let inner = self
429            .inner
430            .inner()
431            .create_groups_accumulator(self.fix_inner_acc_args(acc_args)?)?;
432        Ok(Box::new(StateGroupsAccum::new(inner, state_type)?))
433    }
434
435    fn name(&self) -> &str {
436        self.name.as_str()
437    }
438
439    fn is_nullable(&self) -> bool {
440        self.inner.is_nullable()
441    }
442
443    /// Return state_fields as the output struct type.
444    ///
445    fn return_type(&self, arg_types: &[DataType]) -> datafusion_common::Result<DataType> {
446        let input_fields = &arg_types
447            .iter()
448            .map(|x| Arc::new(Field::new("x", x.clone(), false)))
449            .collect::<Vec<_>>();
450
451        let state_fields_args = StateFieldsArgs {
452            name: self.inner().name(),
453            input_fields,
454            return_field: self.inner.return_field(input_fields)?,
455            // those args are also needed as they are vital to construct the state fields correctly.
456            ordering_fields: &self.ordering,
457            is_distinct: self.distinct,
458        };
459        let state_fields = self.inner.state_fields(state_fields_args)?;
460
461        let state_fields = state_fields
462            .into_iter()
463            .map(|f| {
464                let mut f = f.as_ref().clone();
465                // since state can be null when no input rows, so make all fields nullable
466                f.set_nullable(true);
467                Arc::new(f)
468            })
469            .collect::<Vec<_>>();
470
471        let struct_field = DataType::Struct(state_fields.into());
472        Ok(struct_field)
473    }
474
475    /// The state function's output fields are the same as the original aggregate function's state fields.
476    fn state_fields(
477        &self,
478        args: datafusion_expr::function::StateFieldsArgs,
479    ) -> datafusion_common::Result<Vec<FieldRef>> {
480        let state_fields_args = StateFieldsArgs {
481            name: args.name,
482            input_fields: args.input_fields,
483            return_field: self.inner.return_field(args.input_fields)?,
484            ordering_fields: args.ordering_fields,
485            is_distinct: args.is_distinct,
486        };
487        self.inner.state_fields(state_fields_args)
488    }
489
490    /// The state function's signature is the same as the original aggregate function's signature,
491    fn signature(&self) -> &Signature {
492        self.inner.signature()
493    }
494
495    /// Coerce types also do nothing, as optimizer should be able to already make struct types
496    fn coerce_types(&self, arg_types: &[DataType]) -> datafusion_common::Result<Vec<DataType>> {
497        self.inner.coerce_types(arg_types)
498    }
499
500    fn value_from_stats(
501        &self,
502        statistics_args: &datafusion_expr::StatisticsArgs,
503    ) -> Option<ScalarValue> {
504        let inner = self.inner().inner();
505        // only count/min/max need special handling here, for getting result from statistics
506        // the result of count/min/max is also the result of count_state so can return directly
507        let can_use_stat = inner.is::<Count>() || inner.is::<Max>() || inner.is::<Min>();
508        if !can_use_stat {
509            return None;
510        }
511
512        // fix return type by extract the first field's data type from the struct type
513        let state_type = if let DataType::Struct(fields) = &statistics_args.return_type {
514            if fields.is_empty() {
515                return None;
516            }
517            fields[0].data_type().clone()
518        } else {
519            return None;
520        };
521
522        let fixed_args = datafusion_expr::StatisticsArgs {
523            statistics: statistics_args.statistics,
524            return_type: &state_type,
525            is_distinct: statistics_args.is_distinct,
526            exprs: statistics_args.exprs,
527        };
528
529        let ret = self.inner().value_from_stats(&fixed_args)?;
530
531        // wrap the result into struct scalar value
532        let fields = if let DataType::Struct(fields) = &statistics_args.return_type {
533            fields
534        } else {
535            return None;
536        };
537
538        let array = ret.to_array().ok()?;
539
540        let struct_array = StructArray::new(fields.clone(), vec![array], None);
541        let ret = ScalarValue::Struct(Arc::new(struct_array));
542        Some(ret)
543    }
544}
545
546/// The wrapper's input is the same as the original aggregate function's input,
547/// and the output is the state function's output.
548#[derive(Debug)]
549pub struct StateAccum {
550    inner: Box<dyn Accumulator>,
551    state_fields: Fields,
552}
553
554pub struct StateGroupsAccum {
555    inner: Box<dyn GroupsAccumulator>,
556    state_fields: Fields,
557}
558
559impl StateGroupsAccum {
560    fn new(
561        inner: Box<dyn GroupsAccumulator>,
562        state_type: DataType,
563    ) -> datafusion_common::Result<Self> {
564        let DataType::Struct(fields) = state_type else {
565            return Err(datafusion_common::DataFusionError::Internal(format!(
566                "Expected a struct type for state, got: {:?}",
567                state_type
568            )));
569        };
570        Ok(Self {
571            inner,
572            state_fields: fields,
573        })
574    }
575
576    fn wrap_state_arrays(&self, arrays: Vec<ArrayRef>) -> datafusion_common::Result<ArrayRef> {
577        Ok(Arc::new(state_struct_array(&self.state_fields, arrays)?))
578    }
579}
580
581impl GroupsAccumulator for StateGroupsAccum {
582    fn update_batch(
583        &mut self,
584        values: &[ArrayRef],
585        group_indices: &[usize],
586        opt_filter: Option<&BooleanArray>,
587        total_num_groups: usize,
588    ) -> datafusion_common::Result<()> {
589        self.inner
590            .update_batch(values, group_indices, opt_filter, total_num_groups)
591    }
592
593    fn merge_batch(
594        &mut self,
595        values: &[ArrayRef],
596        group_indices: &[usize],
597        total_num_groups: usize,
598    ) -> datafusion_common::Result<()> {
599        self.inner
600            .merge_batch(values, group_indices, total_num_groups)
601    }
602
603    fn evaluate(&mut self, emit_to: EmitTo) -> datafusion_common::Result<ArrayRef> {
604        let state = self.inner.state(emit_to)?;
605        self.wrap_state_arrays(state)
606    }
607
608    fn state(&mut self, emit_to: EmitTo) -> datafusion_common::Result<Vec<ArrayRef>> {
609        self.inner.state(emit_to)
610    }
611
612    fn convert_to_state(
613        &self,
614        values: &[ArrayRef],
615        opt_filter: Option<&BooleanArray>,
616    ) -> datafusion_common::Result<Vec<ArrayRef>> {
617        self.inner.convert_to_state(values, opt_filter)
618    }
619
620    fn size(&self) -> usize {
621        self.inner.size()
622    }
623}
624
625/// Wraps the state arrays of an accumulator into a struct of the declared state fields.
626///
627/// The declared state type is derived from logical expressions, while the accumulator names
628/// nested fields after physical expressions. For example, `array_agg(v ORDER BY ts)` declares
629/// its orderings as `List(Struct("ts": ..))` but produces `List(Struct("ts@0": ..))`. Arrays that
630/// differ only in nested field names are cast to the declared type; any other difference is an
631/// error.
632fn state_struct_array(
633    state_fields: &Fields,
634    arrays: Vec<ArrayRef>,
635) -> datafusion_common::Result<StructArray> {
636    if arrays.len() != state_fields.len() {
637        return Err(datafusion_common::DataFusionError::Internal(format!(
638            "Expected {} state arrays for fields {:?}, got {}",
639            state_fields.len(),
640            state_fields,
641            arrays.len()
642        )));
643    }
644    let arrays = arrays
645        .into_iter()
646        .zip(state_fields.iter())
647        .map(|(array, field)| {
648            let expected = field.data_type();
649            if array.data_type() == expected {
650                Ok(array)
651            } else if array.data_type().equals_datatype(expected) {
652                Ok(make_array(relabel_nested_fields(
653                    array.to_data(),
654                    expected,
655                )?))
656            } else {
657                Err(datafusion_common::DataFusionError::Internal(format!(
658                    "State field `{}` expects type {expected}, but the accumulator produced {}",
659                    field.name(),
660                    array.data_type()
661                )))
662            }
663        })
664        .collect::<datafusion_common::Result<Vec<_>>>()?;
665    Ok(StructArray::try_new(state_fields.clone(), arrays, None)?)
666}
667
668/// Rebuilds `data` with the type `target`, which must match it position by position apart
669/// from nested field names and metadata. Unlike a cast, children are never matched by name.
670fn relabel_nested_fields(
671    data: ArrayData,
672    target: &DataType,
673) -> datafusion_common::Result<ArrayData> {
674    let child_types = match target {
675        DataType::List(field)
676        | DataType::LargeList(field)
677        | DataType::FixedSizeList(field, _)
678        | DataType::Map(field, _) => vec![field.data_type()],
679        DataType::Struct(fields) => fields.iter().map(|f| f.data_type()).collect(),
680        _ if data.child_data().is_empty() => vec![],
681        _ => {
682            return Err(datafusion_common::DataFusionError::NotImplemented(format!(
683                "Relabeling nested fields of {target}"
684            )));
685        }
686    };
687    let children = data
688        .child_data()
689        .iter()
690        .zip(child_types)
691        .map(|(child, child_type)| relabel_nested_fields(child.clone(), child_type))
692        .collect::<datafusion_common::Result<Vec<_>>>()?;
693    Ok(data
694        .into_builder()
695        .data_type(target.clone())
696        .child_data(children)
697        .build()?)
698}
699
700impl StateAccum {
701    pub fn new(
702        inner: Box<dyn Accumulator>,
703        state_type: DataType,
704    ) -> datafusion_common::Result<Self> {
705        let DataType::Struct(fields) = state_type else {
706            return Err(datafusion_common::DataFusionError::Internal(format!(
707                "Expected a struct type for state, got: {:?}",
708                state_type
709            )));
710        };
711        Ok(Self {
712            inner,
713            state_fields: fields,
714        })
715    }
716}
717
718impl Accumulator for StateAccum {
719    fn evaluate(&mut self) -> datafusion_common::Result<ScalarValue> {
720        let state = self.inner.state()?;
721
722        let array = state
723            .iter()
724            .map(|s| s.to_array())
725            .collect::<Result<Vec<_>, _>>()?;
726        let struct_array = state_struct_array(&self.state_fields, array)?;
727        Ok(ScalarValue::Struct(Arc::new(struct_array)))
728    }
729
730    fn merge_batch(
731        &mut self,
732        states: &[datatypes::arrow::array::ArrayRef],
733    ) -> datafusion_common::Result<()> {
734        self.inner.merge_batch(states)
735    }
736
737    fn update_batch(
738        &mut self,
739        values: &[datatypes::arrow::array::ArrayRef],
740    ) -> datafusion_common::Result<()> {
741        self.inner.update_batch(values)
742    }
743
744    fn size(&self) -> usize {
745        self.inner.size()
746    }
747
748    fn state(&mut self) -> datafusion_common::Result<Vec<ScalarValue>> {
749        self.inner.state()
750    }
751}
752
753/// A globally registerable wrapper for a state-family merge UDAF.
754///
755/// The wrapped merge function has the family contract `P..., State`. This
756/// wrapper exposes `P..., delta_state, persisted_state` and forwards the two
757/// state columns to the existing accumulator in that order. State values are
758/// opaque to this adapter; null is the inner merge family's identity value.
759#[derive(Debug, Clone)]
760pub(crate) struct DeltaMergeWrapper {
761    inner: AggregateUDF,
762    name: String,
763    signature: Signature,
764    inner_types: Vec<DataType>,
765    state_type: DataType,
766}
767
768impl DeltaMergeWrapper {
769    /// Build the wrapper for one of the explicitly supported exact merge UDAFs.
770    ///
771    /// The caller supplies the known merge signature, so construction cannot
772    /// fail while inspecting an arbitrary UDAF signature.
773    pub(crate) fn new(
774        inner: AggregateUDF,
775        state_name: &str,
776        inner_types: Vec<DataType>,
777        state_type: DataType,
778    ) -> Self {
779        let mut wrapper_types = inner_types.clone();
780        wrapper_types.push(state_type.clone());
781        Self {
782            name: aggr_delta_merge_func_name(state_name),
783            signature: Signature::exact(wrapper_types, inner.signature().volatility),
784            inner,
785            inner_types,
786            state_type,
787        }
788    }
789
790    fn resolve_inner_args(
791        &self,
792        input_fields: &[FieldRef],
793    ) -> datafusion_common::Result<Vec<FieldRef>> {
794        if input_fields.len() != self.inner_types.len() + 1 {
795            return Err(datafusion_common::DataFusionError::Plan(
796                "delta merge requires parameters, delta state, and persisted state".to_string(),
797            ));
798        }
799        for (field, expected_type) in input_fields[..self.inner_types.len()]
800            .iter()
801            .zip(&self.inner_types)
802        {
803            if field.data_type() != expected_type {
804                return Err(datafusion_common::DataFusionError::Plan(format!(
805                    "delta merge argument type does not match its exact signature: {:?} != {expected_type:?}",
806                    field.data_type()
807                )));
808            }
809        }
810        let persisted = &input_fields[self.inner_types.len()];
811        if persisted.data_type() != &self.state_type && persisted.data_type() != &DataType::Null {
812            return Err(datafusion_common::DataFusionError::Plan(format!(
813                "persisted state type does not match the exact state type: {:?} != {:?}",
814                persisted.data_type(),
815                self.state_type
816            )));
817        }
818        Ok(input_fields[..self.inner_types.len()].to_vec())
819    }
820}
821
822impl AggregateUDFImpl for DeltaMergeWrapper {
823    fn accumulator<'a, 'b>(
824        &'a self,
825        acc_args: datafusion_expr::function::AccumulatorArgs<'b>,
826    ) -> datafusion_common::Result<Box<dyn Accumulator>> {
827        if acc_args.exprs.len() != acc_args.expr_fields.len() {
828            return Err(datafusion_common::DataFusionError::Plan(
829                "delta merge expression and field arities differ".to_string(),
830            ));
831        }
832        let inner_fields = self.resolve_inner_args(acc_args.expr_fields)?;
833        for (expr, expected_type) in acc_args.exprs.iter().zip(
834            self.inner_types
835                .iter()
836                .chain(std::iter::once(&self.state_type)),
837        ) {
838            if expr.data_type(acc_args.schema)? != *expected_type {
839                return Err(datafusion_common::DataFusionError::Internal(
840                    "delta merge physical expression type is not resolved".to_string(),
841                ));
842            }
843        }
844        let state_index = self.inner_types.len() - 1;
845        let inner_args = datafusion_expr::function::AccumulatorArgs {
846            return_field: acc_args.return_field,
847            schema: acc_args.schema,
848            ignore_nulls: acc_args.ignore_nulls,
849            order_bys: acc_args.order_bys,
850            is_reversed: acc_args.is_reversed,
851            name: self.inner.name(),
852            is_distinct: acc_args.is_distinct,
853            exprs: &acc_args.exprs[..=state_index],
854            expr_fields: &inner_fields,
855        };
856        Ok(Box::new(DeltaMergeAccum {
857            inner: self.inner.accumulator(inner_args)?,
858            params: state_index,
859        }))
860    }
861
862    fn name(&self) -> &str {
863        &self.name
864    }
865
866    fn is_nullable(&self) -> bool {
867        self.inner.is_nullable()
868    }
869
870    fn return_type(&self, arg_types: &[DataType]) -> datafusion_common::Result<DataType> {
871        let fields = arg_types
872            .iter()
873            .enumerate()
874            .map(|(index, data_type)| {
875                Arc::new(Field::new(index.to_string(), data_type.clone(), true))
876            })
877            .collect::<Vec<_>>();
878        let inner_fields = self.resolve_inner_args(&fields)?;
879        self.inner.return_type(
880            &inner_fields
881                .iter()
882                .map(|field| field.data_type().clone())
883                .collect::<Vec<_>>(),
884        )
885    }
886
887    fn return_field(&self, arg_fields: &[FieldRef]) -> datafusion_common::Result<FieldRef> {
888        let inner_fields = self.resolve_inner_args(arg_fields)?;
889        self.inner.return_field(&inner_fields)
890    }
891
892    fn signature(&self) -> &Signature {
893        &self.signature
894    }
895
896    fn state_fields(
897        &self,
898        args: datafusion_expr::function::StateFieldsArgs,
899    ) -> datafusion_common::Result<Vec<FieldRef>> {
900        let inner_fields = self.resolve_inner_args(args.input_fields)?;
901        self.inner
902            .state_fields(datafusion_expr::function::StateFieldsArgs {
903                name: args.name,
904                input_fields: &inner_fields,
905                return_field: args.return_field,
906                ordering_fields: args.ordering_fields,
907                is_distinct: args.is_distinct,
908            })
909    }
910}
911
912impl PartialEq for DeltaMergeWrapper {
913    fn eq(&self, other: &Self) -> bool {
914        self.name == other.name && self.inner == other.inner
915    }
916}
917impl Eq for DeltaMergeWrapper {}
918impl Hash for DeltaMergeWrapper {
919    fn hash<H: Hasher>(&self, state: &mut H) {
920        self.name.hash(state);
921        self.inner.hash(state);
922    }
923}
924
925#[derive(Debug)]
926struct DeltaMergeAccum {
927    inner: Box<dyn Accumulator>,
928    params: usize,
929}
930
931impl Accumulator for DeltaMergeAccum {
932    fn evaluate(&mut self) -> datafusion_common::Result<ScalarValue> {
933        self.inner.evaluate()
934    }
935
936    fn update_batch(&mut self, values: &[ArrayRef]) -> datafusion_common::Result<()> {
937        if values.len() != self.params + 2 {
938            return Err(datafusion_common::DataFusionError::Plan(format!(
939                "delta merge expected {} arguments, got {}",
940                self.params + 2,
941                values.len()
942            )));
943        }
944        // Null-state identity is an inner family precondition. The wrapper
945        // forwards opaque states and never decodes or filters them.
946        let mut inner_values = values[..self.params + 1].to_vec();
947        self.inner.update_batch(&inner_values)?;
948        inner_values[self.params] = values[self.params + 1].clone();
949        self.inner.update_batch(&inner_values)
950    }
951
952    fn merge_batch(&mut self, states: &[ArrayRef]) -> datafusion_common::Result<()> {
953        self.inner.merge_batch(states)
954    }
955
956    fn size(&self) -> usize {
957        self.inner.size()
958    }
959
960    fn state(&mut self) -> datafusion_common::Result<Vec<ScalarValue>> {
961        self.inner.state()
962    }
963}
964
965/// TODO(discord9): mark this function as non-ser/de able
966///
967/// This wrapper shouldn't be register as a udaf, as it contain extra data that is not serializable.
968/// and changes for different logical plans.
969#[derive(Debug, Clone)]
970pub struct MergeWrapper {
971    inner: AggregateUDF,
972    name: String,
973    merge_signature: Signature,
974    /// The original physical expression of the aggregate function, can't store the original aggregate function directly, as PhysicalExpr didn't implement Any
975    original_phy_expr: Arc<AggregateFunctionExpr>,
976    return_field: FieldRef,
977}
978impl MergeWrapper {
979    pub fn new(
980        inner: AggregateUDF,
981        original_phy_expr: Arc<AggregateFunctionExpr>,
982        original_input_fields: Vec<FieldRef>,
983    ) -> datafusion_common::Result<Self> {
984        let name = aggr_merge_func_name(inner.name());
985        // the input type is actually struct type, which is the state fields of the original aggregate function.
986        let merge_signature = Signature::user_defined(datafusion_expr::Volatility::Immutable);
987        let return_field = inner.return_field(&original_input_fields)?.clone();
988
989        Ok(Self {
990            inner,
991            name,
992            merge_signature,
993            original_phy_expr,
994            return_field,
995        })
996    }
997
998    pub fn inner(&self) -> &AggregateUDF {
999        &self.inner
1000    }
1001}
1002
1003impl AggregateUDFImpl for MergeWrapper {
1004    fn accumulator<'a, 'b>(
1005        &'a self,
1006        acc_args: datafusion_expr::function::AccumulatorArgs<'b>,
1007    ) -> datafusion_common::Result<Box<dyn Accumulator>> {
1008        if acc_args.exprs.len() != 1
1009            || !matches!(
1010                acc_args.exprs[0].data_type(acc_args.schema)?,
1011                DataType::Struct(_)
1012            )
1013        {
1014            return Err(datafusion_common::DataFusionError::Internal(format!(
1015                "Expected one struct type as input, got: {:?}",
1016                acc_args.schema
1017            )));
1018        }
1019        let input_type = acc_args.exprs[0].data_type(acc_args.schema)?;
1020        let DataType::Struct(fields) = input_type else {
1021            return Err(datafusion_common::DataFusionError::Internal(format!(
1022                "Expected a struct type for input, got: {:?}",
1023                input_type
1024            )));
1025        };
1026
1027        let inner_accum = self.original_phy_expr.create_accumulator()?;
1028        Ok(Box::new(MergeAccum::new(inner_accum, &fields)))
1029    }
1030
1031    fn name(&self) -> &str {
1032        self.name.as_str()
1033    }
1034
1035    fn is_nullable(&self) -> bool {
1036        self.inner.is_nullable()
1037    }
1038
1039    /// Notice here the `arg_types` is actually the `state_fields`'s data types,
1040    /// so return fixed return type instead of using `arg_types` to determine the return type.
1041    fn return_type(&self, _arg_types: &[DataType]) -> datafusion_common::Result<DataType> {
1042        // The return type is the same as the original aggregate function's return type.
1043        Ok(self.return_field.data_type().clone())
1044    }
1045
1046    /// Similar to return_type, we just return the fixed return field.
1047    fn return_field(&self, _arg_fields: &[FieldRef]) -> datafusion_common::Result<FieldRef> {
1048        Ok(self.return_field.clone())
1049    }
1050
1051    fn signature(&self) -> &Signature {
1052        &self.merge_signature
1053    }
1054
1055    /// Coerce types also do nothing, as optimizer should be able to already make struct types
1056    fn coerce_types(&self, arg_types: &[DataType]) -> datafusion_common::Result<Vec<DataType>> {
1057        // just check if the arg_types are only one and is struct array
1058        if arg_types.len() != 1 || !matches!(arg_types.first(), Some(DataType::Struct(_))) {
1059            return Err(datafusion_common::DataFusionError::Internal(format!(
1060                "Expected one struct type as input, got: {:?}",
1061                arg_types
1062            )));
1063        }
1064        Ok(arg_types.to_vec())
1065    }
1066
1067    /// Just return the original aggregate function's state fields.
1068    fn state_fields(
1069        &self,
1070        _args: datafusion_expr::function::StateFieldsArgs,
1071    ) -> datafusion_common::Result<Vec<FieldRef>> {
1072        self.original_phy_expr.state_fields()
1073    }
1074}
1075
1076impl PartialEq for MergeWrapper {
1077    fn eq(&self, other: &Self) -> bool {
1078        self.inner == other.inner
1079    }
1080}
1081
1082impl Eq for MergeWrapper {}
1083
1084impl Hash for MergeWrapper {
1085    fn hash<H: Hasher>(&self, state: &mut H) {
1086        self.inner.hash(state);
1087    }
1088}
1089
1090/// The merge accumulator, which modify `update_batch`'s behavior to accept one struct array which
1091/// include the state fields of original aggregate function, and merge said states into original accumulator
1092/// the output is the same as original aggregate function
1093#[derive(Debug)]
1094pub struct MergeAccum {
1095    inner: Box<dyn Accumulator>,
1096    state_fields: Fields,
1097}
1098
1099impl MergeAccum {
1100    pub fn new(inner: Box<dyn Accumulator>, state_fields: &Fields) -> Self {
1101        Self {
1102            inner,
1103            state_fields: state_fields.clone(),
1104        }
1105    }
1106}
1107
1108impl Accumulator for MergeAccum {
1109    fn evaluate(&mut self) -> datafusion_common::Result<ScalarValue> {
1110        self.inner.evaluate()
1111    }
1112
1113    fn merge_batch(&mut self, states: &[arrow::array::ArrayRef]) -> datafusion_common::Result<()> {
1114        self.inner.merge_batch(states)
1115    }
1116
1117    fn update_batch(&mut self, values: &[arrow::array::ArrayRef]) -> datafusion_common::Result<()> {
1118        let value = values.first().ok_or_else(|| {
1119            datafusion_common::DataFusionError::Internal("No values provided for merge".to_string())
1120        })?;
1121        // The input values are states from other accumulators, so we merge them.
1122        let struct_arr = value
1123            .as_any()
1124            .downcast_ref::<StructArray>()
1125            .ok_or_else(|| {
1126                datafusion_common::DataFusionError::Internal(format!(
1127                    "Expected StructArray, got: {:?}",
1128                    value.data_type()
1129                ))
1130            })?;
1131        let fields = struct_arr.fields();
1132        if fields != &self.state_fields {
1133            debug!(
1134                "State fields mismatch, expected: {:?}, got: {:?}",
1135                self.state_fields, fields
1136            );
1137            // state fields mismatch might be acceptable by datafusion, continue
1138        }
1139
1140        // now fields should be the same, so we can merge the batch
1141        // by pass the columns as order should be the same
1142        let state_columns = struct_arr.columns();
1143        self.inner.merge_batch(state_columns)
1144    }
1145
1146    fn size(&self) -> usize {
1147        self.inner.size()
1148    }
1149
1150    fn state(&mut self) -> datafusion_common::Result<Vec<ScalarValue>> {
1151        self.inner.state()
1152    }
1153}