Skip to main content

datafusion_functions_aggregate/
min_max.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! [`Max`] and [`MaxAccumulator`] accumulator for the `max` function
19//! [`Min`] and [`MinAccumulator`] accumulator for the `min` function
20
21mod min_max_bytes;
22mod min_max_struct;
23
24use arrow::array::ArrayRef;
25use arrow::datatypes::{
26    DataType, Decimal32Type, Decimal64Type, Decimal128Type, Decimal256Type,
27    DurationMicrosecondType, DurationMillisecondType, DurationNanosecondType,
28    DurationSecondType, Float16Type, Float32Type, Float64Type, Int8Type, Int16Type,
29    Int32Type, Int64Type, UInt8Type, UInt16Type, UInt32Type, UInt64Type,
30};
31use datafusion_common::stats::Precision;
32use datafusion_common::{ColumnStatistics, Result, exec_err, internal_err};
33use datafusion_functions_aggregate_common::aggregate::groups_accumulator::prim_op::PrimitiveGroupsAccumulator;
34use datafusion_physical_expr::expressions;
35use std::cmp::Ordering;
36use std::fmt::Debug;
37
38use arrow::datatypes::i256;
39use arrow::datatypes::{
40    Date32Type, Date64Type, Time32MillisecondType, Time32SecondType,
41    Time64MicrosecondType, Time64NanosecondType, TimeUnit, TimestampMicrosecondType,
42    TimestampMillisecondType, TimestampNanosecondType, TimestampSecondType,
43};
44
45use crate::min_max::min_max_bytes::MinMaxBytesAccumulator;
46use crate::min_max::min_max_struct::MinMaxStructAccumulator;
47use datafusion_common::ScalarValue;
48use datafusion_expr::{
49    Accumulator, AggregateUDFImpl, Documentation, SetMonotonicity, Signature, Volatility,
50    function::AccumulatorArgs,
51};
52use datafusion_expr::{GroupsAccumulator, StatisticsArgs};
53use datafusion_macros::user_doc;
54use half::f16;
55use std::collections::VecDeque;
56use std::mem::{size_of, size_of_val};
57use std::ops::Deref;
58
59fn get_min_max_result_type(input_types: &[DataType]) -> Result<Vec<DataType>> {
60    // make sure that the input types only has one element.
61    if input_types.len() != 1 {
62        return exec_err!(
63            "min/max was called with {} arguments. It requires only 1.",
64            input_types.len()
65        );
66    }
67    // min and max support the dictionary data type
68    // unpack the dictionary to get the value
69    match &input_types[0] {
70        DataType::Dictionary(_, dict_value_type) => {
71            // TODO add checker, if the value type is complex data type
72            Ok(vec![dict_value_type.deref().clone()])
73        }
74        // TODO add checker for datatype which min and max supported
75        // For example, the `Struct` and `Map` type are not supported in the MIN and MAX function
76        _ => Ok(input_types.to_vec()),
77    }
78}
79
80#[user_doc(
81    doc_section(label = "General Functions"),
82    description = "Returns the maximum value in the specified column.",
83    syntax_example = "max(expression)",
84    sql_example = r#"```sql
85> SELECT max(column_name) FROM table_name;
86+----------------------+
87| max(column_name)      |
88+----------------------+
89| 150                  |
90+----------------------+
91```"#,
92    standard_argument(name = "expression",)
93)]
94// MAX aggregate UDF
95#[derive(Debug, PartialEq, Eq, Hash)]
96pub struct Max {
97    signature: Signature,
98}
99
100impl Max {
101    pub fn new() -> Self {
102        Self {
103            signature: Signature::user_defined(Volatility::Immutable),
104        }
105    }
106}
107
108impl Default for Max {
109    fn default() -> Self {
110        Self::new()
111    }
112}
113/// Creates a [`PrimitiveGroupsAccumulator`] for computing `MAX`
114/// the specified [`ArrowPrimitiveType`].
115///
116/// [`ArrowPrimitiveType`]: arrow::datatypes::ArrowPrimitiveType
117macro_rules! primitive_max_accumulator {
118    ($DATA_TYPE:ident, $NATIVE:ident, $PRIMTYPE:ident) => {{
119        Ok(Box::new(
120            PrimitiveGroupsAccumulator::<$PRIMTYPE, _>::new($DATA_TYPE, |cur, new| {
121                match (new).partial_cmp(cur) {
122                    Some(Ordering::Greater) | None => {
123                        // new is Greater or None
124                        *cur = new
125                    }
126                    _ => {}
127                }
128            })
129            // Initialize each accumulator to $NATIVE::MIN
130            .with_starting_value($NATIVE::MIN),
131        ))
132    }};
133}
134
135/// Creates a [`PrimitiveGroupsAccumulator`] for computing `MIN`
136/// the specified [`ArrowPrimitiveType`].
137///
138///
139/// [`ArrowPrimitiveType`]: arrow::datatypes::ArrowPrimitiveType
140macro_rules! primitive_min_accumulator {
141    ($DATA_TYPE:ident, $NATIVE:ident, $PRIMTYPE:ident) => {{
142        Ok(Box::new(
143            PrimitiveGroupsAccumulator::<$PRIMTYPE, _>::new(&$DATA_TYPE, |cur, new| {
144                match (new).partial_cmp(cur) {
145                    Some(Ordering::Less) | None => {
146                        // new is Less or NaN
147                        *cur = new
148                    }
149                    _ => {}
150                }
151            })
152            // Initialize each accumulator to $NATIVE::MAX
153            .with_starting_value($NATIVE::MAX),
154        ))
155    }};
156}
157
158trait FromColumnStatistics {
159    fn value_from_column_statistics(
160        &self,
161        stats: &ColumnStatistics,
162    ) -> Option<ScalarValue>;
163
164    fn value_from_statistics(
165        &self,
166        statistics_args: &StatisticsArgs,
167    ) -> Option<ScalarValue> {
168        if let Precision::Exact(num_rows) = &statistics_args.statistics.num_rows {
169            match *num_rows {
170                0 => return ScalarValue::try_from(statistics_args.return_type).ok(),
171                value if value > 0 => {
172                    let col_stats = &statistics_args.statistics.column_statistics;
173                    if statistics_args.exprs.len() == 1 {
174                        // TODO optimize with exprs other than Column
175                        if let Some(col_expr) =
176                            statistics_args.exprs[0].downcast_ref::<expressions::Column>()
177                        {
178                            return self.value_from_column_statistics(
179                                &col_stats[col_expr.index()],
180                            );
181                        }
182                    }
183                }
184                _ => {}
185            }
186        }
187        None
188    }
189}
190
191impl FromColumnStatistics for Max {
192    fn value_from_column_statistics(
193        &self,
194        col_stats: &ColumnStatistics,
195    ) -> Option<ScalarValue> {
196        if let Precision::Exact(ref val) = col_stats.max_value
197            && !val.is_null()
198        {
199            return Some(val.clone());
200        }
201        None
202    }
203}
204
205impl AggregateUDFImpl for Max {
206    fn name(&self) -> &str {
207        "max"
208    }
209
210    fn signature(&self) -> &Signature {
211        &self.signature
212    }
213
214    fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
215        Ok(arg_types[0].to_owned())
216    }
217
218    fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
219        Ok(Box::new(MaxAccumulator::try_new(
220            acc_args.return_field.data_type(),
221        )?))
222    }
223
224    fn groups_accumulator_supported(&self, args: AccumulatorArgs) -> bool {
225        use DataType::*;
226        matches!(
227            args.return_field.data_type(),
228            Int8 | Int16
229                | Int32
230                | Int64
231                | UInt8
232                | UInt16
233                | UInt32
234                | UInt64
235                | Float16
236                | Float32
237                | Float64
238                | Decimal32(_, _)
239                | Decimal64(_, _)
240                | Decimal128(_, _)
241                | Decimal256(_, _)
242                | Date32
243                | Date64
244                | Time32(_)
245                | Time64(_)
246                | Timestamp(_, _)
247                | Utf8
248                | LargeUtf8
249                | Utf8View
250                | Binary
251                | LargeBinary
252                | BinaryView
253                | Duration(_)
254                | Struct(_)
255        )
256    }
257
258    fn create_groups_accumulator(
259        &self,
260        args: AccumulatorArgs,
261    ) -> Result<Box<dyn GroupsAccumulator>> {
262        use DataType::*;
263        use TimeUnit::*;
264        let data_type = args.return_field.data_type();
265        match data_type {
266            Int8 => primitive_max_accumulator!(data_type, i8, Int8Type),
267            Int16 => primitive_max_accumulator!(data_type, i16, Int16Type),
268            Int32 => primitive_max_accumulator!(data_type, i32, Int32Type),
269            Int64 => primitive_max_accumulator!(data_type, i64, Int64Type),
270            UInt8 => primitive_max_accumulator!(data_type, u8, UInt8Type),
271            UInt16 => primitive_max_accumulator!(data_type, u16, UInt16Type),
272            UInt32 => primitive_max_accumulator!(data_type, u32, UInt32Type),
273            UInt64 => primitive_max_accumulator!(data_type, u64, UInt64Type),
274            Float16 => {
275                primitive_max_accumulator!(data_type, f16, Float16Type)
276            }
277            Float32 => {
278                primitive_max_accumulator!(data_type, f32, Float32Type)
279            }
280            Float64 => {
281                primitive_max_accumulator!(data_type, f64, Float64Type)
282            }
283            Date32 => primitive_max_accumulator!(data_type, i32, Date32Type),
284            Date64 => primitive_max_accumulator!(data_type, i64, Date64Type),
285            Time32(Second) => {
286                primitive_max_accumulator!(data_type, i32, Time32SecondType)
287            }
288            Time32(Millisecond) => {
289                primitive_max_accumulator!(data_type, i32, Time32MillisecondType)
290            }
291            Time64(Microsecond) => {
292                primitive_max_accumulator!(data_type, i64, Time64MicrosecondType)
293            }
294            Time64(Nanosecond) => {
295                primitive_max_accumulator!(data_type, i64, Time64NanosecondType)
296            }
297            Timestamp(Second, _) => {
298                primitive_max_accumulator!(data_type, i64, TimestampSecondType)
299            }
300            Timestamp(Millisecond, _) => {
301                primitive_max_accumulator!(data_type, i64, TimestampMillisecondType)
302            }
303            Timestamp(Microsecond, _) => {
304                primitive_max_accumulator!(data_type, i64, TimestampMicrosecondType)
305            }
306            Timestamp(Nanosecond, _) => {
307                primitive_max_accumulator!(data_type, i64, TimestampNanosecondType)
308            }
309            Duration(Second) => {
310                primitive_max_accumulator!(data_type, i64, DurationSecondType)
311            }
312            Duration(Millisecond) => {
313                primitive_max_accumulator!(data_type, i64, DurationMillisecondType)
314            }
315            Duration(Microsecond) => {
316                primitive_max_accumulator!(data_type, i64, DurationMicrosecondType)
317            }
318            Duration(Nanosecond) => {
319                primitive_max_accumulator!(data_type, i64, DurationNanosecondType)
320            }
321            Decimal32(_, _) => {
322                primitive_max_accumulator!(data_type, i32, Decimal32Type)
323            }
324            Decimal64(_, _) => {
325                primitive_max_accumulator!(data_type, i64, Decimal64Type)
326            }
327            Decimal128(_, _) => {
328                primitive_max_accumulator!(data_type, i128, Decimal128Type)
329            }
330            Decimal256(_, _) => {
331                primitive_max_accumulator!(data_type, i256, Decimal256Type)
332            }
333            Utf8 | LargeUtf8 | Utf8View | Binary | LargeBinary | BinaryView => {
334                Ok(Box::new(MinMaxBytesAccumulator::new_max(data_type.clone())))
335            }
336            Struct(_) => Ok(Box::new(MinMaxStructAccumulator::new_max(
337                data_type.clone(),
338            ))),
339            // This is only reached if groups_accumulator_supported is out of sync
340            _ => internal_err!("GroupsAccumulator not supported for max({})", data_type),
341        }
342    }
343
344    fn create_sliding_accumulator(
345        &self,
346        args: AccumulatorArgs,
347    ) -> Result<Box<dyn Accumulator>> {
348        Ok(Box::new(SlidingMaxAccumulator::try_new(
349            args.return_field.data_type(),
350        )?))
351    }
352
353    fn is_descending(&self) -> Option<bool> {
354        Some(true)
355    }
356
357    fn order_sensitivity(&self) -> datafusion_expr::utils::AggregateOrderSensitivity {
358        datafusion_expr::utils::AggregateOrderSensitivity::Insensitive
359    }
360
361    fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
362        get_min_max_result_type(arg_types)
363    }
364    fn reverse_expr(&self) -> datafusion_expr::ReversedUDAF {
365        datafusion_expr::ReversedUDAF::Identical
366    }
367    fn value_from_stats(&self, statistics_args: &StatisticsArgs) -> Option<ScalarValue> {
368        self.value_from_statistics(statistics_args)
369    }
370
371    fn documentation(&self) -> Option<&Documentation> {
372        self.doc()
373    }
374
375    fn set_monotonicity(&self, _data_type: &DataType) -> SetMonotonicity {
376        // `MAX` is monotonically increasing as it always increases or stays
377        // the same as new values are seen.
378        SetMonotonicity::Increasing
379    }
380}
381
382#[derive(Debug)]
383pub struct SlidingMaxAccumulator {
384    /// Typed NULL returned when the window contains no non-null values
385    empty_value: ScalarValue,
386    moving_max: MovingMax<ScalarValue>,
387}
388
389impl SlidingMaxAccumulator {
390    /// new max accumulator
391    pub fn try_new(datatype: &DataType) -> Result<Self> {
392        Ok(Self {
393            empty_value: ScalarValue::try_from(datatype)?,
394            moving_max: MovingMax::<ScalarValue>::new(),
395        })
396    }
397
398    fn current_max(&self) -> ScalarValue {
399        match self.moving_max.max() {
400            Some(res) => res.clone(),
401            None => self.empty_value.clone(),
402        }
403    }
404}
405
406impl Accumulator for SlidingMaxAccumulator {
407    fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
408        for idx in 0..values[0].len() {
409            let val = ScalarValue::try_from_array(&values[0], idx)?;
410            if !val.is_null() {
411                self.moving_max.push(val);
412            }
413        }
414        Ok(())
415    }
416
417    fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
418        // We assume that values are retracted in the order they were added, so
419        // the retracted values must be the oldest elements of `moving_max`.
420        // NULLs are never pushed, so be sure to only pop once per non-NULL
421        // value.
422        let valid_count = values[0].len() - values[0].logical_null_count();
423        for _ in 0..valid_count {
424            self.moving_max.pop();
425        }
426        Ok(())
427    }
428
429    fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
430        self.update_batch(states)
431    }
432
433    fn state(&mut self) -> Result<Vec<ScalarValue>> {
434        Ok(vec![self.current_max()])
435    }
436
437    fn evaluate(&mut self) -> Result<ScalarValue> {
438        Ok(self.current_max())
439    }
440
441    fn supports_retract_batch(&self) -> bool {
442        true
443    }
444
445    fn size(&self) -> usize {
446        size_of_val(self) - size_of_val(&self.empty_value)
447            + self.empty_value.size()
448            + self.moving_max.heap_size(|sv| sv.size() - size_of_val(sv))
449    }
450}
451
452#[user_doc(
453    doc_section(label = "General Functions"),
454    description = "Returns the minimum value in the specified column.",
455    syntax_example = "min(expression)",
456    sql_example = r#"```sql
457> SELECT min(column_name) FROM table_name;
458+----------------------+
459| min(column_name)      |
460+----------------------+
461| 12                   |
462+----------------------+
463```"#,
464    standard_argument(name = "expression",)
465)]
466#[derive(Debug, PartialEq, Eq, Hash)]
467pub struct Min {
468    signature: Signature,
469}
470
471impl Min {
472    pub fn new() -> Self {
473        Self {
474            signature: Signature::user_defined(Volatility::Immutable),
475        }
476    }
477}
478
479impl Default for Min {
480    fn default() -> Self {
481        Self::new()
482    }
483}
484
485impl FromColumnStatistics for Min {
486    fn value_from_column_statistics(
487        &self,
488        col_stats: &ColumnStatistics,
489    ) -> Option<ScalarValue> {
490        if let Precision::Exact(ref val) = col_stats.min_value
491            && !val.is_null()
492        {
493            return Some(val.clone());
494        }
495        None
496    }
497}
498
499impl AggregateUDFImpl for Min {
500    fn name(&self) -> &str {
501        "min"
502    }
503
504    fn signature(&self) -> &Signature {
505        &self.signature
506    }
507
508    fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
509        Ok(arg_types[0].to_owned())
510    }
511
512    fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
513        Ok(Box::new(MinAccumulator::try_new(
514            acc_args.return_field.data_type(),
515        )?))
516    }
517
518    fn groups_accumulator_supported(&self, args: AccumulatorArgs) -> bool {
519        use DataType::*;
520        matches!(
521            args.return_field.data_type(),
522            Int8 | Int16
523                | Int32
524                | Int64
525                | UInt8
526                | UInt16
527                | UInt32
528                | UInt64
529                | Float16
530                | Float32
531                | Float64
532                | Decimal32(_, _)
533                | Decimal64(_, _)
534                | Decimal128(_, _)
535                | Decimal256(_, _)
536                | Date32
537                | Date64
538                | Time32(_)
539                | Time64(_)
540                | Timestamp(_, _)
541                | Utf8
542                | LargeUtf8
543                | Utf8View
544                | Binary
545                | LargeBinary
546                | BinaryView
547                | Duration(_)
548                | Struct(_)
549        )
550    }
551
552    fn create_groups_accumulator(
553        &self,
554        args: AccumulatorArgs,
555    ) -> Result<Box<dyn GroupsAccumulator>> {
556        use DataType::*;
557        use TimeUnit::*;
558        let data_type = args.return_field.data_type();
559        match data_type {
560            Int8 => primitive_min_accumulator!(data_type, i8, Int8Type),
561            Int16 => primitive_min_accumulator!(data_type, i16, Int16Type),
562            Int32 => primitive_min_accumulator!(data_type, i32, Int32Type),
563            Int64 => primitive_min_accumulator!(data_type, i64, Int64Type),
564            UInt8 => primitive_min_accumulator!(data_type, u8, UInt8Type),
565            UInt16 => primitive_min_accumulator!(data_type, u16, UInt16Type),
566            UInt32 => primitive_min_accumulator!(data_type, u32, UInt32Type),
567            UInt64 => primitive_min_accumulator!(data_type, u64, UInt64Type),
568            Float16 => {
569                primitive_min_accumulator!(data_type, f16, Float16Type)
570            }
571            Float32 => {
572                primitive_min_accumulator!(data_type, f32, Float32Type)
573            }
574            Float64 => {
575                primitive_min_accumulator!(data_type, f64, Float64Type)
576            }
577            Date32 => primitive_min_accumulator!(data_type, i32, Date32Type),
578            Date64 => primitive_min_accumulator!(data_type, i64, Date64Type),
579            Time32(Second) => {
580                primitive_min_accumulator!(data_type, i32, Time32SecondType)
581            }
582            Time32(Millisecond) => {
583                primitive_min_accumulator!(data_type, i32, Time32MillisecondType)
584            }
585            Time64(Microsecond) => {
586                primitive_min_accumulator!(data_type, i64, Time64MicrosecondType)
587            }
588            Time64(Nanosecond) => {
589                primitive_min_accumulator!(data_type, i64, Time64NanosecondType)
590            }
591            Timestamp(Second, _) => {
592                primitive_min_accumulator!(data_type, i64, TimestampSecondType)
593            }
594            Timestamp(Millisecond, _) => {
595                primitive_min_accumulator!(data_type, i64, TimestampMillisecondType)
596            }
597            Timestamp(Microsecond, _) => {
598                primitive_min_accumulator!(data_type, i64, TimestampMicrosecondType)
599            }
600            Timestamp(Nanosecond, _) => {
601                primitive_min_accumulator!(data_type, i64, TimestampNanosecondType)
602            }
603            Duration(Second) => {
604                primitive_min_accumulator!(data_type, i64, DurationSecondType)
605            }
606            Duration(Millisecond) => {
607                primitive_min_accumulator!(data_type, i64, DurationMillisecondType)
608            }
609            Duration(Microsecond) => {
610                primitive_min_accumulator!(data_type, i64, DurationMicrosecondType)
611            }
612            Duration(Nanosecond) => {
613                primitive_min_accumulator!(data_type, i64, DurationNanosecondType)
614            }
615            Decimal32(_, _) => {
616                primitive_min_accumulator!(data_type, i32, Decimal32Type)
617            }
618            Decimal64(_, _) => {
619                primitive_min_accumulator!(data_type, i64, Decimal64Type)
620            }
621            Decimal128(_, _) => {
622                primitive_min_accumulator!(data_type, i128, Decimal128Type)
623            }
624            Decimal256(_, _) => {
625                primitive_min_accumulator!(data_type, i256, Decimal256Type)
626            }
627            Utf8 | LargeUtf8 | Utf8View | Binary | LargeBinary | BinaryView => {
628                Ok(Box::new(MinMaxBytesAccumulator::new_min(data_type.clone())))
629            }
630            Struct(_) => Ok(Box::new(MinMaxStructAccumulator::new_min(
631                data_type.clone(),
632            ))),
633            // This is only reached if groups_accumulator_supported is out of sync
634            _ => internal_err!("GroupsAccumulator not supported for min({})", data_type),
635        }
636    }
637
638    fn create_sliding_accumulator(
639        &self,
640        args: AccumulatorArgs,
641    ) -> Result<Box<dyn Accumulator>> {
642        Ok(Box::new(SlidingMinAccumulator::try_new(
643            args.return_field.data_type(),
644        )?))
645    }
646
647    fn is_descending(&self) -> Option<bool> {
648        Some(false)
649    }
650
651    fn value_from_stats(&self, statistics_args: &StatisticsArgs) -> Option<ScalarValue> {
652        self.value_from_statistics(statistics_args)
653    }
654    fn order_sensitivity(&self) -> datafusion_expr::utils::AggregateOrderSensitivity {
655        datafusion_expr::utils::AggregateOrderSensitivity::Insensitive
656    }
657
658    fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
659        get_min_max_result_type(arg_types)
660    }
661
662    fn reverse_expr(&self) -> datafusion_expr::ReversedUDAF {
663        datafusion_expr::ReversedUDAF::Identical
664    }
665
666    fn documentation(&self) -> Option<&Documentation> {
667        self.doc()
668    }
669
670    fn set_monotonicity(&self, _data_type: &DataType) -> SetMonotonicity {
671        // `MIN` is monotonically decreasing as it always decreases or stays
672        // the same as new values are seen.
673        SetMonotonicity::Decreasing
674    }
675}
676
677#[derive(Debug)]
678pub struct SlidingMinAccumulator {
679    /// Typed NULL returned when the window contains no non-null values
680    empty_value: ScalarValue,
681    moving_min: MovingMin<ScalarValue>,
682}
683
684impl SlidingMinAccumulator {
685    pub fn try_new(datatype: &DataType) -> Result<Self> {
686        Ok(Self {
687            empty_value: ScalarValue::try_from(datatype)?,
688            moving_min: MovingMin::<ScalarValue>::new(),
689        })
690    }
691
692    fn current_min(&self) -> ScalarValue {
693        match self.moving_min.min() {
694            Some(res) => res.clone(),
695            None => self.empty_value.clone(),
696        }
697    }
698}
699
700impl Accumulator for SlidingMinAccumulator {
701    fn state(&mut self) -> Result<Vec<ScalarValue>> {
702        Ok(vec![self.current_min()])
703    }
704
705    fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
706        for idx in 0..values[0].len() {
707            let val = ScalarValue::try_from_array(&values[0], idx)?;
708            if !val.is_null() {
709                self.moving_min.push(val);
710            }
711        }
712        Ok(())
713    }
714
715    fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
716        // We assume that values are retracted in the order they were added, so
717        // the retracted values must be the oldest elements of `moving_min`.
718        // NULLs are never pushed, so be sure to only pop once per non-NULL
719        // value.
720        let valid_count = values[0].len() - values[0].logical_null_count();
721        for _ in 0..valid_count {
722            self.moving_min.pop();
723        }
724        Ok(())
725    }
726
727    fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
728        self.update_batch(states)
729    }
730
731    fn evaluate(&mut self) -> Result<ScalarValue> {
732        Ok(self.current_min())
733    }
734
735    fn supports_retract_batch(&self) -> bool {
736        true
737    }
738
739    fn size(&self) -> usize {
740        size_of_val(self) - size_of_val(&self.empty_value)
741            + self.empty_value.size()
742            + self.moving_min.heap_size(|sv| sv.size() - size_of_val(sv))
743    }
744}
745
746/// Keep track of the minimum value in a sliding window.
747///
748/// `MovingMin` keeps track of the minimum value in a sliding window using a
749/// monotonic deque. Each element is stored with its sequence number, and the
750/// deque maintains candidate elements in ascending value order.
751///
752/// Complexity:
753/// - O(1) for getting the minimum
754/// - amortized O(1) for push
755/// - O(1) for pop
756#[derive(Debug)]
757pub(crate) struct MovingMin<T> {
758    deque: VecDeque<(u64, T)>,
759    push_seq: u64,
760    pop_seq: u64,
761}
762
763impl<T: PartialOrd> Default for MovingMin<T> {
764    fn default() -> Self {
765        Self {
766            deque: VecDeque::new(),
767            push_seq: 0,
768            pop_seq: 0,
769        }
770    }
771}
772
773impl<T: PartialOrd> MovingMin<T> {
774    /// Creates a new `MovingMin` to keep track of the minimum in a sliding window.
775    #[inline]
776    pub fn new() -> Self {
777        Self::default()
778    }
779
780    /// Creates a new `MovingMin` to keep track of the minimum in a sliding window with
781    /// `capacity` allocated slots.
782    #[cfg(test)]
783    #[inline]
784    pub fn with_capacity(capacity: usize) -> Self {
785        Self {
786            deque: VecDeque::with_capacity(capacity),
787            push_seq: 0,
788            pop_seq: 0,
789        }
790    }
791
792    /// Returns the minimum of the sliding window or `None` if the window is
793    /// empty.
794    #[inline]
795    pub fn min(&self) -> Option<&T> {
796        self.deque.front().map(|(_, val)| val)
797    }
798
799    #[inline]
800    fn check_invariants(&self) {
801        debug_assert!(self.pop_seq <= self.push_seq);
802        debug_assert!(
803            self.deque
804                .front()
805                .is_none_or(|&(front_seq, _)| front_seq >= self.pop_seq)
806        );
807    }
808
809    /// Pushes a new element into the sliding window.
810    #[inline]
811    pub fn push(&mut self, val: T) {
812        let seq = self.push_seq;
813        self.push_seq += 1;
814        while self.deque.back().is_some_and(|back_val| back_val.1 >= val) {
815            self.deque.pop_back();
816        }
817        self.deque.push_back((seq, val));
818
819        self.check_invariants();
820    }
821
822    /// Removes the oldest value from the sliding window.
823    ///
824    /// If the window is empty, this is a no-op.
825    #[inline]
826    pub fn pop(&mut self) {
827        if self.is_empty() {
828            return;
829        }
830        let seq = self.pop_seq;
831        self.pop_seq += 1;
832        if self
833            .deque
834            .front()
835            .is_some_and(|front_val| front_val.0 == seq)
836        {
837            self.deque.pop_front();
838        }
839
840        self.check_invariants();
841    }
842
843    /// Returns the number of elements stored in the sliding window.
844    #[cfg(test)]
845    pub fn len(&self) -> usize {
846        (self.push_seq - self.pop_seq) as usize
847    }
848
849    /// Returns `true` if the moving window contains no elements.
850    #[inline]
851    pub fn is_empty(&self) -> bool {
852        self.push_seq == self.pop_seq
853    }
854
855    /// Heap bytes owned by the deque plus each stored `T`'s
856    /// heap payload as reported by `elem_heap`. Excludes `size_of::<Self>()`.
857    #[inline]
858    fn heap_size(&self, elem_heap: impl Fn(&T) -> usize) -> usize {
859        moving_deque_heap_size(&self.deque, elem_heap)
860    }
861}
862
863/// Shared implementation for [`MovingMin::heap_size`] and
864/// [`MovingMax::heap_size`]. Both share the same deque layout.
865#[inline]
866fn moving_deque_heap_size<T>(
867    deque: &VecDeque<(u64, T)>,
868    elem_heap: impl Fn(&T) -> usize,
869) -> usize {
870    let buffers = deque.capacity() * size_of::<(u64, T)>();
871    let elems: usize = deque.iter().map(|(_, val)| elem_heap(val)).sum();
872    buffers + elems
873}
874
875/// Keep track of the maximum value in a sliding window.
876///
877/// `MovingMax` keeps track of the maximum value in a sliding window using a
878/// monotonic deque. Each element is stored with its sequence number, and the
879/// deque maintains candidate elements in descending value order.
880///
881/// Complexity:
882/// - O(1) for getting the maximum
883/// - amortized O(1) for push
884/// - O(1) for pop
885#[derive(Debug)]
886pub(crate) struct MovingMax<T> {
887    deque: VecDeque<(u64, T)>,
888    push_seq: u64,
889    pop_seq: u64,
890}
891
892impl<T: PartialOrd> Default for MovingMax<T> {
893    fn default() -> Self {
894        Self {
895            deque: VecDeque::new(),
896            push_seq: 0,
897            pop_seq: 0,
898        }
899    }
900}
901
902impl<T: PartialOrd> MovingMax<T> {
903    /// Creates a new `MovingMax` to keep track of the maximum in a sliding window.
904    #[inline]
905    pub fn new() -> Self {
906        Self::default()
907    }
908
909    /// Creates a new `MovingMax` to keep track of the maximum in a sliding window with
910    /// `capacity` allocated slots.
911    #[cfg(test)]
912    #[inline]
913    pub fn with_capacity(capacity: usize) -> Self {
914        Self {
915            deque: VecDeque::with_capacity(capacity),
916            push_seq: 0,
917            pop_seq: 0,
918        }
919    }
920
921    /// Returns the maximum of the sliding window or `None` if the window is empty.
922    #[inline]
923    pub fn max(&self) -> Option<&T> {
924        self.deque.front().map(|(_, val)| val)
925    }
926
927    #[inline]
928    fn check_invariants(&self) {
929        debug_assert!(self.pop_seq <= self.push_seq);
930        debug_assert!(
931            self.deque
932                .front()
933                .is_none_or(|&(front_seq, _)| front_seq >= self.pop_seq)
934        );
935    }
936
937    /// Pushes a new element into the sliding window.
938    #[inline]
939    pub fn push(&mut self, val: T) {
940        let seq = self.push_seq;
941        self.push_seq += 1;
942        while self.deque.back().is_some_and(|back_val| back_val.1 <= val) {
943            self.deque.pop_back();
944        }
945        self.deque.push_back((seq, val));
946
947        self.check_invariants();
948    }
949
950    /// Removes the oldest value from the sliding window.
951    ///
952    /// If the window is empty, this is a no-op.
953    #[inline]
954    pub fn pop(&mut self) {
955        if self.is_empty() {
956            return;
957        }
958        let seq = self.pop_seq;
959        self.pop_seq += 1;
960        if self
961            .deque
962            .front()
963            .is_some_and(|front_val| front_val.0 == seq)
964        {
965            self.deque.pop_front();
966        }
967
968        self.check_invariants();
969    }
970
971    /// Returns the number of elements stored in the sliding window.
972    #[cfg(test)]
973    pub fn len(&self) -> usize {
974        (self.push_seq - self.pop_seq) as usize
975    }
976
977    /// Returns `true` if the moving window contains no elements.
978    #[inline]
979    pub fn is_empty(&self) -> bool {
980        self.push_seq == self.pop_seq
981    }
982
983    /// Heap bytes owned by the deque plus each stored `T`'s
984    /// heap payload as reported by `elem_heap`. Excludes `size_of::<Self>()`.
985    #[inline]
986    fn heap_size(&self, elem_heap: impl Fn(&T) -> usize) -> usize {
987        moving_deque_heap_size(&self.deque, elem_heap)
988    }
989}
990
991make_udaf_expr_and_func!(
992    Max,
993    max,
994    expression,
995    "Returns the maximum of a group of values.",
996    max_udaf
997);
998
999make_udaf_expr_and_func!(
1000    Min,
1001    min,
1002    expression,
1003    "Returns the minimum of a group of values.",
1004    min_udaf
1005);
1006
1007// Re-export accumulators from the common module for backwards compatibility
1008pub use datafusion_functions_aggregate_common::min_max::{
1009    MaxAccumulator, MinAccumulator,
1010};
1011
1012#[cfg(test)]
1013mod tests {
1014    use super::*;
1015    use arrow::{
1016        array::{
1017            Array, DictionaryArray, Float32Array, Int8Array, Int32Array,
1018            IntervalDayTimeArray, IntervalMonthDayNanoArray, IntervalYearMonthArray,
1019            PrimitiveArray, StringArray,
1020        },
1021        datatypes::{
1022            ArrowDictionaryKeyType, IntervalDayTimeType, IntervalMonthDayNanoType,
1023            IntervalUnit, IntervalYearMonthType,
1024        },
1025    };
1026    use std::sync::Arc;
1027
1028    #[test]
1029    fn interval_min_max() {
1030        // IntervalYearMonth
1031        let b = IntervalYearMonthArray::from(vec![
1032            IntervalYearMonthType::make_value(0, 1),
1033            IntervalYearMonthType::make_value(5, 34),
1034            IntervalYearMonthType::make_value(-2, 4),
1035            IntervalYearMonthType::make_value(7, -4),
1036            IntervalYearMonthType::make_value(0, 1),
1037        ]);
1038        let b: ArrayRef = Arc::new(b);
1039
1040        let mut min =
1041            MinAccumulator::try_new(&DataType::Interval(IntervalUnit::YearMonth))
1042                .unwrap();
1043        min.update_batch(&[Arc::clone(&b)]).unwrap();
1044        let min_res = min.evaluate().unwrap();
1045        assert_eq!(
1046            min_res,
1047            ScalarValue::IntervalYearMonth(Some(IntervalYearMonthType::make_value(
1048                -2, 4,
1049            )))
1050        );
1051
1052        let mut max =
1053            MaxAccumulator::try_new(&DataType::Interval(IntervalUnit::YearMonth))
1054                .unwrap();
1055        max.update_batch(&[Arc::clone(&b)]).unwrap();
1056        let max_res = max.evaluate().unwrap();
1057        assert_eq!(
1058            max_res,
1059            ScalarValue::IntervalYearMonth(Some(IntervalYearMonthType::make_value(
1060                5, 34,
1061            )))
1062        );
1063
1064        // IntervalDayTime
1065        let b = IntervalDayTimeArray::from(vec![
1066            IntervalDayTimeType::make_value(0, 0),
1067            IntervalDayTimeType::make_value(5, 454000),
1068            IntervalDayTimeType::make_value(-34, 0),
1069            IntervalDayTimeType::make_value(7, -4000),
1070            IntervalDayTimeType::make_value(1, 0),
1071        ]);
1072        let b: ArrayRef = Arc::new(b);
1073
1074        let mut min =
1075            MinAccumulator::try_new(&DataType::Interval(IntervalUnit::DayTime)).unwrap();
1076        min.update_batch(&[Arc::clone(&b)]).unwrap();
1077        let min_res = min.evaluate().unwrap();
1078        assert_eq!(
1079            min_res,
1080            ScalarValue::IntervalDayTime(Some(IntervalDayTimeType::make_value(-34, 0)))
1081        );
1082
1083        let mut max =
1084            MaxAccumulator::try_new(&DataType::Interval(IntervalUnit::DayTime)).unwrap();
1085        max.update_batch(&[Arc::clone(&b)]).unwrap();
1086        let max_res = max.evaluate().unwrap();
1087        assert_eq!(
1088            max_res,
1089            ScalarValue::IntervalDayTime(Some(IntervalDayTimeType::make_value(7, -4000)))
1090        );
1091
1092        // IntervalMonthDayNano
1093        let b = IntervalMonthDayNanoArray::from(vec![
1094            IntervalMonthDayNanoType::make_value(1, 0, 0),
1095            IntervalMonthDayNanoType::make_value(344, 34, -43_000_000_000),
1096            IntervalMonthDayNanoType::make_value(-593, -33, 13_000_000_000),
1097            IntervalMonthDayNanoType::make_value(5, 2, 493_000_000_000),
1098            IntervalMonthDayNanoType::make_value(1, 0, 0),
1099        ]);
1100        let b: ArrayRef = Arc::new(b);
1101
1102        let mut min =
1103            MinAccumulator::try_new(&DataType::Interval(IntervalUnit::MonthDayNano))
1104                .unwrap();
1105        min.update_batch(&[Arc::clone(&b)]).unwrap();
1106        let min_res = min.evaluate().unwrap();
1107        assert_eq!(
1108            min_res,
1109            ScalarValue::IntervalMonthDayNano(Some(
1110                IntervalMonthDayNanoType::make_value(-593, -33, 13_000_000_000)
1111            ))
1112        );
1113
1114        let mut max =
1115            MaxAccumulator::try_new(&DataType::Interval(IntervalUnit::MonthDayNano))
1116                .unwrap();
1117        max.update_batch(&[Arc::clone(&b)]).unwrap();
1118        let max_res = max.evaluate().unwrap();
1119        assert_eq!(
1120            max_res,
1121            ScalarValue::IntervalMonthDayNano(Some(
1122                IntervalMonthDayNanoType::make_value(344, 34, -43_000_000_000)
1123            ))
1124        );
1125    }
1126
1127    #[test]
1128    fn float_min_max_with_nans() {
1129        let pos_nan = f32::NAN;
1130        let zero = 0_f32;
1131        let neg_inf = f32::NEG_INFINITY;
1132
1133        let check = |acc: &mut dyn Accumulator, values: &[&[f32]], expected: f32| {
1134            for batch in values.iter() {
1135                let batch =
1136                    Arc::new(Float32Array::from_iter_values(batch.iter().copied()));
1137                acc.update_batch(&[batch]).unwrap();
1138            }
1139            let result = acc.evaluate().unwrap();
1140            assert_eq!(result, ScalarValue::Float32(Some(expected)));
1141        };
1142
1143        // This test checks both comparison between batches (which uses the min_max macro
1144        // defined above) and within a batch (which uses the arrow min/max compute function
1145        // and verifies both respect the total order comparison for floats)
1146
1147        let min = || MinAccumulator::try_new(&DataType::Float32).unwrap();
1148        let max = || MaxAccumulator::try_new(&DataType::Float32).unwrap();
1149
1150        check(&mut min(), &[&[zero], &[pos_nan]], zero);
1151        check(&mut min(), &[&[zero, pos_nan]], zero);
1152        check(&mut min(), &[&[zero], &[neg_inf]], neg_inf);
1153        check(&mut min(), &[&[zero, neg_inf]], neg_inf);
1154        check(&mut max(), &[&[zero], &[pos_nan]], pos_nan);
1155        check(&mut max(), &[&[zero, pos_nan]], pos_nan);
1156        check(&mut max(), &[&[zero], &[neg_inf]], zero);
1157        check(&mut max(), &[&[zero, neg_inf]], zero);
1158    }
1159
1160    use rand::Rng;
1161
1162    fn get_random_vec_i32(len: usize) -> Vec<i32> {
1163        let mut rng = rand::rng();
1164        let mut input = Vec::with_capacity(len);
1165        for _i in 0..len {
1166            input.push(rng.random_range(0..100));
1167        }
1168        input
1169    }
1170
1171    fn moving_min_i32(len: usize, n_sliding_window: usize) -> Result<()> {
1172        let data = get_random_vec_i32(len);
1173        let mut expected = Vec::with_capacity(len);
1174        let mut moving_min = MovingMin::<i32>::new();
1175        let mut res = Vec::with_capacity(len);
1176        for i in 0..len {
1177            let start = i.saturating_sub(n_sliding_window);
1178            expected.push(*data[start..i + 1].iter().min().unwrap());
1179
1180            moving_min.push(data[i]);
1181            if i > n_sliding_window {
1182                moving_min.pop();
1183            }
1184            res.push(*moving_min.min().unwrap());
1185        }
1186        assert_eq!(res, expected);
1187        Ok(())
1188    }
1189
1190    fn moving_max_i32(len: usize, n_sliding_window: usize) -> Result<()> {
1191        let data = get_random_vec_i32(len);
1192        let mut expected = Vec::with_capacity(len);
1193        let mut moving_max = MovingMax::<i32>::new();
1194        let mut res = Vec::with_capacity(len);
1195        for i in 0..len {
1196            let start = i.saturating_sub(n_sliding_window);
1197            expected.push(*data[start..i + 1].iter().max().unwrap());
1198
1199            moving_max.push(data[i]);
1200            if i > n_sliding_window {
1201                moving_max.pop();
1202            }
1203            res.push(*moving_max.max().unwrap());
1204        }
1205        assert_eq!(res, expected);
1206        Ok(())
1207    }
1208
1209    #[test]
1210    fn sliding_min_all_null_window() -> Result<()> {
1211        let mut min_acc = SlidingMinAccumulator::try_new(&DataType::Int32)?;
1212
1213        let values: ArrayRef = Arc::new(Int32Array::from(vec![Some(3), None]));
1214        min_acc.update_batch(&[Arc::clone(&values)])?;
1215        assert_eq!(min_acc.evaluate()?, ScalarValue::Int32(Some(3)));
1216
1217        // Retract `3`; the window now contains only the NULL
1218        let retracted: ArrayRef = Arc::new(Int32Array::from(vec![Some(3)]));
1219        min_acc.retract_batch(&[Arc::clone(&retracted)])?;
1220        assert_eq!(min_acc.evaluate()?, ScalarValue::Int32(None));
1221
1222        // A subsequent non-null value must be picked up again
1223        let update: ArrayRef = Arc::new(Int32Array::from(vec![Some(7)]));
1224        min_acc.update_batch(&[Arc::clone(&update)])?;
1225        assert_eq!(min_acc.evaluate()?, ScalarValue::Int32(Some(7)));
1226
1227        // Retracting the NULL row must not pop the remaining value
1228        let null_row: ArrayRef = Arc::new(Int32Array::from(vec![None::<i32>]));
1229        min_acc.retract_batch(&[Arc::clone(&null_row)])?;
1230        assert_eq!(min_acc.evaluate()?, ScalarValue::Int32(Some(7)));
1231
1232        Ok(())
1233    }
1234
1235    #[test]
1236    fn sliding_max_all_null_window() -> Result<()> {
1237        let mut max_acc = SlidingMaxAccumulator::try_new(&DataType::Int32)?;
1238
1239        let values: ArrayRef = Arc::new(Int32Array::from(vec![Some(3), None]));
1240        max_acc.update_batch(&[Arc::clone(&values)])?;
1241        assert_eq!(max_acc.evaluate()?, ScalarValue::Int32(Some(3)));
1242
1243        // Retract `3`; the window now contains only the NULL
1244        let retracted: ArrayRef = Arc::new(Int32Array::from(vec![Some(3)]));
1245        max_acc.retract_batch(&[Arc::clone(&retracted)])?;
1246        assert_eq!(max_acc.evaluate()?, ScalarValue::Int32(None));
1247
1248        // A subsequent non-null value must be picked up again
1249        let update: ArrayRef = Arc::new(Int32Array::from(vec![Some(7)]));
1250        max_acc.update_batch(&[Arc::clone(&update)])?;
1251        assert_eq!(max_acc.evaluate()?, ScalarValue::Int32(Some(7)));
1252
1253        // Retracting the NULL row must not disturb the remaining value
1254        let null_row: ArrayRef = Arc::new(Int32Array::from(vec![None::<i32>]));
1255        max_acc.retract_batch(&[Arc::clone(&null_row)])?;
1256        assert_eq!(max_acc.evaluate()?, ScalarValue::Int32(Some(7)));
1257
1258        Ok(())
1259    }
1260
1261    #[test]
1262    fn moving_min_tests() -> Result<()> {
1263        moving_min_i32(100, 10)?;
1264        moving_min_i32(100, 20)?;
1265        moving_min_i32(100, 50)?;
1266        moving_min_i32(100, 100)?;
1267        Ok(())
1268    }
1269
1270    #[test]
1271    fn moving_max_tests() -> Result<()> {
1272        moving_max_i32(100, 10)?;
1273        moving_max_i32(100, 20)?;
1274        moving_max_i32(100, 50)?;
1275        moving_max_i32(100, 100)?;
1276        Ok(())
1277    }
1278
1279    #[test]
1280    fn moving_min_max_heap_size_i32() {
1281        // Fixed-width `T` has no per-element heap payload, so `heap_size`
1282        // reports exactly the buffer's capacity in bytes.
1283        let mut moving_min = MovingMin::<i32>::with_capacity(4);
1284        let mut moving_max = MovingMax::<i32>::with_capacity(4);
1285        let elem = |_: &i32| 0;
1286
1287        let buffer_only = moving_min.deque.capacity() * size_of::<(u64, i32)>();
1288        assert_eq!(moving_min.heap_size(elem), buffer_only);
1289        assert_eq!(moving_max.heap_size(elem), buffer_only);
1290
1291        for i in 0..3 {
1292            moving_min.push(i);
1293            moving_max.push(i);
1294        }
1295        // Elements sit inside the pre-allocated buffers, so still buffer-only.
1296        assert_eq!(moving_min.heap_size(elem), buffer_only);
1297        assert_eq!(moving_max.heap_size(elem), buffer_only);
1298    }
1299
1300    #[test]
1301    fn moving_min_max_heap_size_counts_elems() {
1302        let mut moving_min = MovingMin::<String>::with_capacity(2);
1303        let mut moving_max = MovingMax::<String>::with_capacity(2);
1304        let elem = |s: &String| s.capacity();
1305
1306        moving_min.push("abcdef".to_string());
1307        moving_max.push("abcdef".to_string());
1308
1309        let buffers = moving_min.deque.capacity() * size_of::<(u64, String)>();
1310        let elems = 6;
1311        assert_eq!(moving_min.heap_size(elem), buffers + elems);
1312        assert_eq!(moving_max.heap_size(elem), buffers + elems);
1313    }
1314
1315    #[test]
1316    fn test_moving_min_max_empty_pop() {
1317        let mut moving_min = MovingMin::<i32>::new();
1318        moving_min.pop(); // empty pop is a no-op
1319        assert_eq!(moving_min.len(), 0);
1320        assert!(moving_min.is_empty());
1321        // Verify it still works correctly after empty pop
1322        moving_min.push(10);
1323        moving_min.push(20);
1324        assert_eq!(moving_min.min(), Some(&10));
1325        moving_min.pop();
1326        assert_eq!(moving_min.min(), Some(&20));
1327
1328        let mut moving_max = MovingMax::<i32>::new();
1329        moving_max.pop(); // empty pop is a no-op
1330        assert_eq!(moving_max.len(), 0);
1331        assert!(moving_max.is_empty());
1332        // Verify it still works correctly after empty pop
1333        moving_max.push(20);
1334        moving_max.push(10);
1335        assert_eq!(moving_max.max(), Some(&20));
1336        moving_max.pop();
1337        assert_eq!(moving_max.max(), Some(&10));
1338    }
1339
1340    #[test]
1341    fn test_moving_min_max_duplicate_heavy() {
1342        let mut moving_min = MovingMin::<i32>::new();
1343        let mut moving_max = MovingMax::<i32>::new();
1344
1345        // Push duplicates
1346        for _ in 0..5 {
1347            moving_min.push(5);
1348            moving_max.push(5);
1349        }
1350
1351        assert_eq!(moving_min.len(), 5);
1352        assert_eq!(moving_max.len(), 5);
1353
1354        // Ensure min/max query works and we can pop all duplicates correctly
1355        for i in (1..=5).rev() {
1356            assert_eq!(moving_min.len(), i);
1357            assert_eq!(moving_max.len(), i);
1358            assert_eq!(moving_min.min(), Some(&5));
1359            assert_eq!(moving_max.max(), Some(&5));
1360            moving_min.pop();
1361            moving_max.pop();
1362        }
1363
1364        assert!(moving_min.is_empty());
1365        assert!(moving_max.is_empty());
1366    }
1367
1368    #[test]
1369    fn test_min_max_coerce_types() {
1370        // the coerced types is same with input types
1371        let funs: Vec<Box<dyn AggregateUDFImpl>> =
1372            vec![Box::new(Min::new()), Box::new(Max::new())];
1373        let input_types = vec![
1374            vec![DataType::Int32],
1375            vec![DataType::Decimal128(10, 2)],
1376            vec![DataType::Decimal256(1, 1)],
1377            vec![DataType::Utf8],
1378        ];
1379        for fun in funs {
1380            for input_type in &input_types {
1381                let result = fun.coerce_types(input_type);
1382                assert_eq!(*input_type, result.unwrap());
1383            }
1384        }
1385    }
1386
1387    #[test]
1388    fn test_get_min_max_return_type_coerce_dictionary() -> Result<()> {
1389        let data_type =
1390            DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8));
1391        let result = get_min_max_result_type(&[data_type])?;
1392        assert_eq!(result, vec![DataType::Utf8]);
1393        Ok(())
1394    }
1395
1396    #[test]
1397    fn test_min_max_dictionary() -> Result<()> {
1398        let values = StringArray::from(vec!["b", "c", "a", "🦀", "d"]);
1399        let keys = Int32Array::from(vec![Some(0), Some(1), Some(2), None, Some(4)]);
1400        let dict_array =
1401            DictionaryArray::try_new(keys, Arc::new(values) as ArrayRef).unwrap();
1402        let dict_array_ref = Arc::new(dict_array) as ArrayRef;
1403        let rt_type =
1404            get_min_max_result_type(&[dict_array_ref.data_type().clone()])?[0].clone();
1405
1406        let mut min_acc = MinAccumulator::try_new(&rt_type)?;
1407        min_acc.update_batch(&[Arc::clone(&dict_array_ref)])?;
1408        let min_result = min_acc.evaluate()?;
1409        assert_eq!(min_result, ScalarValue::Utf8(Some("a".to_string())));
1410
1411        let mut max_acc = MaxAccumulator::try_new(&rt_type)?;
1412        max_acc.update_batch(&[Arc::clone(&dict_array_ref)])?;
1413        let max_result = max_acc.evaluate()?;
1414        assert_eq!(max_result, ScalarValue::Utf8(Some("d".to_string())));
1415        Ok(())
1416    }
1417
1418    fn dict_scalar(key_type: DataType, inner: ScalarValue) -> ScalarValue {
1419        ScalarValue::Dictionary(Box::new(key_type), Box::new(inner))
1420    }
1421
1422    fn utf8_dict_scalar(key_type: DataType, value: &str) -> ScalarValue {
1423        dict_scalar(key_type, ScalarValue::Utf8(Some(value.to_string())))
1424    }
1425
1426    fn string_dictionary_batch(values: &[&str], keys: &[Option<i32>]) -> ArrayRef {
1427        string_dictionary_batch_with_keys(Int32Array::from(keys.to_vec()), values)
1428    }
1429
1430    fn string_dictionary_batch_with_keys<K>(
1431        keys: PrimitiveArray<K>,
1432        values: &[&str],
1433    ) -> ArrayRef
1434    where
1435        K: ArrowDictionaryKeyType,
1436    {
1437        let values = Arc::new(StringArray::from(values.to_vec())) as ArrayRef;
1438        Arc::new(DictionaryArray::try_new(keys, values).unwrap()) as ArrayRef
1439    }
1440
1441    fn optional_string_dictionary_batch(
1442        values: &[Option<&str>],
1443        keys: &[Option<i32>],
1444    ) -> ArrayRef {
1445        let values = Arc::new(StringArray::from(values.to_vec())) as ArrayRef;
1446        Arc::new(
1447            DictionaryArray::try_new(Int32Array::from(keys.to_vec()), values).unwrap(),
1448        ) as ArrayRef
1449    }
1450
1451    fn float_dictionary_batch(values: &[f32], keys: &[Option<i32>]) -> ArrayRef {
1452        let values = Arc::new(Float32Array::from(values.to_vec())) as ArrayRef;
1453        Arc::new(
1454            DictionaryArray::try_new(Int32Array::from(keys.to_vec()), values).unwrap(),
1455        ) as ArrayRef
1456    }
1457
1458    fn evaluate_dictionary_accumulator(
1459        mut acc: impl Accumulator,
1460        batches: &[ArrayRef],
1461    ) -> Result<ScalarValue> {
1462        for batch in batches {
1463            acc.update_batch(&[Arc::clone(batch)])?;
1464        }
1465        acc.evaluate()
1466    }
1467
1468    fn assert_dictionary_min_max(
1469        dict_type: &DataType,
1470        batches: &[ArrayRef],
1471        expected_min: &str,
1472        expected_max: &str,
1473    ) -> Result<()> {
1474        let key_type = match dict_type {
1475            DataType::Dictionary(key_type, _) => key_type.as_ref().clone(),
1476            other => panic!("expected dictionary type, got {other:?}"),
1477        };
1478
1479        let min_result = evaluate_dictionary_accumulator(
1480            MinAccumulator::try_new(dict_type)?,
1481            batches,
1482        )?;
1483        assert_eq!(min_result, utf8_dict_scalar(key_type.clone(), expected_min));
1484
1485        let max_result = evaluate_dictionary_accumulator(
1486            MaxAccumulator::try_new(dict_type)?,
1487            batches,
1488        )?;
1489        assert_eq!(max_result, utf8_dict_scalar(key_type, expected_max));
1490
1491        Ok(())
1492    }
1493
1494    #[test]
1495    fn test_min_max_dictionary_without_coercion() -> Result<()> {
1496        let dict_array_ref = string_dictionary_batch(
1497            &["b", "c", "a", "d"],
1498            &[Some(0), Some(1), Some(2), Some(3)],
1499        );
1500        let dict_type = dict_array_ref.data_type().clone();
1501
1502        assert_dictionary_min_max(&dict_type, &[dict_array_ref], "a", "d")
1503    }
1504
1505    #[test]
1506    fn test_min_max_dictionary_with_nulls() -> Result<()> {
1507        let dict_array_ref = string_dictionary_batch(
1508            &["b", "c", "a"],
1509            &[None, Some(0), None, Some(1), Some(2)],
1510        );
1511        let dict_type = dict_array_ref.data_type().clone();
1512
1513        assert_dictionary_min_max(&dict_type, &[dict_array_ref], "a", "c")
1514    }
1515
1516    #[test]
1517    fn test_min_max_dictionary_ignores_unreferenced_values() -> Result<()> {
1518        let dict_array_ref =
1519            string_dictionary_batch(&["a", "z", "zz_unused"], &[Some(1), Some(1), None]);
1520        let dict_type = dict_array_ref.data_type().clone();
1521
1522        assert_dictionary_min_max(&dict_type, &[dict_array_ref], "z", "z")
1523    }
1524
1525    #[test]
1526    fn test_min_max_dictionary_ignores_referenced_null_values() -> Result<()> {
1527        let dict_array_ref = optional_string_dictionary_batch(
1528            &[Some("b"), None, Some("a"), Some("d")],
1529            &[Some(0), Some(1), Some(2), Some(3)],
1530        );
1531        let dict_type = dict_array_ref.data_type().clone();
1532
1533        assert_dictionary_min_max(&dict_type, &[dict_array_ref], "a", "d")
1534    }
1535
1536    #[test]
1537    fn test_min_max_dictionary_multi_batch() -> Result<()> {
1538        let dict_type =
1539            DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8));
1540        let batch1 = string_dictionary_batch(&["b", "c"], &[Some(0), Some(1)]);
1541        let batch2 = string_dictionary_batch(&["a", "d"], &[Some(0), Some(1)]);
1542
1543        assert_dictionary_min_max(&dict_type, &[batch1, batch2], "a", "d")
1544    }
1545
1546    #[test]
1547    fn test_min_max_dictionary_int8_keys() -> Result<()> {
1548        let dict_type =
1549            DataType::Dictionary(Box::new(DataType::Int8), Box::new(DataType::Utf8));
1550        let dict_array_ref = string_dictionary_batch_with_keys(
1551            Int8Array::from(vec![Some(0), Some(1), Some(2), Some(3)]),
1552            &["b", "c", "a", "d"],
1553        );
1554
1555        assert_dictionary_min_max(&dict_type, &[dict_array_ref], "a", "d")
1556    }
1557
1558    #[test]
1559    fn test_min_max_dictionary_float_with_nans() -> Result<()> {
1560        let dict_type =
1561            DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Float32));
1562        let batch1 = float_dictionary_batch(&[0.0, f32::NAN], &[Some(0), Some(1)]);
1563        let batch2 = float_dictionary_batch(&[f32::NEG_INFINITY], &[Some(0)]);
1564
1565        let min_result = evaluate_dictionary_accumulator(
1566            MinAccumulator::try_new(&dict_type)?,
1567            &[Arc::clone(&batch1), Arc::clone(&batch2)],
1568        )?;
1569        assert_eq!(
1570            min_result,
1571            dict_scalar(
1572                DataType::Int32,
1573                ScalarValue::Float32(Some(f32::NEG_INFINITY)),
1574            )
1575        );
1576
1577        let max_result = evaluate_dictionary_accumulator(
1578            MaxAccumulator::try_new(&dict_type)?,
1579            &[batch1, batch2],
1580        )?;
1581        assert_eq!(
1582            max_result,
1583            dict_scalar(DataType::Int32, ScalarValue::Float32(Some(f32::NAN)))
1584        );
1585
1586        Ok(())
1587    }
1588}