1use std::fmt::{self, Debug, Display};
21
22use crate::{Result, ScalarValue};
23
24use crate::error::_plan_err;
25use crate::utils::aggregate::precision_add;
26use arrow::datatypes::{DataType, Schema};
27
28#[derive(Clone, PartialEq, Eq, Default, Copy)]
31pub enum Precision<T: Debug + Clone + PartialEq + Eq + PartialOrd> {
32 Exact(T),
39 Inexact(T),
47 #[default]
60 Absent,
61}
62
63impl<T: Debug + Clone + PartialEq + Eq + PartialOrd> Precision<T> {
64 pub fn get_value(&self) -> Option<&T> {
67 match self {
68 Precision::Exact(value) | Precision::Inexact(value) => Some(value),
69 Precision::Absent => None,
70 }
71 }
72
73 pub fn map<U, F>(self, f: F) -> Precision<U>
76 where
77 F: Fn(T) -> U,
78 U: Debug + Clone + PartialEq + Eq + PartialOrd,
79 {
80 match self {
81 Precision::Exact(val) => Precision::Exact(f(val)),
82 Precision::Inexact(val) => Precision::Inexact(f(val)),
83 _ => Precision::<U>::Absent,
84 }
85 }
86
87 pub fn is_exact(&self) -> Option<bool> {
90 match self {
91 Precision::Exact(_) => Some(true),
92 Precision::Inexact(_) => Some(false),
93 _ => None,
94 }
95 }
96
97 pub fn max(&self, other: &Precision<T>) -> Precision<T> {
101 match (self, other) {
102 (Precision::Exact(a), Precision::Exact(b)) => {
103 Precision::Exact(if a >= b { a.clone() } else { b.clone() })
104 }
105 (Precision::Inexact(a), Precision::Exact(b))
106 | (Precision::Exact(a), Precision::Inexact(b))
107 | (Precision::Inexact(a), Precision::Inexact(b)) => {
108 Precision::Inexact(if a >= b { a.clone() } else { b.clone() })
109 }
110 (_, _) => Precision::Absent,
111 }
112 }
113
114 pub fn min(&self, other: &Precision<T>) -> Precision<T> {
118 match (self, other) {
119 (Precision::Exact(a), Precision::Exact(b)) => {
120 Precision::Exact(if a >= b { b.clone() } else { a.clone() })
121 }
122 (Precision::Inexact(a), Precision::Exact(b))
123 | (Precision::Exact(a), Precision::Inexact(b))
124 | (Precision::Inexact(a), Precision::Inexact(b)) => {
125 Precision::Inexact(if a >= b { b.clone() } else { a.clone() })
126 }
127 (_, _) => Precision::Absent,
128 }
129 }
130
131 pub fn to_inexact(self) -> Self {
133 match self {
134 Precision::Exact(value) => Precision::Inexact(value),
135 _ => self,
136 }
137 }
138}
139
140impl Precision<usize> {
141 pub fn add(&self, other: &Precision<usize>) -> Precision<usize> {
145 match (self, other) {
146 (Precision::Exact(a), Precision::Exact(b)) => a.checked_add(*b).map_or_else(
147 || Precision::Inexact(a.saturating_add(*b)),
148 Precision::Exact,
149 ),
150 (Precision::Inexact(a), Precision::Exact(b))
151 | (Precision::Exact(a), Precision::Inexact(b))
152 | (Precision::Inexact(a), Precision::Inexact(b)) => {
153 Precision::Inexact(a.saturating_add(*b))
154 }
155 (_, _) => Precision::Absent,
156 }
157 }
158
159 pub fn sub(&self, other: &Precision<usize>) -> Precision<usize> {
163 match (self, other) {
164 (Precision::Exact(a), Precision::Exact(b)) => a.checked_sub(*b).map_or_else(
165 || Precision::Inexact(a.saturating_sub(*b)),
166 Precision::Exact,
167 ),
168 (Precision::Inexact(a), Precision::Exact(b))
169 | (Precision::Exact(a), Precision::Inexact(b))
170 | (Precision::Inexact(a), Precision::Inexact(b)) => {
171 Precision::Inexact(a.saturating_sub(*b))
172 }
173 (_, _) => Precision::Absent,
174 }
175 }
176
177 pub fn multiply(&self, other: &Precision<usize>) -> Precision<usize> {
181 match (self, other) {
182 (Precision::Exact(a), Precision::Exact(b)) => a.checked_mul(*b).map_or_else(
183 || Precision::Inexact(a.saturating_mul(*b)),
184 Precision::Exact,
185 ),
186 (Precision::Inexact(a), Precision::Exact(b))
187 | (Precision::Exact(a), Precision::Inexact(b))
188 | (Precision::Inexact(a), Precision::Inexact(b)) => {
189 Precision::Inexact(a.saturating_mul(*b))
190 }
191 (_, _) => Precision::Absent,
192 }
193 }
194
195 pub fn with_estimated_selectivity(self, selectivity: f64) -> Self {
201 if self == Precision::Exact(0) {
202 return self;
203 }
204 self.map(|v| ((v as f64 * selectivity).ceil()) as usize)
205 .to_inexact()
206 }
207}
208
209impl Precision<ScalarValue> {
210 fn sum_data_type(data_type: &DataType) -> DataType {
211 match data_type {
212 DataType::Int8 | DataType::Int16 | DataType::Int32 => DataType::Int64,
213 DataType::UInt8 | DataType::UInt16 | DataType::UInt32 => DataType::UInt64,
214 _ => data_type.clone(),
215 }
216 }
217
218 fn cast_scalar_to_sum_type(value: &ScalarValue) -> Result<ScalarValue> {
219 let source_type = value.data_type();
220 let target_type = Self::sum_data_type(&source_type);
221 if source_type == target_type {
222 Ok(value.clone())
223 } else {
224 value.cast_to(&target_type)
225 }
226 }
227
228 pub fn add(&self, other: &Precision<ScalarValue>) -> Precision<ScalarValue> {
238 match (self, other) {
239 (Precision::Exact(a), Precision::Exact(b)) => a
240 .add_checked(b)
241 .map(Precision::Exact)
242 .unwrap_or(Precision::Absent),
243 (Precision::Inexact(a), Precision::Exact(b))
244 | (Precision::Exact(a), Precision::Inexact(b))
245 | (Precision::Inexact(a), Precision::Inexact(b)) => a
246 .add_checked(b)
247 .map(Precision::Inexact)
248 .unwrap_or(Precision::Absent),
249 (_, _) => Precision::Absent,
250 }
251 }
252
253 pub fn cast_to_sum_type(&self) -> Precision<ScalarValue> {
258 match (self.is_exact(), self.get_value()) {
259 (Some(true), Some(value)) => Self::cast_scalar_to_sum_type(value)
260 .map(Precision::Exact)
261 .unwrap_or(Precision::Absent),
262 (Some(false), Some(value)) => Self::cast_scalar_to_sum_type(value)
263 .map(Precision::Inexact)
264 .unwrap_or(Precision::Absent),
265 (_, _) => Precision::Absent,
266 }
267 }
268
269 pub fn add_for_sum(&self, other: &Precision<ScalarValue>) -> Precision<ScalarValue> {
272 let mut lhs = self.cast_to_sum_type();
273 let rhs = other.cast_to_sum_type();
274 precision_add(&mut lhs, &rhs);
275 lhs
276 }
277
278 pub fn sub(&self, other: &Precision<ScalarValue>) -> Precision<ScalarValue> {
282 match (self, other) {
283 (Precision::Exact(a), Precision::Exact(b)) => {
284 a.sub(b).map(Precision::Exact).unwrap_or(Precision::Absent)
285 }
286 (Precision::Inexact(a), Precision::Exact(b))
287 | (Precision::Exact(a), Precision::Inexact(b))
288 | (Precision::Inexact(a), Precision::Inexact(b)) => a
289 .sub(b)
290 .map(Precision::Inexact)
291 .unwrap_or(Precision::Absent),
292 (_, _) => Precision::Absent,
293 }
294 }
295
296 pub fn multiply(&self, other: &Precision<ScalarValue>) -> Precision<ScalarValue> {
300 match (self, other) {
301 (Precision::Exact(a), Precision::Exact(b)) => a
302 .mul_checked(b)
303 .map(Precision::Exact)
304 .unwrap_or(Precision::Absent),
305 (Precision::Inexact(a), Precision::Exact(b))
306 | (Precision::Exact(a), Precision::Inexact(b))
307 | (Precision::Inexact(a), Precision::Inexact(b)) => a
308 .mul_checked(b)
309 .map(Precision::Inexact)
310 .unwrap_or(Precision::Absent),
311 (_, _) => Precision::Absent,
312 }
313 }
314
315 pub fn cast_to(&self, data_type: &DataType) -> Result<Precision<ScalarValue>> {
317 match self {
318 Precision::Exact(value) => value.cast_to(data_type).map(Precision::Exact),
319 Precision::Inexact(value) => value.cast_to(data_type).map(Precision::Inexact),
320 Precision::Absent => Ok(Precision::Absent),
321 }
322 }
323}
324
325impl<T: Debug + Clone + PartialEq + Eq + PartialOrd> From<Option<T>> for Precision<T> {
326 fn from(option: Option<T>) -> Self {
327 option.map_or(Precision::Absent, Precision::Exact)
328 }
329}
330
331impl<T: Debug + Clone + PartialEq + Eq + PartialOrd> Debug for Precision<T> {
332 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333 match self {
334 Precision::Exact(inner) => write!(f, "Exact({inner:?})"),
335 Precision::Inexact(inner) => write!(f, "Inexact({inner:?})"),
336 Precision::Absent => write!(f, "Absent"),
337 }
338 }
339}
340
341impl<T: Debug + Clone + PartialEq + Eq + PartialOrd> Display for Precision<T> {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 match self {
344 Precision::Exact(inner) => write!(f, "Exact({inner:?})"),
345 Precision::Inexact(inner) => write!(f, "Inexact({inner:?})"),
346 Precision::Absent => write!(f, "Absent"),
347 }
348 }
349}
350
351impl From<Precision<usize>> for Precision<ScalarValue> {
352 fn from(value: Precision<usize>) -> Self {
353 match value {
354 Precision::Exact(v) => Precision::Exact(ScalarValue::UInt64(Some(v as u64))),
355 Precision::Inexact(v) => {
356 Precision::Inexact(ScalarValue::UInt64(Some(v as u64)))
357 }
358 Precision::Absent => Precision::Absent,
359 }
360 }
361}
362
363#[derive(Debug, Clone, PartialEq, Eq)]
368pub struct Statistics {
369 pub num_rows: Precision<usize>,
371 pub total_byte_size: Precision<usize>,
378 pub column_statistics: Vec<ColumnStatistics>,
383}
384
385#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
387pub enum NdvFallback {
388 #[default]
391 Max,
392 Sum,
395}
396
397impl NdvFallback {
398 fn merge(self, left: usize, right: usize) -> usize {
399 match self {
400 Self::Max => usize::max(left, right),
401 Self::Sum => left.saturating_add(right),
402 }
403 }
404}
405
406impl Default for Statistics {
407 fn default() -> Self {
410 Self {
411 num_rows: Precision::Absent,
412 total_byte_size: Precision::Absent,
413 column_statistics: vec![],
414 }
415 }
416}
417
418impl Statistics {
419 pub fn new_unknown(schema: &Schema) -> Self {
422 Self {
423 num_rows: Precision::Absent,
424 total_byte_size: Precision::Absent,
425 column_statistics: Statistics::unknown_column(schema),
426 }
427 }
428
429 pub fn calculate_total_byte_size(&mut self, schema: &Schema) {
434 let mut row_size = Some(0);
435 for field in schema.fields() {
436 match field.data_type().primitive_width() {
437 Some(width) => {
438 row_size = row_size.map(|s| s + width);
439 }
440 None => {
441 row_size = None;
442 break;
443 }
444 }
445 }
446 match (row_size, &self.num_rows) {
447 (None, _) | (Some(_), Precision::Absent) => {
448 self.total_byte_size = self.total_byte_size.to_inexact();
449 }
450 (Some(size), _) => {
451 self.total_byte_size = self.num_rows.multiply(&Precision::Exact(size));
452 }
453 }
454 }
455
456 pub fn unknown_column(schema: &Schema) -> Vec<ColumnStatistics> {
458 schema
459 .fields()
460 .iter()
461 .map(|_| ColumnStatistics::new_unknown())
462 .collect()
463 }
464
465 pub fn with_num_rows(mut self, num_rows: Precision<usize>) -> Self {
467 self.num_rows = num_rows;
468 self
469 }
470
471 pub fn with_total_byte_size(mut self, total_byte_size: Precision<usize>) -> Self {
473 self.total_byte_size = total_byte_size;
474 self
475 }
476
477 pub fn add_column_statistics(mut self, column_stats: ColumnStatistics) -> Self {
479 self.column_statistics.push(column_stats);
480 self
481 }
482
483 pub fn to_inexact(mut self) -> Self {
486 self.num_rows = self.num_rows.to_inexact();
487 self.total_byte_size = self.total_byte_size.to_inexact();
488 self.column_statistics = self
489 .column_statistics
490 .into_iter()
491 .map(|s| s.to_inexact())
492 .collect();
493 self
494 }
495
496 pub fn project(self, projection: Option<&impl AsRef<[usize]>>) -> Self {
502 let projection = projection.map(AsRef::as_ref);
503 self.project_impl(projection)
504 }
505
506 fn project_impl(mut self, projection: Option<&[usize]>) -> Self {
507 let Some(projection) = projection.map(AsRef::as_ref) else {
508 return self;
509 };
510
511 #[expect(clippy::large_enum_variant)]
512 enum Slot {
513 Taken(usize),
515 Present(ColumnStatistics),
517 }
518
519 let mut columns: Vec<_> = std::mem::take(&mut self.column_statistics)
521 .into_iter()
522 .map(Slot::Present)
523 .collect();
524
525 for idx in projection.iter() {
526 let next_idx = self.column_statistics.len();
527 let slot = std::mem::replace(
528 columns.get_mut(*idx).expect("projection out of bounds"),
529 Slot::Taken(next_idx),
530 );
531 match slot {
532 Slot::Present(col) => self.column_statistics.push(col),
534 Slot::Taken(prev_idx) => self
536 .column_statistics
537 .push(self.column_statistics[prev_idx].clone()),
538 }
539 }
540
541 self
542 }
543
544 pub fn with_fetch(
549 mut self,
550 fetch: Option<usize>,
551 skip: usize,
552 n_partitions: usize,
553 ) -> Result<Self> {
554 if fetch.is_none() && skip == 0 {
555 return Ok(self);
556 }
557
558 let fetch_val = fetch.unwrap_or(usize::MAX);
559
560 let num_rows_before = self.num_rows;
562
563 self.num_rows = match self {
564 Statistics {
565 num_rows: Precision::Exact(nr),
566 ..
567 }
568 | Statistics {
569 num_rows: Precision::Inexact(nr),
570 ..
571 } => {
572 if nr <= skip {
574 check_num_rows(Some(0), self.num_rows.is_exact().unwrap())
578 } else if nr <= fetch_val && skip == 0 {
579 return Ok(self);
585 } else if nr - skip <= fetch_val {
586 check_num_rows(
590 (nr - skip).checked_mul(n_partitions),
591 self.num_rows.is_exact().unwrap(),
593 )
594 } else {
595 check_num_rows(
600 fetch_val.checked_mul(n_partitions),
601 self.num_rows.is_exact().unwrap(),
603 )
604 }
605 }
606 Statistics {
607 num_rows: Precision::Absent,
608 ..
609 } => check_num_rows(fetch.and_then(|v| v.checked_mul(n_partitions)), false),
610 };
611 let ratio: Option<f64> = match (num_rows_before, self.num_rows) {
612 (
613 Precision::Exact(nr_before) | Precision::Inexact(nr_before),
614 Precision::Exact(nr_after) | Precision::Inexact(nr_after),
615 ) => {
616 if nr_before == 0 {
617 Some(0.0)
618 } else {
619 Some(nr_after as f64 / nr_before as f64)
620 }
621 }
622 _ => None,
623 };
624 self.column_statistics = self
625 .column_statistics
626 .into_iter()
627 .map(|cs| {
628 let mut cs = cs.to_inexact();
629 cs.byte_size = match (cs.byte_size, ratio) {
631 (Precision::Exact(n) | Precision::Inexact(n), Some(ratio)) => {
632 Precision::Inexact((n as f64 * ratio) as usize)
633 }
634 _ => Precision::Absent,
635 };
636 if let Some(&rows) = self.num_rows.get_value() {
638 cs.distinct_count = cs.distinct_count.min(&Precision::Inexact(rows));
639 }
640 cs
641 })
642 .collect();
643
644 let sum_scan_bytes: Option<usize> = self
647 .column_statistics
648 .iter()
649 .map(|cs| cs.byte_size.get_value().copied())
650 .try_fold(0usize, |acc, val| val.map(|v| acc + v));
651
652 self.total_byte_size = match sum_scan_bytes {
653 Some(sum) => Precision::Inexact(sum),
654 None => {
655 match (&self.total_byte_size, ratio) {
657 (Precision::Exact(n) | Precision::Inexact(n), Some(ratio)) => {
658 Precision::Inexact((*n as f64 * ratio) as usize)
659 }
660 _ => Precision::Absent,
661 }
662 }
663 };
664 Ok(self)
665 }
666
667 pub fn try_merge_iter<'a, I>(items: I, schema: &Schema) -> Result<Statistics>
715 where
716 I: IntoIterator<Item = &'a Statistics>,
717 {
718 Self::try_merge_iter_with_ndv_fallback(items, schema, NdvFallback::Max)
719 }
720
721 pub fn try_merge_iter_with_ndv_fallback<'a, I>(
724 items: I,
725 schema: &Schema,
726 ndv_fallback: NdvFallback,
727 ) -> Result<Statistics>
728 where
729 I: IntoIterator<Item = &'a Statistics>,
730 {
731 let mut items = items.into_iter();
732 let Some(first) = items.next() else {
733 return Ok(Statistics::new_unknown(schema));
734 };
735 let Some(second) = items.next() else {
736 return Ok(first.clone());
737 };
738
739 let num_cols = first.column_statistics.len();
740 let mut num_rows = first.num_rows;
741 let mut total_byte_size = first.total_byte_size;
742 let mut column_statistics = first.column_statistics.clone();
743 for col_stats in &mut column_statistics {
744 cast_sum_value_to_sum_type_in_place(&mut col_stats.sum_value);
745 }
746
747 for (i, stat) in std::iter::once(second).chain(items).enumerate() {
749 if stat.column_statistics.len() != num_cols {
750 return _plan_err!(
751 "Cannot merge statistics with different number of columns: {} vs {} (item {})",
752 num_cols,
753 stat.column_statistics.len(),
754 i + 1
755 );
756 }
757 num_rows = num_rows.add(&stat.num_rows);
758 total_byte_size = total_byte_size.add(&stat.total_byte_size);
759
760 for (col_stats, item_cs) in
764 column_statistics.iter_mut().zip(&stat.column_statistics)
765 {
766 col_stats.null_count = col_stats.null_count.add(&item_cs.null_count);
767
768 col_stats.distinct_count = match (
770 col_stats.distinct_count.get_value(),
771 item_cs.distinct_count.get_value(),
772 ) {
773 (Some(&l), Some(&r)) => Precision::Inexact(
774 estimate_ndv_with_overlap(col_stats, item_cs, l, r)
775 .unwrap_or_else(|| ndv_fallback.merge(l, r)),
776 ),
777 _ => Precision::Absent,
778 };
779 precision_min(&mut col_stats.min_value, &item_cs.min_value);
780 precision_max(&mut col_stats.max_value, &item_cs.max_value);
781 precision_add_for_sum_in_place(
782 &mut col_stats.sum_value,
783 &item_cs.sum_value,
784 );
785 col_stats.byte_size = col_stats.byte_size.add(&item_cs.byte_size);
786 }
787 }
788
789 Ok(Statistics {
790 num_rows,
791 total_byte_size,
792 column_statistics,
793 })
794 }
795}
796
797pub fn estimate_ndv_with_overlap(
832 left: &ColumnStatistics,
833 right: &ColumnStatistics,
834 ndv_left: usize,
835 ndv_right: usize,
836) -> Option<usize> {
837 let left_min = left.min_value.get_value()?;
838 let left_max = left.max_value.get_value()?;
839 let right_min = right.min_value.get_value()?;
840 let right_max = right.max_value.get_value()?;
841
842 let range_left = left_max.distance_u64(left_min)?;
843 let range_right = right_max.distance_u64(right_min)?;
844
845 if range_left == 0 || range_right == 0 {
848 let overlaps = left_min <= right_max && right_min <= left_max;
849 return Some(if overlaps {
850 usize::max(ndv_left, ndv_right)
851 } else {
852 ndv_left + ndv_right
853 });
854 }
855
856 let overlap_min = if left_min >= right_min {
857 left_min
858 } else {
859 right_min
860 };
861 let overlap_max = if left_max <= right_max {
862 left_max
863 } else {
864 right_max
865 };
866
867 if overlap_min > overlap_max {
869 return Some(ndv_left + ndv_right);
870 }
871
872 let overlap_range = overlap_max.distance_u64(overlap_min)? as f64;
873
874 let overlap_left = overlap_range / range_left as f64;
875 let overlap_right = overlap_range / range_right as f64;
876
877 let intersection = f64::max(
878 overlap_left * ndv_left as f64,
879 overlap_right * ndv_right as f64,
880 );
881 let only_left = (1.0 - overlap_left) * ndv_left as f64;
882 let only_right = (1.0 - overlap_right) * ndv_right as f64;
883
884 Some((intersection + only_left + only_right).round() as usize)
885}
886
887#[inline]
890fn precision_min<T>(lhs: &mut Precision<T>, rhs: &Precision<T>)
891where
892 T: Debug + Clone + PartialEq + Eq + PartialOrd,
893{
894 *lhs = match (std::mem::take(lhs), rhs) {
895 (Precision::Exact(left), Precision::Exact(right)) => {
896 if left <= *right {
897 Precision::Exact(left)
898 } else {
899 Precision::Exact(right.clone())
900 }
901 }
902 (Precision::Exact(left), Precision::Inexact(right))
903 | (Precision::Inexact(left), Precision::Exact(right))
904 | (Precision::Inexact(left), Precision::Inexact(right)) => {
905 if left <= *right {
906 Precision::Inexact(left)
907 } else {
908 Precision::Inexact(right.clone())
909 }
910 }
911 (_, _) => Precision::Absent,
912 };
913}
914
915#[inline]
918fn precision_max<T>(lhs: &mut Precision<T>, rhs: &Precision<T>)
919where
920 T: Debug + Clone + PartialEq + Eq + PartialOrd,
921{
922 *lhs = match (std::mem::take(lhs), rhs) {
923 (Precision::Exact(left), Precision::Exact(right)) => {
924 if left >= *right {
925 Precision::Exact(left)
926 } else {
927 Precision::Exact(right.clone())
928 }
929 }
930 (Precision::Exact(left), Precision::Inexact(right))
931 | (Precision::Inexact(left), Precision::Exact(right))
932 | (Precision::Inexact(left), Precision::Inexact(right)) => {
933 if left >= *right {
934 Precision::Inexact(left)
935 } else {
936 Precision::Inexact(right.clone())
937 }
938 }
939 (_, _) => Precision::Absent,
940 };
941}
942
943#[inline]
944fn cast_sum_value_to_sum_type_in_place(value: &mut Precision<ScalarValue>) {
945 let (is_exact, inner) = match std::mem::take(value) {
946 Precision::Exact(v) => (true, v),
947 Precision::Inexact(v) => (false, v),
948 Precision::Absent => return,
949 };
950 let source_type = inner.data_type();
951 let target_type = Precision::<ScalarValue>::sum_data_type(&source_type);
952
953 let wrap_precision_fn: fn(ScalarValue) -> Precision<ScalarValue> = if is_exact {
954 Precision::Exact
955 } else {
956 Precision::Inexact
957 };
958
959 *value = if source_type == target_type {
960 wrap_precision_fn(inner)
961 } else {
962 inner
963 .cast_to(&target_type)
964 .map(wrap_precision_fn)
965 .unwrap_or(Precision::Absent)
966 };
967}
968
969#[inline]
970fn precision_add_for_sum_in_place(
971 lhs: &mut Precision<ScalarValue>,
972 rhs: &Precision<ScalarValue>,
973) {
974 let (value, wrap_fn): (&ScalarValue, fn(ScalarValue) -> Precision<ScalarValue>) =
975 match rhs {
976 Precision::Exact(v) => (v, Precision::Exact),
977 Precision::Inexact(v) => (v, Precision::Inexact),
978 Precision::Absent => {
979 *lhs = Precision::Absent;
980 return;
981 }
982 };
983 let source_type = value.data_type();
984 let target_type = Precision::<ScalarValue>::sum_data_type(&source_type);
985 if source_type == target_type {
986 precision_add(lhs, rhs);
987 } else {
988 let rhs = value
989 .cast_to(&target_type)
990 .map(wrap_fn)
991 .unwrap_or(Precision::Absent);
992 precision_add(lhs, &rhs);
993 }
994}
995
996fn check_num_rows(value: Option<usize>, is_exact: bool) -> Precision<usize> {
999 if let Some(value) = value {
1000 if is_exact {
1001 Precision::Exact(value)
1002 } else {
1003 Precision::Inexact(value)
1005 }
1006 } else {
1007 Precision::Absent
1010 }
1011}
1012
1013impl Display for Statistics {
1014 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1015 let column_stats = self
1017 .column_statistics
1018 .iter()
1019 .enumerate()
1020 .map(|(i, cs)| {
1021 let s = format!("(Col[{i}]:");
1022 let s = if cs.min_value != Precision::Absent {
1023 format!("{} Min={}", s, cs.min_value)
1024 } else {
1025 s
1026 };
1027 let s = if cs.max_value != Precision::Absent {
1028 format!("{} Max={}", s, cs.max_value)
1029 } else {
1030 s
1031 };
1032 let s = if cs.sum_value != Precision::Absent {
1033 format!("{} Sum={}", s, cs.sum_value)
1034 } else {
1035 s
1036 };
1037 let s = if cs.null_count != Precision::Absent {
1038 format!("{} Null={}", s, cs.null_count)
1039 } else {
1040 s
1041 };
1042 let s = if cs.distinct_count != Precision::Absent {
1043 format!("{} Distinct={}", s, cs.distinct_count)
1044 } else {
1045 s
1046 };
1047 let s = if cs.byte_size != Precision::Absent {
1048 format!("{} ScanBytes={}", s, cs.byte_size)
1049 } else {
1050 s
1051 };
1052
1053 s + ")"
1054 })
1055 .collect::<Vec<_>>()
1056 .join(",");
1057
1058 write!(
1059 f,
1060 "Rows={}, Bytes={}, [{}]",
1061 self.num_rows, self.total_byte_size, column_stats
1062 )?;
1063
1064 Ok(())
1065 }
1066}
1067
1068#[derive(Clone, Debug, PartialEq, Eq, Default)]
1070pub struct ColumnStatistics {
1071 pub null_count: Precision<usize>,
1073 pub max_value: Precision<ScalarValue>,
1075 pub min_value: Precision<ScalarValue>,
1077 pub sum_value: Precision<ScalarValue>,
1087 pub distinct_count: Precision<usize>,
1089 pub byte_size: Precision<usize>,
1104}
1105
1106impl ColumnStatistics {
1107 pub fn is_singleton(&self) -> bool {
1109 match (&self.min_value, &self.max_value) {
1110 (Precision::Exact(min), Precision::Exact(max)) => {
1112 !min.is_null() && !max.is_null() && (min == max)
1113 }
1114 (_, _) => false,
1115 }
1116 }
1117
1118 pub fn new_unknown() -> Self {
1120 Self {
1121 null_count: Precision::Absent,
1122 max_value: Precision::Absent,
1123 min_value: Precision::Absent,
1124 sum_value: Precision::Absent,
1125 distinct_count: Precision::Absent,
1126 byte_size: Precision::Absent,
1127 }
1128 }
1129
1130 pub fn with_null_count(mut self, null_count: Precision<usize>) -> Self {
1132 self.null_count = null_count;
1133 self
1134 }
1135
1136 pub fn with_max_value(mut self, max_value: Precision<ScalarValue>) -> Self {
1138 self.max_value = max_value;
1139 self
1140 }
1141
1142 pub fn with_min_value(mut self, min_value: Precision<ScalarValue>) -> Self {
1144 self.min_value = min_value;
1145 self
1146 }
1147
1148 pub fn with_sum_value(mut self, sum_value: Precision<ScalarValue>) -> Self {
1150 self.sum_value = match sum_value {
1151 Precision::Exact(value) => {
1152 Precision::<ScalarValue>::cast_scalar_to_sum_type(&value)
1153 .map(Precision::Exact)
1154 .unwrap_or(Precision::Absent)
1155 }
1156 Precision::Inexact(value) => {
1157 Precision::<ScalarValue>::cast_scalar_to_sum_type(&value)
1158 .map(Precision::Inexact)
1159 .unwrap_or(Precision::Absent)
1160 }
1161 Precision::Absent => Precision::Absent,
1162 };
1163 self
1164 }
1165
1166 pub fn with_distinct_count(mut self, distinct_count: Precision<usize>) -> Self {
1168 self.distinct_count = distinct_count;
1169 self
1170 }
1171
1172 pub fn with_byte_size(mut self, byte_size: Precision<usize>) -> Self {
1175 self.byte_size = byte_size;
1176 self
1177 }
1178
1179 pub fn to_inexact(mut self) -> Self {
1183 self.null_count = self.null_count.to_inexact();
1184 self.max_value = self.max_value.to_inexact();
1185 self.min_value = self.min_value.to_inexact();
1186 self.sum_value = self.sum_value.to_inexact();
1187 self.distinct_count = self.distinct_count.to_inexact();
1188 self.byte_size = self.byte_size.to_inexact();
1189 self
1190 }
1191}
1192
1193#[cfg(test)]
1194mod tests {
1195 use super::*;
1196 use crate::assert_contains;
1197 use arrow::datatypes::Field;
1198 use std::sync::Arc;
1199
1200 #[test]
1201 fn test_get_value() {
1202 let exact_precision = Precision::Exact(42);
1203 let inexact_precision = Precision::Inexact(23);
1204 let absent_precision = Precision::<i32>::Absent;
1205
1206 assert_eq!(*exact_precision.get_value().unwrap(), 42);
1207 assert_eq!(*inexact_precision.get_value().unwrap(), 23);
1208 assert_eq!(absent_precision.get_value(), None);
1209 }
1210
1211 #[test]
1212 fn test_with_estimated_selectivity() {
1213 assert_eq!(
1215 Precision::Exact(0).with_estimated_selectivity(0.5),
1216 Precision::Exact(0)
1217 );
1218 assert_eq!(
1219 Precision::Exact(0).with_estimated_selectivity(1.0),
1220 Precision::Exact(0)
1221 );
1222
1223 assert_eq!(
1226 Precision::Exact(100).with_estimated_selectivity(0.5),
1227 Precision::Inexact(50)
1228 );
1229 assert_eq!(
1230 Precision::Exact(100).with_estimated_selectivity(1.0),
1231 Precision::Inexact(100)
1232 );
1233 assert_eq!(
1234 Precision::Exact(3).with_estimated_selectivity(0.5),
1235 Precision::Inexact(2)
1236 );
1237
1238 assert_eq!(
1240 Precision::Inexact(0).with_estimated_selectivity(0.5),
1241 Precision::Inexact(0)
1242 );
1243 assert_eq!(
1244 Precision::<usize>::Absent.with_estimated_selectivity(0.5),
1245 Precision::Absent
1246 );
1247 }
1248
1249 #[test]
1250 fn test_map() {
1251 let exact_precision = Precision::Exact(42);
1252 let inexact_precision = Precision::Inexact(23);
1253 let absent_precision = Precision::Absent;
1254
1255 let squared = |x| x * x;
1256
1257 assert_eq!(exact_precision.map(squared), Precision::Exact(1764));
1258 assert_eq!(inexact_precision.map(squared), Precision::Inexact(529));
1259 assert_eq!(absent_precision.map(squared), Precision::Absent);
1260 }
1261
1262 #[test]
1263 fn test_is_exact() {
1264 let exact_precision = Precision::Exact(42);
1265 let inexact_precision = Precision::Inexact(23);
1266 let absent_precision = Precision::<i32>::Absent;
1267
1268 assert_eq!(exact_precision.is_exact(), Some(true));
1269 assert_eq!(inexact_precision.is_exact(), Some(false));
1270 assert_eq!(absent_precision.is_exact(), None);
1271 }
1272
1273 #[test]
1274 fn test_max() {
1275 let precision1 = Precision::Exact(42);
1276 let precision2 = Precision::Inexact(23);
1277 let precision3 = Precision::Exact(30);
1278 let absent_precision = Precision::Absent;
1279
1280 assert_eq!(precision1.max(&precision2), Precision::Inexact(42));
1281 assert_eq!(precision1.max(&precision3), Precision::Exact(42));
1282 assert_eq!(precision2.max(&precision3), Precision::Inexact(30));
1283 assert_eq!(precision1.max(&absent_precision), Precision::Absent);
1284 }
1285
1286 #[test]
1287 fn test_min() {
1288 let precision1 = Precision::Exact(42);
1289 let precision2 = Precision::Inexact(23);
1290 let precision3 = Precision::Exact(30);
1291 let absent_precision = Precision::Absent;
1292
1293 assert_eq!(precision1.min(&precision2), Precision::Inexact(23));
1294 assert_eq!(precision1.min(&precision3), Precision::Exact(30));
1295 assert_eq!(precision2.min(&precision3), Precision::Inexact(23));
1296 assert_eq!(precision1.min(&absent_precision), Precision::Absent);
1297 }
1298
1299 #[test]
1300 fn test_to_inexact() {
1301 let exact_precision = Precision::Exact(42);
1302 let inexact_precision = Precision::Inexact(42);
1303 let absent_precision = Precision::<i32>::Absent;
1304
1305 assert_eq!(exact_precision.to_inexact(), inexact_precision);
1306 assert_eq!(inexact_precision.to_inexact(), inexact_precision);
1307 assert_eq!(absent_precision.to_inexact(), absent_precision);
1308 }
1309
1310 #[test]
1311 fn test_add() {
1312 let precision1 = Precision::Exact(42);
1313 let precision2 = Precision::Inexact(23);
1314 let precision3 = Precision::Exact(30);
1315 let absent_precision = Precision::Absent;
1316 let precision_max_exact = Precision::Exact(usize::MAX);
1317 let precision_max_inexact = Precision::Exact(usize::MAX);
1318
1319 assert_eq!(precision1.add(&precision2), Precision::Inexact(65));
1320 assert_eq!(precision1.add(&precision3), Precision::Exact(72));
1321 assert_eq!(precision2.add(&precision3), Precision::Inexact(53));
1322 assert_eq!(precision1.add(&absent_precision), Precision::Absent);
1323 assert_eq!(
1324 precision_max_exact.add(&precision1),
1325 Precision::Inexact(usize::MAX)
1326 );
1327 assert_eq!(
1328 precision_max_inexact.add(&precision1),
1329 Precision::Inexact(usize::MAX)
1330 );
1331 }
1332
1333 #[test]
1334 fn test_add_scalar() {
1335 let precision = Precision::Exact(ScalarValue::Int32(Some(42)));
1336
1337 assert_eq!(
1338 precision.add(&Precision::Exact(ScalarValue::Int32(Some(23)))),
1339 Precision::Exact(ScalarValue::Int32(Some(65))),
1340 );
1341 assert_eq!(
1342 precision.add(&Precision::Inexact(ScalarValue::Int32(Some(23)))),
1343 Precision::Inexact(ScalarValue::Int32(Some(65))),
1344 );
1345 assert_eq!(
1346 precision.add(&Precision::Exact(ScalarValue::Int32(None))),
1347 Precision::Exact(ScalarValue::Int32(None)),
1349 );
1350 assert_eq!(precision.add(&Precision::Absent), Precision::Absent);
1351 }
1352
1353 #[test]
1354 fn test_add_for_sum_scalar_integer_widening() {
1355 let precision = Precision::Exact(ScalarValue::Int32(Some(42)));
1356
1357 assert_eq!(
1358 precision.add_for_sum(&Precision::Exact(ScalarValue::Int32(Some(23)))),
1359 Precision::Exact(ScalarValue::Int64(Some(65))),
1360 );
1361 assert_eq!(
1362 precision.add_for_sum(&Precision::Inexact(ScalarValue::Int32(Some(23)))),
1363 Precision::Inexact(ScalarValue::Int64(Some(65))),
1364 );
1365 }
1366
1367 #[test]
1368 fn test_add_for_sum_prevents_int32_overflow() {
1369 let lhs = Precision::Exact(ScalarValue::Int32(Some(i32::MAX)));
1370 let rhs = Precision::Exact(ScalarValue::Int32(Some(1)));
1371
1372 assert_eq!(
1373 lhs.add_for_sum(&rhs),
1374 Precision::Exact(ScalarValue::Int64(Some(i64::from(i32::MAX) + 1))),
1375 );
1376 }
1377
1378 #[test]
1379 fn test_add_for_sum_scalar_unsigned_integer_widening() {
1380 let precision = Precision::Exact(ScalarValue::UInt32(Some(42)));
1381
1382 assert_eq!(
1383 precision.add_for_sum(&Precision::Exact(ScalarValue::UInt32(Some(23)))),
1384 Precision::Exact(ScalarValue::UInt64(Some(65))),
1385 );
1386 assert_eq!(
1387 precision.add_for_sum(&Precision::Inexact(ScalarValue::UInt32(Some(23)))),
1388 Precision::Inexact(ScalarValue::UInt64(Some(65))),
1389 );
1390 }
1391
1392 #[test]
1393 fn test_sub() {
1394 let precision1 = Precision::Exact(42);
1395 let precision2 = Precision::Inexact(23);
1396 let precision3 = Precision::Exact(30);
1397 let absent_precision = Precision::Absent;
1398
1399 assert_eq!(precision1.sub(&precision2), Precision::Inexact(19));
1400 assert_eq!(precision1.sub(&precision3), Precision::Exact(12));
1401 assert_eq!(precision2.sub(&precision1), Precision::Inexact(0));
1402 assert_eq!(precision3.sub(&precision1), Precision::Inexact(0));
1403 assert_eq!(precision1.sub(&absent_precision), Precision::Absent);
1404 }
1405
1406 #[test]
1407 fn test_sub_scalar() {
1408 let precision = Precision::Exact(ScalarValue::Int32(Some(42)));
1409
1410 assert_eq!(
1411 precision.sub(&Precision::Exact(ScalarValue::Int32(Some(23)))),
1412 Precision::Exact(ScalarValue::Int32(Some(19))),
1413 );
1414 assert_eq!(
1415 precision.sub(&Precision::Inexact(ScalarValue::Int32(Some(23)))),
1416 Precision::Inexact(ScalarValue::Int32(Some(19))),
1417 );
1418 assert_eq!(
1419 precision.sub(&Precision::Exact(ScalarValue::Int32(None))),
1420 Precision::Exact(ScalarValue::Int32(None)),
1422 );
1423 assert_eq!(precision.sub(&Precision::Absent), Precision::Absent);
1424 }
1425
1426 #[test]
1427 fn test_multiply() {
1428 let precision1 = Precision::Exact(6);
1429 let precision2 = Precision::Inexact(3);
1430 let precision3 = Precision::Exact(5);
1431 let precision_max_exact = Precision::Exact(usize::MAX);
1432 let precision_max_inexact = Precision::Exact(usize::MAX);
1433 let absent_precision = Precision::Absent;
1434
1435 assert_eq!(precision1.multiply(&precision2), Precision::Inexact(18));
1436 assert_eq!(precision1.multiply(&precision3), Precision::Exact(30));
1437 assert_eq!(precision2.multiply(&precision3), Precision::Inexact(15));
1438 assert_eq!(precision1.multiply(&absent_precision), Precision::Absent);
1439 assert_eq!(
1440 precision_max_exact.multiply(&precision1),
1441 Precision::Inexact(usize::MAX)
1442 );
1443 assert_eq!(
1444 precision_max_inexact.multiply(&precision1),
1445 Precision::Inexact(usize::MAX)
1446 );
1447 }
1448
1449 #[test]
1450 fn test_multiply_scalar() {
1451 let precision = Precision::Exact(ScalarValue::Int32(Some(6)));
1452
1453 assert_eq!(
1454 precision.multiply(&Precision::Exact(ScalarValue::Int32(Some(5)))),
1455 Precision::Exact(ScalarValue::Int32(Some(30))),
1456 );
1457 assert_eq!(
1458 precision.multiply(&Precision::Inexact(ScalarValue::Int32(Some(5)))),
1459 Precision::Inexact(ScalarValue::Int32(Some(30))),
1460 );
1461 assert_eq!(
1462 precision.multiply(&Precision::Exact(ScalarValue::Int32(None))),
1463 Precision::Exact(ScalarValue::Int32(None)),
1465 );
1466 assert_eq!(precision.multiply(&Precision::Absent), Precision::Absent);
1467 }
1468
1469 #[test]
1470 fn test_cast_to() {
1471 assert_eq!(
1473 Precision::Exact(ScalarValue::Int32(Some(42)))
1474 .cast_to(&DataType::Int64)
1475 .unwrap(),
1476 Precision::Exact(ScalarValue::Int64(Some(42))),
1477 );
1478 assert_eq!(
1479 Precision::Inexact(ScalarValue::Int32(Some(42)))
1480 .cast_to(&DataType::Int64)
1481 .unwrap(),
1482 Precision::Inexact(ScalarValue::Int64(Some(42))),
1483 );
1484 assert_eq!(
1486 Precision::Exact(ScalarValue::Int32(None))
1487 .cast_to(&DataType::Int64)
1488 .unwrap(),
1489 Precision::Exact(ScalarValue::Int64(None)),
1490 );
1491 assert!(
1493 Precision::Exact(ScalarValue::Int32(Some(256)))
1494 .cast_to(&DataType::Int8)
1495 .is_err()
1496 );
1497 }
1498
1499 #[test]
1500 fn test_precision_cloning() {
1501 let precision: Precision<usize> = Precision::Exact(42);
1503 let p2 = precision;
1504 assert_eq!(precision, p2);
1505
1506 let precision: Precision<ScalarValue> =
1508 Precision::Exact(ScalarValue::Int64(Some(42)));
1509 let p2 = precision.clone();
1510 assert_eq!(precision, p2);
1511 }
1512
1513 #[test]
1514 fn test_project_none() {
1515 let projection: Option<Vec<usize>> = None;
1516 let stats = make_stats(vec![10, 20, 30]).project(projection.as_ref());
1517 assert_eq!(stats, make_stats(vec![10, 20, 30]));
1518 }
1519
1520 #[test]
1521 fn test_project_empty() {
1522 let projection = Some(vec![]);
1523 let stats = make_stats(vec![10, 20, 30]).project(projection.as_ref());
1524 assert_eq!(stats, make_stats(vec![]));
1525 }
1526
1527 #[test]
1528 fn test_project_swap() {
1529 let projection = Some(vec![2, 1]);
1530 let stats = make_stats(vec![10, 20, 30]).project(projection.as_ref());
1531 assert_eq!(stats, make_stats(vec![30, 20]));
1532 }
1533
1534 #[test]
1535 fn test_project_repeated() {
1536 let projection = Some(vec![1, 2, 1, 1, 0, 2]);
1537 let stats = make_stats(vec![10, 20, 30]).project(projection.as_ref());
1538 assert_eq!(stats, make_stats(vec![20, 30, 20, 20, 10, 30]));
1539 }
1540
1541 fn make_stats(counts: impl IntoIterator<Item = usize>) -> Statistics {
1543 Statistics {
1544 num_rows: Precision::Exact(42),
1545 total_byte_size: Precision::Exact(500),
1546 column_statistics: counts.into_iter().map(col_stats_i64).collect(),
1547 }
1548 }
1549
1550 fn col_stats_i64(null_count: usize) -> ColumnStatistics {
1551 ColumnStatistics {
1552 null_count: Precision::Exact(null_count),
1553 max_value: Precision::Exact(ScalarValue::Int64(Some(42))),
1554 min_value: Precision::Exact(ScalarValue::Int64(Some(64))),
1555 sum_value: Precision::Exact(ScalarValue::Int64(Some(4600))),
1556 distinct_count: Precision::Exact(100),
1557 byte_size: Precision::Exact(800),
1558 }
1559 }
1560
1561 fn make_single_i64_ndv_stats(
1562 distinct_count: Precision<usize>,
1563 min_value: Option<i64>,
1564 max_value: Option<i64>,
1565 ) -> Statistics {
1566 let to_precision = |value| Precision::Exact(ScalarValue::Int64(Some(value)));
1567
1568 Statistics::default()
1569 .with_num_rows(Precision::Exact(10))
1570 .add_column_statistics(
1571 ColumnStatistics::new_unknown()
1572 .with_distinct_count(distinct_count)
1573 .with_min_value(
1574 min_value.map(to_precision).unwrap_or(Precision::Absent),
1575 )
1576 .with_max_value(
1577 max_value.map(to_precision).unwrap_or(Precision::Absent),
1578 ),
1579 )
1580 }
1581
1582 fn merge_single_i64_ndv_distinct_count(
1583 left: Statistics,
1584 right: Statistics,
1585 ndv_fallback: NdvFallback,
1586 ) -> Precision<usize> {
1587 let schema = Schema::new(vec![Field::new("a", DataType::Int64, true)]);
1588
1589 Statistics::try_merge_iter_with_ndv_fallback(
1590 [&left, &right],
1591 &schema,
1592 ndv_fallback,
1593 )
1594 .unwrap()
1595 .column_statistics[0]
1596 .distinct_count
1597 }
1598
1599 #[test]
1600 fn test_try_merge() {
1601 let schema = Arc::new(Schema::new(vec![
1603 Field::new("col1", DataType::Int32, false),
1604 Field::new("col2", DataType::Int32, false),
1605 ]));
1606
1607 let stats1 = Statistics {
1609 num_rows: Precision::Exact(10),
1610 total_byte_size: Precision::Exact(100),
1611 column_statistics: vec![
1612 ColumnStatistics {
1613 null_count: Precision::Exact(1),
1614 max_value: Precision::Exact(ScalarValue::Int32(Some(100))),
1615 min_value: Precision::Exact(ScalarValue::Int32(Some(1))),
1616 sum_value: Precision::Exact(ScalarValue::Int32(Some(500))),
1617 distinct_count: Precision::Absent,
1618 byte_size: Precision::Exact(40),
1619 },
1620 ColumnStatistics {
1621 null_count: Precision::Exact(2),
1622 max_value: Precision::Exact(ScalarValue::Int32(Some(200))),
1623 min_value: Precision::Exact(ScalarValue::Int32(Some(10))),
1624 sum_value: Precision::Exact(ScalarValue::Int32(Some(1000))),
1625 distinct_count: Precision::Absent,
1626 byte_size: Precision::Exact(40),
1627 },
1628 ],
1629 };
1630
1631 let stats2 = Statistics {
1632 num_rows: Precision::Exact(15),
1633 total_byte_size: Precision::Exact(150),
1634 column_statistics: vec![
1635 ColumnStatistics {
1636 null_count: Precision::Exact(2),
1637 max_value: Precision::Exact(ScalarValue::Int32(Some(120))),
1638 min_value: Precision::Exact(ScalarValue::Int32(Some(-10))),
1639 sum_value: Precision::Exact(ScalarValue::Int32(Some(600))),
1640 distinct_count: Precision::Absent,
1641 byte_size: Precision::Exact(60),
1642 },
1643 ColumnStatistics {
1644 null_count: Precision::Exact(3),
1645 max_value: Precision::Exact(ScalarValue::Int32(Some(180))),
1646 min_value: Precision::Exact(ScalarValue::Int32(Some(5))),
1647 sum_value: Precision::Exact(ScalarValue::Int32(Some(1200))),
1648 distinct_count: Precision::Absent,
1649 byte_size: Precision::Exact(60),
1650 },
1651 ],
1652 };
1653
1654 let items = vec![stats1, stats2];
1655
1656 let summary_stats = Statistics::try_merge_iter(&items, &schema).unwrap();
1657
1658 assert_eq!(summary_stats.num_rows, Precision::Exact(25)); assert_eq!(summary_stats.total_byte_size, Precision::Exact(250)); let col1_stats = &summary_stats.column_statistics[0];
1664 assert_eq!(col1_stats.null_count, Precision::Exact(3)); assert_eq!(
1666 col1_stats.max_value,
1667 Precision::Exact(ScalarValue::Int32(Some(120)))
1668 );
1669 assert_eq!(
1670 col1_stats.min_value,
1671 Precision::Exact(ScalarValue::Int32(Some(-10)))
1672 );
1673 assert_eq!(
1674 col1_stats.sum_value,
1675 Precision::Exact(ScalarValue::Int64(Some(1100)))
1676 ); let col2_stats = &summary_stats.column_statistics[1];
1679 assert_eq!(col2_stats.null_count, Precision::Exact(5)); assert_eq!(
1681 col2_stats.max_value,
1682 Precision::Exact(ScalarValue::Int32(Some(200)))
1683 );
1684 assert_eq!(
1685 col2_stats.min_value,
1686 Precision::Exact(ScalarValue::Int32(Some(5)))
1687 );
1688 assert_eq!(
1689 col2_stats.sum_value,
1690 Precision::Exact(ScalarValue::Int64(Some(2200)))
1691 ); }
1693
1694 #[test]
1695 fn test_try_merge_mixed_precision() {
1696 let schema = Arc::new(Schema::new(vec![Field::new(
1698 "col1",
1699 DataType::Int32,
1700 false,
1701 )]));
1702
1703 let stats1 = Statistics {
1705 num_rows: Precision::Exact(10),
1706 total_byte_size: Precision::Inexact(100),
1707 column_statistics: vec![ColumnStatistics {
1708 null_count: Precision::Exact(1),
1709 max_value: Precision::Exact(ScalarValue::Int32(Some(100))),
1710 min_value: Precision::Inexact(ScalarValue::Int32(Some(1))),
1711 sum_value: Precision::Exact(ScalarValue::Int32(Some(500))),
1712 distinct_count: Precision::Absent,
1713 byte_size: Precision::Exact(40),
1714 }],
1715 };
1716
1717 let stats2 = Statistics {
1718 num_rows: Precision::Inexact(15),
1719 total_byte_size: Precision::Exact(150),
1720 column_statistics: vec![ColumnStatistics {
1721 null_count: Precision::Inexact(2),
1722 max_value: Precision::Inexact(ScalarValue::Int32(Some(120))),
1723 min_value: Precision::Exact(ScalarValue::Int32(Some(-10))),
1724 sum_value: Precision::Absent,
1725 distinct_count: Precision::Absent,
1726 byte_size: Precision::Inexact(60),
1727 }],
1728 };
1729
1730 let items = vec![stats1, stats2];
1731
1732 let summary_stats = Statistics::try_merge_iter(&items, &schema).unwrap();
1733
1734 assert_eq!(summary_stats.num_rows, Precision::Inexact(25));
1735 assert_eq!(summary_stats.total_byte_size, Precision::Inexact(250));
1736
1737 let col_stats = &summary_stats.column_statistics[0];
1738 assert_eq!(col_stats.null_count, Precision::Inexact(3));
1739 assert_eq!(
1740 col_stats.max_value,
1741 Precision::Inexact(ScalarValue::Int32(Some(120)))
1742 );
1743 assert_eq!(
1744 col_stats.min_value,
1745 Precision::Inexact(ScalarValue::Int32(Some(-10)))
1746 );
1747 assert_eq!(col_stats.sum_value, Precision::Absent);
1748 }
1749
1750 #[test]
1751 fn test_try_merge_empty() {
1752 let schema = Arc::new(Schema::new(vec![Field::new(
1753 "col1",
1754 DataType::Int32,
1755 false,
1756 )]));
1757
1758 let items: Vec<Statistics> = vec![];
1760
1761 let summary_stats = Statistics::try_merge_iter(&items, &schema).unwrap();
1762
1763 assert_eq!(summary_stats.num_rows, Precision::Absent);
1765 assert_eq!(summary_stats.total_byte_size, Precision::Absent);
1766 assert_eq!(summary_stats.column_statistics.len(), 1);
1767 assert_eq!(
1768 summary_stats.column_statistics[0].null_count,
1769 Precision::Absent
1770 );
1771 }
1772
1773 #[test]
1774 fn test_try_merge_mismatched_size() {
1775 let schema = Arc::new(Schema::new(vec![Field::new(
1777 "col1",
1778 DataType::Int32,
1779 false,
1780 )]));
1781
1782 let stats1 = Statistics::default();
1784
1785 let stats2 =
1786 Statistics::default().add_column_statistics(ColumnStatistics::new_unknown());
1787
1788 let items = vec![stats1, stats2];
1789
1790 let e = Statistics::try_merge_iter(&items, &schema).unwrap_err();
1791 assert_contains!(
1792 e.to_string(),
1793 "Error during planning: Cannot merge statistics with different number of columns: 0 vs 1"
1794 );
1795 }
1796
1797 #[test]
1798 fn test_try_merge_distinct_count_absent() {
1799 let stats1 = Statistics::default()
1801 .with_num_rows(Precision::Exact(10))
1802 .with_total_byte_size(Precision::Exact(100))
1803 .add_column_statistics(
1804 ColumnStatistics::new_unknown()
1805 .with_null_count(Precision::Exact(0))
1806 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(1))))
1807 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(10))))
1808 .with_distinct_count(Precision::Exact(5)),
1809 );
1810
1811 let stats2 = Statistics::default()
1812 .with_num_rows(Precision::Exact(15))
1813 .with_total_byte_size(Precision::Exact(150))
1814 .add_column_statistics(
1815 ColumnStatistics::new_unknown()
1816 .with_null_count(Precision::Exact(0))
1817 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(5))))
1818 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(20))))
1819 .with_distinct_count(Precision::Exact(7)),
1820 );
1821
1822 let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
1824 let merged_stats =
1825 Statistics::try_merge_iter([&stats1, &stats2], &schema).unwrap();
1826
1827 assert_eq!(merged_stats.num_rows, Precision::Exact(25));
1829 assert_eq!(merged_stats.total_byte_size, Precision::Exact(250));
1830
1831 let col_stats = &merged_stats.column_statistics[0];
1832 assert_eq!(col_stats.null_count, Precision::Exact(0));
1833 assert_eq!(
1834 col_stats.min_value,
1835 Precision::Exact(ScalarValue::Int32(Some(1)))
1836 );
1837 assert_eq!(
1838 col_stats.max_value,
1839 Precision::Exact(ScalarValue::Int32(Some(20)))
1840 );
1841 assert_eq!(col_stats.distinct_count, Precision::Inexact(10));
1846 }
1847
1848 #[test]
1849 fn test_try_merge_ndv_disjoint_ranges() {
1850 let stats1 = Statistics::default()
1851 .with_num_rows(Precision::Exact(10))
1852 .add_column_statistics(
1853 ColumnStatistics::new_unknown()
1854 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(0))))
1855 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(10))))
1856 .with_distinct_count(Precision::Exact(5)),
1857 );
1858 let stats2 = Statistics::default()
1859 .with_num_rows(Precision::Exact(10))
1860 .add_column_statistics(
1861 ColumnStatistics::new_unknown()
1862 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(20))))
1863 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(30))))
1864 .with_distinct_count(Precision::Exact(8)),
1865 );
1866
1867 let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
1868 let merged = Statistics::try_merge_iter([&stats1, &stats2], &schema).unwrap();
1869 assert_eq!(
1871 merged.column_statistics[0].distinct_count,
1872 Precision::Inexact(13)
1873 );
1874 }
1875
1876 #[test]
1877 fn test_try_merge_ndv_identical_ranges() {
1878 let stats1 = Statistics::default()
1879 .with_num_rows(Precision::Exact(100))
1880 .add_column_statistics(
1881 ColumnStatistics::new_unknown()
1882 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(0))))
1883 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(100))))
1884 .with_distinct_count(Precision::Exact(50)),
1885 );
1886 let stats2 = Statistics::default()
1887 .with_num_rows(Precision::Exact(100))
1888 .add_column_statistics(
1889 ColumnStatistics::new_unknown()
1890 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(0))))
1891 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(100))))
1892 .with_distinct_count(Precision::Exact(30)),
1893 );
1894
1895 let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
1896 let merged = Statistics::try_merge_iter([&stats1, &stats2], &schema).unwrap();
1897 assert_eq!(
1899 merged.column_statistics[0].distinct_count,
1900 Precision::Inexact(50)
1901 );
1902 }
1903
1904 #[test]
1905 fn test_try_merge_ndv_partial_overlap() {
1906 let stats1 = Statistics::default()
1907 .with_num_rows(Precision::Exact(100))
1908 .add_column_statistics(
1909 ColumnStatistics::new_unknown()
1910 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(0))))
1911 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(100))))
1912 .with_distinct_count(Precision::Exact(80)),
1913 );
1914 let stats2 = Statistics::default()
1915 .with_num_rows(Precision::Exact(100))
1916 .add_column_statistics(
1917 ColumnStatistics::new_unknown()
1918 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(50))))
1919 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(150))))
1920 .with_distinct_count(Precision::Exact(60)),
1921 );
1922
1923 let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
1924 let merged = Statistics::try_merge_iter([&stats1, &stats2], &schema).unwrap();
1925 assert_eq!(
1929 merged.column_statistics[0].distinct_count,
1930 Precision::Inexact(110)
1931 );
1932 }
1933
1934 #[test]
1935 fn test_try_merge_ndv_missing_min_max() {
1936 let stats1 = Statistics::default()
1937 .with_num_rows(Precision::Exact(10))
1938 .add_column_statistics(
1939 ColumnStatistics::new_unknown().with_distinct_count(Precision::Exact(5)),
1940 );
1941 let stats2 = Statistics::default()
1942 .with_num_rows(Precision::Exact(10))
1943 .add_column_statistics(
1944 ColumnStatistics::new_unknown().with_distinct_count(Precision::Exact(8)),
1945 );
1946
1947 let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
1948 let merged = Statistics::try_merge_iter([&stats1, &stats2], &schema).unwrap();
1949 assert_eq!(
1951 merged.column_statistics[0].distinct_count,
1952 Precision::Inexact(8)
1953 );
1954 }
1955
1956 #[test]
1957 fn test_try_merge_ndv_non_numeric_types() {
1958 let stats1 = Statistics::default()
1959 .with_num_rows(Precision::Exact(10))
1960 .add_column_statistics(
1961 ColumnStatistics::new_unknown()
1962 .with_min_value(Precision::Exact(ScalarValue::Utf8(Some(
1963 "aaa".to_string(),
1964 ))))
1965 .with_max_value(Precision::Exact(ScalarValue::Utf8(Some(
1966 "zzz".to_string(),
1967 ))))
1968 .with_distinct_count(Precision::Exact(5)),
1969 );
1970 let stats2 = Statistics::default()
1971 .with_num_rows(Precision::Exact(10))
1972 .add_column_statistics(
1973 ColumnStatistics::new_unknown()
1974 .with_min_value(Precision::Exact(ScalarValue::Utf8(Some(
1975 "bbb".to_string(),
1976 ))))
1977 .with_max_value(Precision::Exact(ScalarValue::Utf8(Some(
1978 "yyy".to_string(),
1979 ))))
1980 .with_distinct_count(Precision::Exact(8)),
1981 );
1982
1983 let schema = Schema::new(vec![Field::new("a", DataType::Utf8, true)]);
1984 let merged = Statistics::try_merge_iter([&stats1, &stats2], &schema).unwrap();
1985 assert_eq!(
1987 merged.column_statistics[0].distinct_count,
1988 Precision::Inexact(8)
1989 );
1990 }
1991
1992 #[test]
1993 fn test_try_merge_ndv_non_numeric_types_sum_fallback() {
1994 let stats1 = Statistics::default()
1995 .with_num_rows(Precision::Exact(10))
1996 .add_column_statistics(
1997 ColumnStatistics::new_unknown()
1998 .with_min_value(Precision::Exact(ScalarValue::Utf8(Some(
1999 "aaa".to_string(),
2000 ))))
2001 .with_max_value(Precision::Exact(ScalarValue::Utf8(Some(
2002 "zzz".to_string(),
2003 ))))
2004 .with_distinct_count(Precision::Exact(5)),
2005 );
2006 let stats2 = Statistics::default()
2007 .with_num_rows(Precision::Exact(10))
2008 .add_column_statistics(
2009 ColumnStatistics::new_unknown()
2010 .with_min_value(Precision::Exact(ScalarValue::Utf8(Some(
2011 "bbb".to_string(),
2012 ))))
2013 .with_max_value(Precision::Exact(ScalarValue::Utf8(Some(
2014 "yyy".to_string(),
2015 ))))
2016 .with_distinct_count(Precision::Exact(8)),
2017 );
2018
2019 let schema = Schema::new(vec![Field::new("a", DataType::Utf8, true)]);
2020 let merged = Statistics::try_merge_iter_with_ndv_fallback(
2021 [&stats1, &stats2],
2022 &schema,
2023 NdvFallback::Sum,
2024 )
2025 .unwrap();
2026
2027 assert_eq!(
2029 merged.column_statistics[0].distinct_count,
2030 Precision::Inexact(13)
2031 );
2032 }
2033
2034 #[test]
2035 fn test_try_merge_ndv_constant_columns() {
2036 let stats1 = Statistics::default()
2038 .with_num_rows(Precision::Exact(10))
2039 .add_column_statistics(
2040 ColumnStatistics::new_unknown()
2041 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(5))))
2042 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(5))))
2043 .with_distinct_count(Precision::Exact(1)),
2044 );
2045 let stats2 = Statistics::default()
2046 .with_num_rows(Precision::Exact(10))
2047 .add_column_statistics(
2048 ColumnStatistics::new_unknown()
2049 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(5))))
2050 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(5))))
2051 .with_distinct_count(Precision::Exact(1)),
2052 );
2053
2054 let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
2055 let merged = Statistics::try_merge_iter([&stats1, &stats2], &schema).unwrap();
2056 assert_eq!(
2057 merged.column_statistics[0].distinct_count,
2058 Precision::Inexact(1)
2059 );
2060
2061 let stats3 = Statistics::default()
2063 .with_num_rows(Precision::Exact(10))
2064 .add_column_statistics(
2065 ColumnStatistics::new_unknown()
2066 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(5))))
2067 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(5))))
2068 .with_distinct_count(Precision::Exact(1)),
2069 );
2070 let stats4 = Statistics::default()
2071 .with_num_rows(Precision::Exact(10))
2072 .add_column_statistics(
2073 ColumnStatistics::new_unknown()
2074 .with_min_value(Precision::Exact(ScalarValue::Int32(Some(10))))
2075 .with_max_value(Precision::Exact(ScalarValue::Int32(Some(10))))
2076 .with_distinct_count(Precision::Exact(1)),
2077 );
2078
2079 let merged = Statistics::try_merge_iter([&stats3, &stats4], &schema).unwrap();
2080 assert_eq!(
2081 merged.column_statistics[0].distinct_count,
2082 Precision::Inexact(2)
2083 );
2084 }
2085
2086 #[test]
2087 fn test_try_merge_ndv_original_union_edge_cases() {
2088 struct NdvTestCase {
2089 name: &'static str,
2090 left_ndv: Precision<usize>,
2091 left_min: Option<i64>,
2092 left_max: Option<i64>,
2093 right_ndv: Precision<usize>,
2094 right_min: Option<i64>,
2095 right_max: Option<i64>,
2096 expected: Precision<usize>,
2097 }
2098
2099 let cases = vec![
2100 NdvTestCase {
2101 name: "disjoint ranges",
2102 left_ndv: Precision::Exact(5),
2103 left_min: Some(0),
2104 left_max: Some(10),
2105 right_ndv: Precision::Exact(3),
2106 right_min: Some(20),
2107 right_max: Some(30),
2108 expected: Precision::Inexact(8),
2109 },
2110 NdvTestCase {
2111 name: "identical ranges",
2112 left_ndv: Precision::Exact(10),
2113 left_min: Some(0),
2114 left_max: Some(100),
2115 right_ndv: Precision::Exact(8),
2116 right_min: Some(0),
2117 right_max: Some(100),
2118 expected: Precision::Inexact(10),
2119 },
2120 NdvTestCase {
2121 name: "partial overlap",
2122 left_ndv: Precision::Exact(100),
2123 left_min: Some(0),
2124 left_max: Some(100),
2125 right_ndv: Precision::Exact(50),
2126 right_min: Some(50),
2127 right_max: Some(150),
2128 expected: Precision::Inexact(125),
2129 },
2130 NdvTestCase {
2131 name: "right contained in left",
2132 left_ndv: Precision::Exact(100),
2133 left_min: Some(0),
2134 left_max: Some(100),
2135 right_ndv: Precision::Exact(50),
2136 right_min: Some(25),
2137 right_max: Some(75),
2138 expected: Precision::Inexact(100),
2139 },
2140 NdvTestCase {
2141 name: "same constant value",
2142 left_ndv: Precision::Exact(1),
2143 left_min: Some(5),
2144 left_max: Some(5),
2145 right_ndv: Precision::Exact(1),
2146 right_min: Some(5),
2147 right_max: Some(5),
2148 expected: Precision::Inexact(1),
2149 },
2150 NdvTestCase {
2151 name: "different constant values",
2152 left_ndv: Precision::Exact(1),
2153 left_min: Some(5),
2154 left_max: Some(5),
2155 right_ndv: Precision::Exact(1),
2156 right_min: Some(10),
2157 right_max: Some(10),
2158 expected: Precision::Inexact(2),
2159 },
2160 NdvTestCase {
2161 name: "left constant within right range",
2162 left_ndv: Precision::Exact(1),
2163 left_min: Some(5),
2164 left_max: Some(5),
2165 right_ndv: Precision::Exact(10),
2166 right_min: Some(0),
2167 right_max: Some(10),
2168 expected: Precision::Inexact(10),
2169 },
2170 NdvTestCase {
2171 name: "left constant outside right range",
2172 left_ndv: Precision::Exact(1),
2173 left_min: Some(20),
2174 left_max: Some(20),
2175 right_ndv: Precision::Exact(10),
2176 right_min: Some(0),
2177 right_max: Some(10),
2178 expected: Precision::Inexact(11),
2179 },
2180 NdvTestCase {
2181 name: "right constant within left range",
2182 left_ndv: Precision::Exact(10),
2183 left_min: Some(0),
2184 left_max: Some(10),
2185 right_ndv: Precision::Exact(1),
2186 right_min: Some(5),
2187 right_max: Some(5),
2188 expected: Precision::Inexact(10),
2189 },
2190 NdvTestCase {
2191 name: "right constant outside left range",
2192 left_ndv: Precision::Exact(10),
2193 left_min: Some(0),
2194 left_max: Some(10),
2195 right_ndv: Precision::Exact(1),
2196 right_min: Some(20),
2197 right_max: Some(20),
2198 expected: Precision::Inexact(11),
2199 },
2200 NdvTestCase {
2201 name: "missing bounds exact plus exact",
2202 left_ndv: Precision::Exact(10),
2203 left_min: None,
2204 left_max: None,
2205 right_ndv: Precision::Exact(5),
2206 right_min: None,
2207 right_max: None,
2208 expected: Precision::Inexact(15),
2209 },
2210 NdvTestCase {
2211 name: "missing bounds exact plus inexact",
2212 left_ndv: Precision::Exact(10),
2213 left_min: None,
2214 left_max: None,
2215 right_ndv: Precision::Inexact(5),
2216 right_min: None,
2217 right_max: None,
2218 expected: Precision::Inexact(15),
2219 },
2220 NdvTestCase {
2221 name: "missing bounds inexact plus inexact",
2222 left_ndv: Precision::Inexact(7),
2223 left_min: None,
2224 left_max: None,
2225 right_ndv: Precision::Inexact(3),
2226 right_min: None,
2227 right_max: None,
2228 expected: Precision::Inexact(10),
2229 },
2230 NdvTestCase {
2231 name: "exact plus absent",
2232 left_ndv: Precision::Exact(10),
2233 left_min: None,
2234 left_max: None,
2235 right_ndv: Precision::Absent,
2236 right_min: None,
2237 right_max: None,
2238 expected: Precision::Absent,
2239 },
2240 NdvTestCase {
2241 name: "inexact plus absent",
2242 left_ndv: Precision::Inexact(4),
2243 left_min: None,
2244 left_max: None,
2245 right_ndv: Precision::Absent,
2246 right_min: None,
2247 right_max: None,
2248 expected: Precision::Absent,
2249 },
2250 ];
2251
2252 for case in cases {
2253 let actual = merge_single_i64_ndv_distinct_count(
2254 make_single_i64_ndv_stats(case.left_ndv, case.left_min, case.left_max),
2255 make_single_i64_ndv_stats(case.right_ndv, case.right_min, case.right_max),
2256 NdvFallback::Sum,
2257 );
2258
2259 assert_eq!(actual, case.expected, "case {} failed", case.name);
2260 }
2261 }
2262
2263 #[test]
2264 fn test_with_fetch_basic_preservation() {
2265 let original_stats = Statistics {
2267 num_rows: Precision::Exact(1000),
2268 total_byte_size: Precision::Exact(8000),
2269 column_statistics: vec![
2270 ColumnStatistics {
2271 null_count: Precision::Exact(10),
2272 max_value: Precision::Exact(ScalarValue::Int32(Some(100))),
2273 min_value: Precision::Exact(ScalarValue::Int32(Some(0))),
2274 sum_value: Precision::Exact(ScalarValue::Int32(Some(5050))),
2275 distinct_count: Precision::Exact(50),
2276 byte_size: Precision::Exact(4000),
2277 },
2278 ColumnStatistics {
2279 null_count: Precision::Exact(20),
2280 max_value: Precision::Exact(ScalarValue::Int64(Some(200))),
2281 min_value: Precision::Exact(ScalarValue::Int64(Some(10))),
2282 sum_value: Precision::Exact(ScalarValue::Int64(Some(10100))),
2283 distinct_count: Precision::Exact(75),
2284 byte_size: Precision::Exact(8000),
2285 },
2286 ],
2287 };
2288
2289 let result = original_stats.clone().with_fetch(Some(100), 0, 1).unwrap();
2291
2292 assert_eq!(result.num_rows, Precision::Exact(100));
2294
2295 assert_eq!(result.total_byte_size, Precision::Inexact(1200));
2298
2299 assert_eq!(result.column_statistics.len(), 2);
2301
2302 assert_eq!(
2304 result.column_statistics[0].null_count,
2305 Precision::Inexact(10)
2306 );
2307 assert_eq!(
2308 result.column_statistics[0].max_value,
2309 Precision::Inexact(ScalarValue::Int32(Some(100)))
2310 );
2311 assert_eq!(
2312 result.column_statistics[0].min_value,
2313 Precision::Inexact(ScalarValue::Int32(Some(0)))
2314 );
2315 assert_eq!(
2316 result.column_statistics[0].sum_value,
2317 Precision::Inexact(ScalarValue::Int32(Some(5050)))
2318 );
2319 assert_eq!(
2320 result.column_statistics[0].distinct_count,
2321 Precision::Inexact(50)
2322 );
2323
2324 assert_eq!(
2326 result.column_statistics[1].null_count,
2327 Precision::Inexact(20)
2328 );
2329 assert_eq!(
2330 result.column_statistics[1].max_value,
2331 Precision::Inexact(ScalarValue::Int64(Some(200)))
2332 );
2333 assert_eq!(
2334 result.column_statistics[1].min_value,
2335 Precision::Inexact(ScalarValue::Int64(Some(10)))
2336 );
2337 assert_eq!(
2338 result.column_statistics[1].sum_value,
2339 Precision::Inexact(ScalarValue::Int64(Some(10100)))
2340 );
2341 assert_eq!(
2342 result.column_statistics[1].distinct_count,
2343 Precision::Inexact(75)
2344 );
2345 }
2346
2347 #[test]
2348 fn test_with_fetch_inexact_input() {
2349 let original_stats = Statistics {
2351 num_rows: Precision::Inexact(1000),
2352 total_byte_size: Precision::Inexact(8000),
2353 column_statistics: vec![ColumnStatistics {
2354 null_count: Precision::Inexact(10),
2355 max_value: Precision::Inexact(ScalarValue::Int32(Some(100))),
2356 min_value: Precision::Inexact(ScalarValue::Int32(Some(0))),
2357 sum_value: Precision::Inexact(ScalarValue::Int32(Some(5050))),
2358 distinct_count: Precision::Inexact(50),
2359 byte_size: Precision::Inexact(4000),
2360 }],
2361 };
2362
2363 let result = original_stats.clone().with_fetch(Some(500), 0, 1).unwrap();
2364
2365 assert_eq!(result.num_rows, Precision::Inexact(500));
2367
2368 assert_eq!(result.total_byte_size, Precision::Inexact(2000));
2371
2372 assert_eq!(
2374 result.column_statistics[0].null_count,
2375 Precision::Inexact(10)
2376 );
2377 }
2378
2379 #[test]
2380 fn test_with_fetch_skip_all_rows() {
2381 let original_stats = Statistics {
2383 num_rows: Precision::Exact(100),
2384 total_byte_size: Precision::Exact(800),
2385 column_statistics: vec![col_stats_i64(10)],
2386 };
2387
2388 let result = original_stats.clone().with_fetch(Some(50), 100, 1).unwrap();
2389
2390 assert_eq!(result.num_rows, Precision::Exact(0));
2391 assert_eq!(result.total_byte_size, Precision::Inexact(0));
2393 }
2394
2395 #[test]
2396 fn test_with_fetch_skip_all_rows_inexact() {
2397 let original_stats = Statistics {
2401 num_rows: Precision::Inexact(0),
2402 total_byte_size: Precision::Inexact(0),
2403 column_statistics: vec![col_stats_i64(10)],
2404 };
2405
2406 let result = original_stats.clone().with_fetch(None, 0, 1).unwrap();
2407
2408 assert_eq!(result.num_rows, Precision::Inexact(0));
2409 }
2410
2411 #[test]
2412 fn test_with_fetch_no_limit() {
2413 let original_stats = Statistics {
2415 num_rows: Precision::Exact(100),
2416 total_byte_size: Precision::Exact(800),
2417 column_statistics: vec![col_stats_i64(10)],
2418 };
2419
2420 let result = original_stats.clone().with_fetch(None, 0, 1).unwrap();
2421
2422 assert_eq!(result.num_rows, Precision::Exact(100));
2424 assert_eq!(result.total_byte_size, Precision::Exact(800));
2425 }
2426
2427 #[test]
2428 fn test_with_fetch_no_limit_preserves_absent_num_rows() {
2429 let original_stats = Statistics {
2430 num_rows: Precision::Absent,
2431 total_byte_size: Precision::Exact(800),
2432 column_statistics: vec![col_stats_i64(10)],
2433 };
2434
2435 let result = original_stats.clone().with_fetch(None, 0, 1).unwrap();
2436
2437 assert_eq!(result, original_stats);
2438 }
2439
2440 #[test]
2441 fn test_with_fetch_absent_num_rows_does_not_zero_byte_size() {
2442 let original_stats = Statistics {
2443 num_rows: Precision::Absent,
2444 total_byte_size: Precision::Exact(800),
2445 column_statistics: vec![col_stats_i64(10)],
2446 };
2447
2448 let result = original_stats.with_fetch(Some(1), 0, 1).unwrap();
2449
2450 assert_eq!(result.num_rows, Precision::Inexact(1));
2451 assert_eq!(result.total_byte_size, Precision::Absent);
2452 assert_eq!(result.column_statistics[0].byte_size, Precision::Absent);
2453 assert_eq!(
2454 result.column_statistics[0].distinct_count,
2455 Precision::Inexact(1)
2456 );
2457 }
2458
2459 #[test]
2460 fn test_with_fetch_with_skip() {
2461 let original_stats = Statistics {
2463 num_rows: Precision::Exact(1000),
2464 total_byte_size: Precision::Exact(8000),
2465 column_statistics: vec![col_stats_i64(10)],
2466 };
2467
2468 let result = original_stats
2470 .clone()
2471 .with_fetch(Some(300), 200, 1)
2472 .unwrap();
2473
2474 assert_eq!(result.num_rows, Precision::Exact(300));
2475 assert_eq!(result.total_byte_size, Precision::Inexact(240));
2477 }
2478
2479 #[test]
2480 fn test_with_fetch_multi_partition() {
2481 let original_stats = Statistics {
2483 num_rows: Precision::Exact(1000), total_byte_size: Precision::Exact(8000),
2485 column_statistics: vec![col_stats_i64(10)],
2486 };
2487
2488 let result = original_stats.clone().with_fetch(Some(100), 0, 4).unwrap();
2490
2491 assert_eq!(result.num_rows, Precision::Exact(400));
2492 assert_eq!(result.total_byte_size, Precision::Inexact(320));
2494 }
2495
2496 #[test]
2497 fn test_with_fetch_absent_stats() {
2498 let original_stats = Statistics {
2500 num_rows: Precision::Absent,
2501 total_byte_size: Precision::Absent,
2502 column_statistics: vec![ColumnStatistics {
2503 null_count: Precision::Absent,
2504 max_value: Precision::Absent,
2505 min_value: Precision::Absent,
2506 sum_value: Precision::Absent,
2507 distinct_count: Precision::Absent,
2508 byte_size: Precision::Absent,
2509 }],
2510 };
2511
2512 let result = original_stats.clone().with_fetch(Some(100), 0, 1).unwrap();
2513
2514 assert_eq!(result.num_rows, Precision::Inexact(100));
2516 assert_eq!(result.total_byte_size, Precision::Absent);
2517 assert_eq!(result.column_statistics[0].null_count, Precision::Absent);
2519 }
2520
2521 #[test]
2522 fn test_with_fetch_fetch_exceeds_rows() {
2523 let original_stats = Statistics {
2525 num_rows: Precision::Exact(100),
2526 total_byte_size: Precision::Exact(800),
2527 column_statistics: vec![col_stats_i64(10)],
2528 };
2529
2530 let result = original_stats.clone().with_fetch(Some(100), 50, 1).unwrap();
2532
2533 assert_eq!(result.num_rows, Precision::Exact(50));
2534 assert_eq!(result.total_byte_size, Precision::Inexact(400));
2536 }
2537
2538 #[test]
2539 fn test_with_fetch_preserves_all_column_stats() {
2540 let original_col_stats = ColumnStatistics {
2542 null_count: Precision::Exact(42),
2543 max_value: Precision::Exact(ScalarValue::Int32(Some(999))),
2544 min_value: Precision::Exact(ScalarValue::Int32(Some(-100))),
2545 sum_value: Precision::Exact(ScalarValue::Int32(Some(123456))),
2546 distinct_count: Precision::Exact(789),
2547 byte_size: Precision::Exact(4000),
2548 };
2549
2550 let original_stats = Statistics {
2551 num_rows: Precision::Exact(1000),
2552 total_byte_size: Precision::Exact(8000),
2553 column_statistics: vec![original_col_stats.clone()],
2554 };
2555
2556 let result = original_stats.with_fetch(Some(250), 0, 1).unwrap();
2557
2558 let result_col_stats = &result.column_statistics[0];
2559
2560 assert_eq!(result_col_stats.null_count, Precision::Inexact(42));
2562 assert_eq!(
2563 result_col_stats.max_value,
2564 Precision::Inexact(ScalarValue::Int32(Some(999)))
2565 );
2566 assert_eq!(
2567 result_col_stats.min_value,
2568 Precision::Inexact(ScalarValue::Int32(Some(-100)))
2569 );
2570 assert_eq!(
2571 result_col_stats.sum_value,
2572 Precision::Inexact(ScalarValue::Int32(Some(123456)))
2573 );
2574 assert_eq!(result_col_stats.distinct_count, Precision::Inexact(250));
2576 }
2577
2578 #[test]
2579 fn test_byte_size_to_inexact() {
2580 let col_stats = ColumnStatistics {
2581 null_count: Precision::Exact(10),
2582 max_value: Precision::Absent,
2583 min_value: Precision::Absent,
2584 sum_value: Precision::Absent,
2585 distinct_count: Precision::Absent,
2586 byte_size: Precision::Exact(5000),
2587 };
2588
2589 let inexact = col_stats.to_inexact();
2590 assert_eq!(inexact.byte_size, Precision::Inexact(5000));
2591 }
2592
2593 #[test]
2594 fn test_with_byte_size_builder() {
2595 let col_stats =
2596 ColumnStatistics::new_unknown().with_byte_size(Precision::Exact(8192));
2597 assert_eq!(col_stats.byte_size, Precision::Exact(8192));
2598 }
2599
2600 #[test]
2601 fn test_with_sum_value_builder_widens_small_integers() {
2602 let col_stats = ColumnStatistics::new_unknown()
2603 .with_sum_value(Precision::Exact(ScalarValue::UInt32(Some(123))));
2604 assert_eq!(
2605 col_stats.sum_value,
2606 Precision::Exact(ScalarValue::UInt64(Some(123)))
2607 );
2608 }
2609
2610 #[test]
2611 fn test_with_fetch_scales_byte_size() {
2612 let original_stats = Statistics {
2614 num_rows: Precision::Exact(1000),
2615 total_byte_size: Precision::Exact(8000),
2616 column_statistics: vec![
2617 ColumnStatistics {
2618 null_count: Precision::Exact(10),
2619 max_value: Precision::Absent,
2620 min_value: Precision::Absent,
2621 sum_value: Precision::Absent,
2622 distinct_count: Precision::Absent,
2623 byte_size: Precision::Exact(4000),
2624 },
2625 ColumnStatistics {
2626 null_count: Precision::Exact(20),
2627 max_value: Precision::Absent,
2628 min_value: Precision::Absent,
2629 sum_value: Precision::Absent,
2630 distinct_count: Precision::Absent,
2631 byte_size: Precision::Exact(8000),
2632 },
2633 ],
2634 };
2635
2636 let result = original_stats.with_fetch(Some(100), 0, 1).unwrap();
2638
2639 assert_eq!(
2641 result.column_statistics[0].byte_size,
2642 Precision::Inexact(400)
2643 );
2644 assert_eq!(
2645 result.column_statistics[1].byte_size,
2646 Precision::Inexact(800)
2647 );
2648
2649 assert_eq!(result.total_byte_size, Precision::Inexact(1200));
2651 }
2652
2653 #[test]
2654 fn test_with_fetch_total_byte_size_fallback() {
2655 let original_stats = Statistics {
2657 num_rows: Precision::Exact(1000),
2658 total_byte_size: Precision::Exact(8000),
2659 column_statistics: vec![
2660 ColumnStatistics {
2661 null_count: Precision::Exact(10),
2662 max_value: Precision::Absent,
2663 min_value: Precision::Absent,
2664 sum_value: Precision::Absent,
2665 distinct_count: Precision::Absent,
2666 byte_size: Precision::Exact(4000),
2667 },
2668 ColumnStatistics {
2669 null_count: Precision::Exact(20),
2670 max_value: Precision::Absent,
2671 min_value: Precision::Absent,
2672 sum_value: Precision::Absent,
2673 distinct_count: Precision::Absent,
2674 byte_size: Precision::Absent, },
2676 ],
2677 };
2678
2679 let result = original_stats.with_fetch(Some(100), 0, 1).unwrap();
2681
2682 assert_eq!(result.total_byte_size, Precision::Inexact(800));
2684 }
2685
2686 #[test]
2687 fn test_with_fetch_caps_ndv_at_row_count() {
2688 let stats = Statistics {
2690 num_rows: Precision::Exact(1000),
2691 total_byte_size: Precision::Exact(8000),
2692 column_statistics: vec![ColumnStatistics {
2693 distinct_count: Precision::Inexact(500),
2694 ..Default::default()
2695 }],
2696 };
2697
2698 let result = stats.with_fetch(Some(10), 0, 1).unwrap();
2699 assert_eq!(result.num_rows, Precision::Exact(10));
2700 assert_eq!(
2701 result.column_statistics[0].distinct_count,
2702 Precision::Inexact(10)
2703 );
2704 }
2705
2706 #[test]
2707 fn test_with_fetch_caps_ndv_with_skip() {
2708 let stats = Statistics {
2712 num_rows: Precision::Exact(1000),
2713 total_byte_size: Precision::Exact(8000),
2714 column_statistics: vec![ColumnStatistics {
2715 distinct_count: Precision::Inexact(500),
2716 ..Default::default()
2717 }],
2718 };
2719
2720 let result = stats.with_fetch(Some(10), 5, 1).unwrap();
2721 assert_eq!(result.num_rows, Precision::Exact(10));
2722 assert_eq!(
2723 result.column_statistics[0].distinct_count,
2724 Precision::Inexact(10)
2725 );
2726 }
2727
2728 #[test]
2729 fn test_with_fetch_caps_ndv_with_large_skip() {
2730 let stats = Statistics {
2734 num_rows: Precision::Exact(1000),
2735 total_byte_size: Precision::Exact(8000),
2736 column_statistics: vec![ColumnStatistics {
2737 distinct_count: Precision::Inexact(500),
2738 ..Default::default()
2739 }],
2740 };
2741
2742 let result = stats.with_fetch(Some(100), 995, 1).unwrap();
2743 assert_eq!(result.num_rows, Precision::Exact(5));
2744 assert_eq!(
2745 result.column_statistics[0].distinct_count,
2746 Precision::Inexact(5)
2747 );
2748 }
2749
2750 #[test]
2751 fn test_with_fetch_ndv_below_row_count_unchanged() {
2752 let stats = Statistics {
2754 num_rows: Precision::Exact(1000),
2755 total_byte_size: Precision::Exact(8000),
2756 column_statistics: vec![ColumnStatistics {
2757 distinct_count: Precision::Inexact(5),
2758 ..Default::default()
2759 }],
2760 };
2761
2762 let result = stats.with_fetch(Some(10), 0, 1).unwrap();
2763 assert_eq!(result.num_rows, Precision::Exact(10));
2764 assert_eq!(
2765 result.column_statistics[0].distinct_count,
2766 Precision::Inexact(5)
2767 );
2768 }
2769
2770 #[test]
2771 fn test_try_merge_iter_basic() {
2772 let schema = Arc::new(Schema::new(vec![
2773 Field::new("col1", DataType::Int32, false),
2774 Field::new("col2", DataType::Int32, false),
2775 ]));
2776
2777 let stats1 = Statistics {
2778 num_rows: Precision::Exact(10),
2779 total_byte_size: Precision::Exact(100),
2780 column_statistics: vec![
2781 ColumnStatistics {
2782 null_count: Precision::Exact(1),
2783 max_value: Precision::Exact(ScalarValue::Int32(Some(100))),
2784 min_value: Precision::Exact(ScalarValue::Int32(Some(1))),
2785 sum_value: Precision::Exact(ScalarValue::Int32(Some(500))),
2786 distinct_count: Precision::Absent,
2787 byte_size: Precision::Exact(40),
2788 },
2789 ColumnStatistics {
2790 null_count: Precision::Exact(2),
2791 max_value: Precision::Exact(ScalarValue::Int32(Some(200))),
2792 min_value: Precision::Exact(ScalarValue::Int32(Some(10))),
2793 sum_value: Precision::Exact(ScalarValue::Int32(Some(1000))),
2794 distinct_count: Precision::Absent,
2795 byte_size: Precision::Exact(40),
2796 },
2797 ],
2798 };
2799
2800 let stats2 = Statistics {
2801 num_rows: Precision::Exact(15),
2802 total_byte_size: Precision::Exact(150),
2803 column_statistics: vec![
2804 ColumnStatistics {
2805 null_count: Precision::Exact(2),
2806 max_value: Precision::Exact(ScalarValue::Int32(Some(120))),
2807 min_value: Precision::Exact(ScalarValue::Int32(Some(-10))),
2808 sum_value: Precision::Exact(ScalarValue::Int32(Some(600))),
2809 distinct_count: Precision::Absent,
2810 byte_size: Precision::Exact(60),
2811 },
2812 ColumnStatistics {
2813 null_count: Precision::Exact(3),
2814 max_value: Precision::Exact(ScalarValue::Int32(Some(180))),
2815 min_value: Precision::Exact(ScalarValue::Int32(Some(5))),
2816 sum_value: Precision::Exact(ScalarValue::Int32(Some(1200))),
2817 distinct_count: Precision::Absent,
2818 byte_size: Precision::Exact(60),
2819 },
2820 ],
2821 };
2822
2823 let items = vec![&stats1, &stats2];
2824 let summary_stats = Statistics::try_merge_iter(items, &schema).unwrap();
2825
2826 assert_eq!(summary_stats.num_rows, Precision::Exact(25));
2827 assert_eq!(summary_stats.total_byte_size, Precision::Exact(250));
2828
2829 let col1_stats = &summary_stats.column_statistics[0];
2830 assert_eq!(col1_stats.null_count, Precision::Exact(3));
2831 assert_eq!(
2832 col1_stats.max_value,
2833 Precision::Exact(ScalarValue::Int32(Some(120)))
2834 );
2835 assert_eq!(
2836 col1_stats.min_value,
2837 Precision::Exact(ScalarValue::Int32(Some(-10)))
2838 );
2839 assert_eq!(
2840 col1_stats.sum_value,
2841 Precision::Exact(ScalarValue::Int64(Some(1100)))
2842 );
2843
2844 let col2_stats = &summary_stats.column_statistics[1];
2845 assert_eq!(col2_stats.null_count, Precision::Exact(5));
2846 assert_eq!(
2847 col2_stats.max_value,
2848 Precision::Exact(ScalarValue::Int32(Some(200)))
2849 );
2850 assert_eq!(
2851 col2_stats.min_value,
2852 Precision::Exact(ScalarValue::Int32(Some(5)))
2853 );
2854 assert_eq!(
2855 col2_stats.sum_value,
2856 Precision::Exact(ScalarValue::Int64(Some(2200)))
2857 );
2858 }
2859
2860 #[test]
2861 fn test_try_merge_iter_mixed_precision() {
2862 let schema = Arc::new(Schema::new(vec![Field::new(
2863 "col1",
2864 DataType::Int32,
2865 false,
2866 )]));
2867
2868 let stats1 = Statistics {
2869 num_rows: Precision::Exact(10),
2870 total_byte_size: Precision::Inexact(100),
2871 column_statistics: vec![ColumnStatistics {
2872 null_count: Precision::Exact(1),
2873 max_value: Precision::Exact(ScalarValue::Int32(Some(100))),
2874 min_value: Precision::Inexact(ScalarValue::Int32(Some(1))),
2875 sum_value: Precision::Exact(ScalarValue::Int32(Some(500))),
2876 distinct_count: Precision::Absent,
2877 byte_size: Precision::Exact(40),
2878 }],
2879 };
2880
2881 let stats2 = Statistics {
2882 num_rows: Precision::Inexact(15),
2883 total_byte_size: Precision::Exact(150),
2884 column_statistics: vec![ColumnStatistics {
2885 null_count: Precision::Inexact(2),
2886 max_value: Precision::Inexact(ScalarValue::Int32(Some(120))),
2887 min_value: Precision::Exact(ScalarValue::Int32(Some(-10))),
2888 sum_value: Precision::Absent,
2889 distinct_count: Precision::Absent,
2890 byte_size: Precision::Inexact(60),
2891 }],
2892 };
2893
2894 let items = vec![&stats1, &stats2];
2895 let summary_stats = Statistics::try_merge_iter(items, &schema).unwrap();
2896
2897 assert_eq!(summary_stats.num_rows, Precision::Inexact(25));
2898 assert_eq!(summary_stats.total_byte_size, Precision::Inexact(250));
2899
2900 let col_stats = &summary_stats.column_statistics[0];
2901 assert_eq!(col_stats.null_count, Precision::Inexact(3));
2902 assert_eq!(
2903 col_stats.max_value,
2904 Precision::Inexact(ScalarValue::Int32(Some(120)))
2905 );
2906 assert_eq!(
2907 col_stats.min_value,
2908 Precision::Inexact(ScalarValue::Int32(Some(-10)))
2909 );
2910 assert_eq!(col_stats.sum_value, Precision::Absent);
2912 }
2913
2914 #[test]
2915 fn test_try_merge_iter_empty() {
2916 let schema = Arc::new(Schema::new(vec![Field::new(
2917 "col1",
2918 DataType::Int32,
2919 false,
2920 )]));
2921
2922 let items: Vec<&Statistics> = vec![];
2923 let summary_stats = Statistics::try_merge_iter(items, &schema).unwrap();
2924
2925 assert_eq!(summary_stats.num_rows, Precision::Absent);
2926 assert_eq!(summary_stats.total_byte_size, Precision::Absent);
2927 assert_eq!(summary_stats.column_statistics.len(), 1);
2928 assert_eq!(
2929 summary_stats.column_statistics[0].null_count,
2930 Precision::Absent
2931 );
2932 }
2933
2934 #[test]
2935 fn test_try_merge_iter_single_item() {
2936 let schema = Arc::new(Schema::new(vec![Field::new(
2937 "col1",
2938 DataType::Int32,
2939 false,
2940 )]));
2941
2942 let stats = Statistics {
2943 num_rows: Precision::Exact(10),
2944 total_byte_size: Precision::Exact(100),
2945 column_statistics: vec![ColumnStatistics {
2946 null_count: Precision::Exact(1),
2947 max_value: Precision::Exact(ScalarValue::Int32(Some(100))),
2948 min_value: Precision::Exact(ScalarValue::Int32(Some(1))),
2949 sum_value: Precision::Exact(ScalarValue::Int32(Some(500))),
2950 distinct_count: Precision::Exact(10),
2951 byte_size: Precision::Exact(40),
2952 }],
2953 };
2954
2955 let items = vec![&stats];
2956 let summary_stats = Statistics::try_merge_iter(items, &schema).unwrap();
2957
2958 assert_eq!(summary_stats, stats);
2959 }
2960
2961 #[test]
2962 fn test_try_merge_iter_mismatched_columns() {
2963 let schema = Arc::new(Schema::new(vec![Field::new(
2964 "col1",
2965 DataType::Int32,
2966 false,
2967 )]));
2968
2969 let stats1 = Statistics::default();
2970 let stats2 =
2971 Statistics::default().add_column_statistics(ColumnStatistics::new_unknown());
2972
2973 let items = vec![&stats1, &stats2];
2974 let e = Statistics::try_merge_iter(items, &schema).unwrap_err();
2975 assert_contains!(
2976 e.to_string(),
2977 "Cannot merge statistics with different number of columns: 0 vs 1"
2978 );
2979 }
2980
2981 #[test]
2982 fn test_try_merge_iter_three_items() {
2983 let schema = Arc::new(Schema::new(vec![Field::new(
2985 "col1",
2986 DataType::Int64,
2987 false,
2988 )]));
2989
2990 let stats1 = Statistics {
2991 num_rows: Precision::Exact(10),
2992 total_byte_size: Precision::Exact(100),
2993 column_statistics: vec![ColumnStatistics {
2994 null_count: Precision::Exact(1),
2995 max_value: Precision::Exact(ScalarValue::Int64(Some(100))),
2996 min_value: Precision::Exact(ScalarValue::Int64(Some(10))),
2997 sum_value: Precision::Exact(ScalarValue::Int64(Some(500))),
2998 distinct_count: Precision::Exact(8),
2999 byte_size: Precision::Exact(80),
3000 }],
3001 };
3002
3003 let stats2 = Statistics {
3004 num_rows: Precision::Exact(20),
3005 total_byte_size: Precision::Exact(200),
3006 column_statistics: vec![ColumnStatistics {
3007 null_count: Precision::Exact(2),
3008 max_value: Precision::Exact(ScalarValue::Int64(Some(200))),
3009 min_value: Precision::Exact(ScalarValue::Int64(Some(5))),
3010 sum_value: Precision::Exact(ScalarValue::Int64(Some(1000))),
3011 distinct_count: Precision::Exact(15),
3012 byte_size: Precision::Exact(160),
3013 }],
3014 };
3015
3016 let stats3 = Statistics {
3017 num_rows: Precision::Exact(30),
3018 total_byte_size: Precision::Exact(300),
3019 column_statistics: vec![ColumnStatistics {
3020 null_count: Precision::Exact(3),
3021 max_value: Precision::Exact(ScalarValue::Int64(Some(150))),
3022 min_value: Precision::Exact(ScalarValue::Int64(Some(1))),
3023 sum_value: Precision::Exact(ScalarValue::Int64(Some(2000))),
3024 distinct_count: Precision::Exact(25),
3025 byte_size: Precision::Exact(240),
3026 }],
3027 };
3028
3029 let items = vec![&stats1, &stats2, &stats3];
3030 let summary_stats = Statistics::try_merge_iter(items, &schema).unwrap();
3031
3032 assert_eq!(summary_stats.num_rows, Precision::Exact(60));
3033 assert_eq!(summary_stats.total_byte_size, Precision::Exact(600));
3034
3035 let col_stats = &summary_stats.column_statistics[0];
3036 assert_eq!(col_stats.null_count, Precision::Exact(6));
3037 assert_eq!(
3038 col_stats.max_value,
3039 Precision::Exact(ScalarValue::Int64(Some(200)))
3040 );
3041 assert_eq!(
3042 col_stats.min_value,
3043 Precision::Exact(ScalarValue::Int64(Some(1)))
3044 );
3045 assert_eq!(
3046 col_stats.sum_value,
3047 Precision::Exact(ScalarValue::Int64(Some(3500)))
3048 );
3049 assert_eq!(col_stats.byte_size, Precision::Exact(480));
3050 assert_eq!(col_stats.distinct_count, Precision::Inexact(29));
3053 }
3054
3055 #[test]
3056 fn test_try_merge_iter_float_types() {
3057 let schema = Arc::new(Schema::new(vec![Field::new(
3058 "col1",
3059 DataType::Float64,
3060 false,
3061 )]));
3062
3063 let stats1 = Statistics {
3064 num_rows: Precision::Exact(10),
3065 total_byte_size: Precision::Exact(80),
3066 column_statistics: vec![ColumnStatistics {
3067 null_count: Precision::Exact(0),
3068 max_value: Precision::Exact(ScalarValue::Float64(Some(99.9))),
3069 min_value: Precision::Exact(ScalarValue::Float64(Some(1.1))),
3070 sum_value: Precision::Exact(ScalarValue::Float64(Some(500.5))),
3071 distinct_count: Precision::Absent,
3072 byte_size: Precision::Exact(80),
3073 }],
3074 };
3075
3076 let stats2 = Statistics {
3077 num_rows: Precision::Exact(10),
3078 total_byte_size: Precision::Exact(80),
3079 column_statistics: vec![ColumnStatistics {
3080 null_count: Precision::Exact(0),
3081 max_value: Precision::Exact(ScalarValue::Float64(Some(200.0))),
3082 min_value: Precision::Exact(ScalarValue::Float64(Some(0.5))),
3083 sum_value: Precision::Exact(ScalarValue::Float64(Some(1000.0))),
3084 distinct_count: Precision::Absent,
3085 byte_size: Precision::Exact(80),
3086 }],
3087 };
3088
3089 let items = vec![&stats1, &stats2];
3090 let summary_stats = Statistics::try_merge_iter(items, &schema).unwrap();
3091
3092 let col_stats = &summary_stats.column_statistics[0];
3093 assert_eq!(
3094 col_stats.max_value,
3095 Precision::Exact(ScalarValue::Float64(Some(200.0)))
3096 );
3097 assert_eq!(
3098 col_stats.min_value,
3099 Precision::Exact(ScalarValue::Float64(Some(0.5)))
3100 );
3101 assert_eq!(
3102 col_stats.sum_value,
3103 Precision::Exact(ScalarValue::Float64(Some(1500.5)))
3104 );
3105 }
3106
3107 #[test]
3108 fn test_try_merge_iter_string_types() {
3109 let schema =
3110 Arc::new(Schema::new(vec![Field::new("col1", DataType::Utf8, false)]));
3111
3112 let stats1 = Statistics {
3113 num_rows: Precision::Exact(10),
3114 total_byte_size: Precision::Exact(100),
3115 column_statistics: vec![ColumnStatistics {
3116 null_count: Precision::Exact(0),
3117 max_value: Precision::Exact(ScalarValue::Utf8(Some("dog".to_string()))),
3118 min_value: Precision::Exact(ScalarValue::Utf8(Some("ant".to_string()))),
3119 sum_value: Precision::Absent,
3120 distinct_count: Precision::Absent,
3121 byte_size: Precision::Exact(100),
3122 }],
3123 };
3124
3125 let stats2 = Statistics {
3126 num_rows: Precision::Exact(10),
3127 total_byte_size: Precision::Exact(100),
3128 column_statistics: vec![ColumnStatistics {
3129 null_count: Precision::Exact(0),
3130 max_value: Precision::Exact(ScalarValue::Utf8(Some("zebra".to_string()))),
3131 min_value: Precision::Exact(ScalarValue::Utf8(Some("bat".to_string()))),
3132 sum_value: Precision::Absent,
3133 distinct_count: Precision::Absent,
3134 byte_size: Precision::Exact(100),
3135 }],
3136 };
3137
3138 let items = vec![&stats1, &stats2];
3139 let summary_stats = Statistics::try_merge_iter(items, &schema).unwrap();
3140
3141 let col_stats = &summary_stats.column_statistics[0];
3142 assert_eq!(
3143 col_stats.max_value,
3144 Precision::Exact(ScalarValue::Utf8(Some("zebra".to_string())))
3145 );
3146 assert_eq!(
3147 col_stats.min_value,
3148 Precision::Exact(ScalarValue::Utf8(Some("ant".to_string())))
3149 );
3150 assert_eq!(col_stats.sum_value, Precision::Absent);
3151 }
3152
3153 #[test]
3154 fn test_try_merge_iter_all_inexact() {
3155 let schema = Arc::new(Schema::new(vec![Field::new(
3156 "col1",
3157 DataType::Int32,
3158 false,
3159 )]));
3160
3161 let stats1 = Statistics {
3162 num_rows: Precision::Inexact(10),
3163 total_byte_size: Precision::Inexact(100),
3164 column_statistics: vec![ColumnStatistics {
3165 null_count: Precision::Inexact(1),
3166 max_value: Precision::Inexact(ScalarValue::Int32(Some(100))),
3167 min_value: Precision::Inexact(ScalarValue::Int32(Some(1))),
3168 sum_value: Precision::Inexact(ScalarValue::Int32(Some(500))),
3169 distinct_count: Precision::Absent,
3170 byte_size: Precision::Inexact(40),
3171 }],
3172 };
3173
3174 let stats2 = Statistics {
3175 num_rows: Precision::Inexact(20),
3176 total_byte_size: Precision::Inexact(200),
3177 column_statistics: vec![ColumnStatistics {
3178 null_count: Precision::Inexact(2),
3179 max_value: Precision::Inexact(ScalarValue::Int32(Some(200))),
3180 min_value: Precision::Inexact(ScalarValue::Int32(Some(-5))),
3181 sum_value: Precision::Inexact(ScalarValue::Int32(Some(1000))),
3182 distinct_count: Precision::Absent,
3183 byte_size: Precision::Inexact(60),
3184 }],
3185 };
3186
3187 let items = vec![&stats1, &stats2];
3188 let summary_stats = Statistics::try_merge_iter(items, &schema).unwrap();
3189
3190 assert_eq!(summary_stats.num_rows, Precision::Inexact(30));
3191 assert_eq!(summary_stats.total_byte_size, Precision::Inexact(300));
3192
3193 let col_stats = &summary_stats.column_statistics[0];
3194 assert_eq!(col_stats.null_count, Precision::Inexact(3));
3195 assert_eq!(
3196 col_stats.max_value,
3197 Precision::Inexact(ScalarValue::Int32(Some(200)))
3198 );
3199 assert_eq!(
3200 col_stats.min_value,
3201 Precision::Inexact(ScalarValue::Int32(Some(-5)))
3202 );
3203 assert_eq!(
3204 col_stats.sum_value,
3205 Precision::Inexact(ScalarValue::Int64(Some(1500)))
3206 );
3207 }
3208
3209 #[test]
3210 fn test_precision_min_in_place() {
3211 let mut lhs = Precision::Exact(10);
3213 precision_min(&mut lhs, &Precision::Exact(20));
3214 assert_eq!(lhs, Precision::Exact(10));
3215
3216 let mut lhs = Precision::Exact(20);
3217 precision_min(&mut lhs, &Precision::Exact(10));
3218 assert_eq!(lhs, Precision::Exact(10));
3219
3220 let mut lhs = Precision::Exact(5);
3222 precision_min(&mut lhs, &Precision::Exact(5));
3223 assert_eq!(lhs, Precision::Exact(5));
3224
3225 let mut lhs = Precision::Exact(10);
3227 precision_min(&mut lhs, &Precision::Inexact(20));
3228 assert_eq!(lhs, Precision::Inexact(10));
3229
3230 let mut lhs = Precision::Inexact(10);
3231 precision_min(&mut lhs, &Precision::Exact(5));
3232 assert_eq!(lhs, Precision::Inexact(5));
3233
3234 let mut lhs = Precision::Inexact(30);
3236 precision_min(&mut lhs, &Precision::Inexact(20));
3237 assert_eq!(lhs, Precision::Inexact(20));
3238
3239 let mut lhs = Precision::Exact(10);
3241 precision_min(&mut lhs, &Precision::Absent);
3242 assert_eq!(lhs, Precision::Absent);
3243
3244 let mut lhs = Precision::<i32>::Absent;
3245 precision_min(&mut lhs, &Precision::Exact(10));
3246 assert_eq!(lhs, Precision::Absent);
3247 }
3248
3249 #[test]
3250 fn test_precision_max_in_place() {
3251 let mut lhs = Precision::Exact(10);
3253 precision_max(&mut lhs, &Precision::Exact(20));
3254 assert_eq!(lhs, Precision::Exact(20));
3255
3256 let mut lhs = Precision::Exact(20);
3257 precision_max(&mut lhs, &Precision::Exact(10));
3258 assert_eq!(lhs, Precision::Exact(20));
3259
3260 let mut lhs = Precision::Exact(5);
3262 precision_max(&mut lhs, &Precision::Exact(5));
3263 assert_eq!(lhs, Precision::Exact(5));
3264
3265 let mut lhs = Precision::Exact(10);
3267 precision_max(&mut lhs, &Precision::Inexact(20));
3268 assert_eq!(lhs, Precision::Inexact(20));
3269
3270 let mut lhs = Precision::Inexact(10);
3271 precision_max(&mut lhs, &Precision::Exact(5));
3272 assert_eq!(lhs, Precision::Inexact(10));
3273
3274 let mut lhs = Precision::Inexact(20);
3276 precision_max(&mut lhs, &Precision::Inexact(30));
3277 assert_eq!(lhs, Precision::Inexact(30));
3278
3279 let mut lhs = Precision::Exact(10);
3281 precision_max(&mut lhs, &Precision::Absent);
3282 assert_eq!(lhs, Precision::Absent);
3283
3284 let mut lhs = Precision::<i32>::Absent;
3285 precision_max(&mut lhs, &Precision::Exact(10));
3286 assert_eq!(lhs, Precision::Absent);
3287 }
3288
3289 #[test]
3290 fn test_cast_sum_value_to_sum_type_in_place_widens_int32() {
3291 let mut value = Precision::Exact(ScalarValue::Int32(Some(42)));
3292 cast_sum_value_to_sum_type_in_place(&mut value);
3293 assert_eq!(value, Precision::Exact(ScalarValue::Int64(Some(42))));
3294 }
3295
3296 #[test]
3297 fn test_cast_sum_value_to_sum_type_in_place_preserves_int64() {
3298 let mut value = Precision::Exact(ScalarValue::Int64(Some(100)));
3300 cast_sum_value_to_sum_type_in_place(&mut value);
3301 assert_eq!(value, Precision::Exact(ScalarValue::Int64(Some(100))));
3302 }
3303
3304 #[test]
3305 fn test_cast_sum_value_to_sum_type_in_place_inexact() {
3306 let mut value = Precision::Inexact(ScalarValue::Int32(Some(42)));
3307 cast_sum_value_to_sum_type_in_place(&mut value);
3308 assert_eq!(value, Precision::Inexact(ScalarValue::Int64(Some(42))));
3309 }
3310
3311 #[test]
3312 fn test_cast_sum_value_to_sum_type_in_place_absent() {
3313 let mut value = Precision::<ScalarValue>::Absent;
3314 cast_sum_value_to_sum_type_in_place(&mut value);
3315 assert_eq!(value, Precision::Absent);
3316 }
3317
3318 #[test]
3319 fn test_precision_add_for_sum_in_place_same_type() {
3320 let mut lhs = Precision::Exact(ScalarValue::Int64(Some(10)));
3322 let rhs = Precision::Exact(ScalarValue::Int64(Some(20)));
3323 precision_add_for_sum_in_place(&mut lhs, &rhs);
3324 assert_eq!(lhs, Precision::Exact(ScalarValue::Int64(Some(30))));
3325 }
3326
3327 #[test]
3328 fn test_precision_add_for_sum_in_place_widens_rhs() {
3329 let mut lhs = Precision::Exact(ScalarValue::Int64(Some(10)));
3331 let rhs = Precision::Exact(ScalarValue::Int32(Some(5)));
3332 precision_add_for_sum_in_place(&mut lhs, &rhs);
3333 assert_eq!(lhs, Precision::Exact(ScalarValue::Int64(Some(15))));
3334 }
3335
3336 #[test]
3337 fn test_precision_add_for_sum_in_place_inexact() {
3338 let mut lhs = Precision::Inexact(ScalarValue::Int64(Some(10)));
3339 let rhs = Precision::Inexact(ScalarValue::Int32(Some(5)));
3340 precision_add_for_sum_in_place(&mut lhs, &rhs);
3341 assert_eq!(lhs, Precision::Inexact(ScalarValue::Int64(Some(15))));
3342 }
3343
3344 #[test]
3345 fn test_precision_add_for_sum_in_place_absent_rhs() {
3346 let mut lhs = Precision::Exact(ScalarValue::Int64(Some(10)));
3347 precision_add_for_sum_in_place(&mut lhs, &Precision::Absent);
3348 assert_eq!(lhs, Precision::Absent);
3349 }
3350
3351 #[test]
3352 fn test_calculate_total_byte_size() {
3353 let primitive_schema = Schema::new(vec![Field::new("a", DataType::Int32, false)]);
3354 let non_primitive_schema =
3355 Schema::new(vec![Field::new("a", DataType::Utf8, false)]);
3356
3357 let mut stats = Statistics::new_unknown(&primitive_schema);
3359 stats.num_rows = Precision::Exact(10);
3360 stats.calculate_total_byte_size(&primitive_schema);
3361 assert_eq!(stats.total_byte_size, Precision::Exact(40));
3362
3363 let mut stats = Statistics::new_unknown(&primitive_schema);
3367 stats.total_byte_size = Precision::Exact(1234);
3368 stats.calculate_total_byte_size(&primitive_schema);
3369 assert_eq!(stats.total_byte_size, Precision::Inexact(1234));
3370
3371 let mut stats = Statistics::new_unknown(&non_primitive_schema);
3374 stats.num_rows = Precision::Exact(10);
3375 stats.total_byte_size = Precision::Exact(999);
3376 stats.calculate_total_byte_size(&non_primitive_schema);
3377 assert_eq!(stats.total_byte_size, Precision::Inexact(999));
3378 }
3379}