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