1mod 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 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 match &input_types[0] {
70 DataType::Dictionary(_, dict_value_type) => {
71 Ok(vec![dict_value_type.deref().clone()])
73 }
74 _ => 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#[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}
113macro_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 *cur = new
125 }
126 _ => {}
127 }
128 })
129 .with_starting_value($NATIVE::MIN),
131 ))
132 }};
133}
134
135macro_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 *cur = new
148 }
149 _ => {}
150 }
151 })
152 .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 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 _ => 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 SetMonotonicity::Increasing
379 }
380}
381
382#[derive(Debug)]
383pub struct SlidingMaxAccumulator {
384 empty_value: ScalarValue,
386 moving_max: MovingMax<ScalarValue>,
387}
388
389impl SlidingMaxAccumulator {
390 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 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 _ => 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 SetMonotonicity::Decreasing
674 }
675}
676
677#[derive(Debug)]
678pub struct SlidingMinAccumulator {
679 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 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#[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 #[inline]
776 pub fn new() -> Self {
777 Self::default()
778 }
779
780 #[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 #[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 #[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 #[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 #[cfg(test)]
845 pub fn len(&self) -> usize {
846 (self.push_seq - self.pop_seq) as usize
847 }
848
849 #[inline]
851 pub fn is_empty(&self) -> bool {
852 self.push_seq == self.pop_seq
853 }
854
855 #[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#[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#[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 #[inline]
905 pub fn new() -> Self {
906 Self::default()
907 }
908
909 #[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 #[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 #[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 #[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 #[cfg(test)]
973 pub fn len(&self) -> usize {
974 (self.push_seq - self.pop_seq) as usize
975 }
976
977 #[inline]
979 pub fn is_empty(&self) -> bool {
980 self.push_seq == self.pop_seq
981 }
982
983 #[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
1007pub 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 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 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 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 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 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 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 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 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 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 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 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 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(); assert_eq!(moving_min.len(), 0);
1320 assert!(moving_min.is_empty());
1321 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(); assert_eq!(moving_max.len(), 0);
1331 assert!(moving_max.is_empty());
1332 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 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 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 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}