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