1use std::cmp::Ordering;
2use std::collections::{HashMap, HashSet};
3use std::sync::Arc;
4use std::sync::atomic::{AtomicU64, AtomicUsize};
5
6use crate::catalog::ColumnMetadata;
7use crate::executor::evaluator::EvalContext;
8use crate::executor::memory::{MemoryPolicy, MemoryTracker, map_core_memory_error};
9use crate::executor::{EvaluationError, ExecutorError, Result};
10use crate::planner::aggregate_expr::{AggregateExpr, AggregateFunction};
11use crate::planner::typed_expr::TypedExpr;
12use crate::planner::types::ResolvedType;
13use crate::storage::SqlValue;
14use alopex_core::sql::stream::ByteSized;
15
16use super::{Row, RowIterator, iterator::VecIterator};
17
18pub type GroupKeyBytes = Vec<u8>;
20
21fn encode_group_value(value: &SqlValue, buf: &mut Vec<u8>) -> Result<()> {
22 buf.push(value.type_tag());
23 match value {
24 SqlValue::Null => Ok(()),
25 SqlValue::Integer(v) => {
26 buf.extend_from_slice(&v.to_le_bytes());
27 Ok(())
28 }
29 SqlValue::BigInt(v) => {
30 buf.extend_from_slice(&v.to_le_bytes());
31 Ok(())
32 }
33 SqlValue::Float(v) => {
34 buf.extend_from_slice(&v.to_bits().to_le_bytes());
35 Ok(())
36 }
37 SqlValue::Double(v) => {
38 buf.extend_from_slice(&v.to_bits().to_le_bytes());
39 Ok(())
40 }
41 SqlValue::Text(s) => {
42 let len = u32::try_from(s.len()).map_err(|_| ExecutorError::InvalidOperation {
43 operation: "aggregate".into(),
44 reason: "text length exceeds u32::MAX".into(),
45 })?;
46 buf.extend_from_slice(&len.to_le_bytes());
47 buf.extend_from_slice(s.as_bytes());
48 Ok(())
49 }
50 SqlValue::Blob(bytes) => {
51 let len = u32::try_from(bytes.len()).map_err(|_| ExecutorError::InvalidOperation {
52 operation: "aggregate".into(),
53 reason: "blob length exceeds u32::MAX".into(),
54 })?;
55 buf.extend_from_slice(&len.to_le_bytes());
56 buf.extend_from_slice(bytes);
57 Ok(())
58 }
59 SqlValue::Boolean(b) => {
60 buf.push(u8::from(*b));
61 Ok(())
62 }
63 SqlValue::Timestamp(v) => {
64 buf.extend_from_slice(&v.to_le_bytes());
65 Ok(())
66 }
67 SqlValue::Date(v) => {
68 buf.extend_from_slice(&v.to_le_bytes());
69 Ok(())
70 }
71 SqlValue::Time(v) => {
72 buf.extend_from_slice(&v.to_le_bytes());
73 Ok(())
74 }
75 SqlValue::Interval {
76 months,
77 days,
78 micros,
79 } => {
80 buf.extend_from_slice(&months.to_le_bytes());
81 buf.extend_from_slice(&days.to_le_bytes());
82 buf.extend_from_slice(µs.to_le_bytes());
83 Ok(())
84 }
85 SqlValue::Decimal(value) => {
86 buf.extend_from_slice(&value.coefficient.to_le_bytes());
87 buf.push(value.scale);
88 Ok(())
89 }
90 SqlValue::Json(value) => {
91 let bytes = value.as_str().as_bytes();
92 let len = u32::try_from(bytes.len()).map_err(|_| ExecutorError::InvalidOperation {
93 operation: "aggregate".into(),
94 reason: "JSON length exceeds u32::MAX".into(),
95 })?;
96 buf.extend_from_slice(&len.to_le_bytes());
97 buf.extend_from_slice(bytes);
98 Ok(())
99 }
100 SqlValue::Vector(values) => {
101 let len = u32::try_from(values.len()).map_err(|_| ExecutorError::InvalidOperation {
102 operation: "aggregate".into(),
103 reason: "vector length exceeds u32::MAX".into(),
104 })?;
105 buf.extend_from_slice(&len.to_le_bytes());
106 for f in values {
107 buf.extend_from_slice(&f.to_bits().to_le_bytes());
108 }
109 Ok(())
110 }
111 SqlValue::Array(values) => {
112 buf.extend_from_slice(&(values.len() as u32).to_le_bytes());
113 for value in values {
114 encode_group_value(value, buf)?;
115 }
116 Ok(())
117 }
118 SqlValue::Map(values) => {
119 buf.extend_from_slice(&(values.len() as u32).to_le_bytes());
120 for (key, value) in values {
121 encode_group_value(key, buf)?;
122 encode_group_value(value, buf)?;
123 }
124 Ok(())
125 }
126 SqlValue::Struct(values) => {
127 buf.extend_from_slice(&(values.len() as u32).to_le_bytes());
128 for (name, value) in values {
129 buf.extend_from_slice(&(name.len() as u32).to_le_bytes());
130 buf.extend_from_slice(name.as_bytes());
131 encode_group_value(value, buf)?;
132 }
133 Ok(())
134 }
135 }
136}
137
138pub fn encode_group_key(values: &[SqlValue]) -> Result<GroupKeyBytes> {
140 let mut buf = Vec::new();
141 for value in values {
142 encode_group_value(value, &mut buf)?;
143 }
144 Ok(buf)
145}
146
147pub trait Accumulator: Send {
149 fn update(&mut self, value: Option<SqlValue>) -> Result<()>;
151 fn update_values(&mut self, values: &[SqlValue]) -> Result<()> {
154 self.update(values.first().cloned())
155 }
156 fn update_ordered(&mut self, value: Option<SqlValue>, _sort_keys: &[SqlValue]) -> Result<()> {
162 self.update(value)
163 }
164 fn update_ordered_values(&mut self, values: &[SqlValue], sort_keys: &[SqlValue]) -> Result<()> {
165 self.update_ordered(values.first().cloned(), sort_keys)
166 }
167 fn state(&self) -> Result<Vec<SqlValue>>;
169 fn merge(&mut self, state: &[SqlValue]) -> Result<()>;
171 fn finalize(&self) -> Result<SqlValue>;
173 fn clone_box(&self) -> Box<dyn Accumulator>;
175 fn retained_bytes(&self) -> u64 {
180 0
181 }
182}
183
184impl Clone for Box<dyn Accumulator> {
185 fn clone(&self) -> Self {
186 self.clone_box()
187 }
188}
189
190fn invalid_aggregate_state(function: &str, reason: impl Into<String>) -> ExecutorError {
191 ExecutorError::InvalidOperation {
192 operation: function.into(),
193 reason: reason.into(),
194 }
195}
196
197fn expect_state_arity(function: &str, state: &[SqlValue], expected: usize) -> Result<()> {
198 if state.len() == expected {
199 Ok(())
200 } else {
201 Err(invalid_aggregate_state(
202 function,
203 format!("expected {expected} state value(s), got {}", state.len()),
204 ))
205 }
206}
207
208fn state_bigint(function: &str, value: &SqlValue, index: usize) -> Result<i64> {
209 match value {
210 SqlValue::BigInt(v) => Ok(*v),
211 other => Err(invalid_aggregate_state(
212 function,
213 format!(
214 "state value {index} expected BigInt, got {}",
215 other.type_name()
216 ),
217 )),
218 }
219}
220
221fn state_double(function: &str, value: &SqlValue, index: usize) -> Result<f64> {
222 match value {
223 SqlValue::Double(v) => Ok(*v),
224 other => Err(invalid_aggregate_state(
225 function,
226 format!(
227 "state value {index} expected Double, got {}",
228 other.type_name()
229 ),
230 )),
231 }
232}
233
234fn state_text<'a>(function: &str, value: &'a SqlValue, index: usize) -> Result<&'a str> {
235 match value {
236 SqlValue::Text(v) => Ok(v),
237 other => Err(invalid_aggregate_state(
238 function,
239 format!(
240 "state value {index} expected Text, got {}",
241 other.type_name()
242 ),
243 )),
244 }
245}
246
247fn distinct_allows(
248 distinct_values: &mut Option<HashSet<Vec<u8>>>,
249 value: &SqlValue,
250) -> Result<bool> {
251 if value.is_null() {
252 return Ok(false);
253 }
254 let Some(distinct) = distinct_values else {
255 return Ok(true);
256 };
257 let encoded = encode_group_key(std::slice::from_ref(value))?;
258 Ok(distinct.insert(encoded))
259}
260
261fn estimated_distinct_retained_bytes(distinct_values: &Option<HashSet<Vec<u8>>>) -> u64 {
262 let Some(values) = distinct_values else {
263 return 0;
264 };
265 let bucket_bytes = values
268 .capacity()
269 .saturating_mul(std::mem::size_of::<Vec<u8>>() + std::mem::size_of::<u64>() + 1);
270 values.iter().fold(
271 u64::try_from(bucket_bytes).unwrap_or(u64::MAX),
272 |total, value| total.saturating_add(u64::try_from(value.capacity()).unwrap_or(u64::MAX)),
273 )
274}
275
276fn estimated_string_collection_bytes(
277 values: &[String],
278 values_capacity: usize,
279 separator_capacity: usize,
280) -> u64 {
281 let slots = values_capacity.saturating_mul(std::mem::size_of::<String>());
282 values
283 .iter()
284 .fold(u64::try_from(slots).unwrap_or(u64::MAX), |total, value| {
285 total.saturating_add(u64::try_from(value.capacity()).unwrap_or(u64::MAX))
286 })
287 .saturating_add(u64::try_from(separator_capacity).unwrap_or(u64::MAX))
288}
289
290#[derive(Debug, Clone)]
292pub struct CountAccumulator {
293 count: usize,
294 distinct_values: Option<HashSet<Vec<u8>>>,
295}
296
297impl CountAccumulator {
298 pub fn new(distinct: bool) -> Self {
300 Self {
301 count: 0,
302 distinct_values: if distinct { Some(HashSet::new()) } else { None },
303 }
304 }
305}
306
307impl Accumulator for CountAccumulator {
308 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
309 match (&mut self.distinct_values, value) {
310 (Some(distinct), Some(value)) => {
311 if value.is_null() {
312 return Ok(());
313 }
314 let encoded = encode_group_key(std::slice::from_ref(&value))?;
315 if distinct.insert(encoded) {
316 self.count += 1;
317 }
318 }
319 (Some(_), None) => {
320 self.count += 1;
321 }
322 (None, Some(value)) => {
323 if !value.is_null() {
324 self.count += 1;
325 }
326 }
327 (None, None) => {
328 self.count += 1;
329 }
330 }
331 Ok(())
332 }
333
334 fn finalize(&self) -> Result<SqlValue> {
335 Ok(SqlValue::BigInt(self.count as i64))
336 }
337
338 fn state(&self) -> Result<Vec<SqlValue>> {
339 Ok(vec![SqlValue::BigInt(self.count as i64)])
340 }
341
342 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
343 expect_state_arity("count", state, 1)?;
344 let count = state_bigint("count", &state[0], 0)?;
345 if count < 0 {
346 return Err(invalid_aggregate_state(
347 "count",
348 "state count must be non-negative",
349 ));
350 }
351 self.count = self.count.saturating_add(count as usize);
352 Ok(())
353 }
354
355 fn clone_box(&self) -> Box<dyn Accumulator> {
356 Box::new(self.clone())
357 }
358
359 fn retained_bytes(&self) -> u64 {
360 estimated_distinct_retained_bytes(&self.distinct_values)
361 }
362}
363
364#[derive(Debug, Clone)]
366pub struct SumAccumulator {
367 sum: Option<SqlValue>,
368 result_type: ResolvedType,
369 distinct_values: Option<HashSet<Vec<u8>>>,
370}
371
372impl SumAccumulator {
373 pub fn new() -> Self {
375 Self::with_distinct(false)
376 }
377
378 pub fn with_distinct(distinct: bool) -> Self {
379 Self::with_distinct_for_type(distinct, ResolvedType::Double)
380 }
381
382 pub fn with_distinct_for_type(distinct: bool, result_type: ResolvedType) -> Self {
383 Self {
384 sum: None,
385 result_type,
386 distinct_values: if distinct { Some(HashSet::new()) } else { None },
387 }
388 }
389
390 fn add_value(&mut self, value: SqlValue) -> Result<()> {
391 let next = match &self.result_type {
392 ResolvedType::Integer => {
393 let SqlValue::Integer(value) = value else {
394 return sum_type_mismatch("Integer", &value);
395 };
396 let sum = match self.sum.as_ref() {
397 None => value,
398 Some(SqlValue::Integer(current)) => current
399 .checked_add(value)
400 .ok_or(ExecutorError::Evaluation(EvaluationError::Overflow))?,
401 Some(other) => return sum_type_mismatch("Integer", other),
402 };
403 SqlValue::Integer(sum)
404 }
405 ResolvedType::BigInt => {
406 let value = match value {
407 SqlValue::Integer(value) => i64::from(value),
408 SqlValue::BigInt(value) => value,
409 other => return sum_type_mismatch("BigInt", &other),
410 };
411 let sum = match self.sum.as_ref() {
412 None => value,
413 Some(SqlValue::BigInt(current)) => current
414 .checked_add(value)
415 .ok_or(ExecutorError::Evaluation(EvaluationError::Overflow))?,
416 Some(other) => return sum_type_mismatch("BigInt", other),
417 };
418 SqlValue::BigInt(sum)
419 }
420 ResolvedType::Decimal { precision, scale } => {
421 let SqlValue::Decimal(value) = value else {
422 return sum_type_mismatch("Decimal", &value);
423 };
424 let value = value
425 .rescale(*scale)
426 .ok_or(ExecutorError::Evaluation(EvaluationError::Overflow))?;
427 let coefficient = match self.sum.as_ref() {
428 None => value.coefficient,
429 Some(SqlValue::Decimal(current)) => current
430 .coefficient
431 .checked_add(value.coefficient)
432 .ok_or(ExecutorError::Evaluation(EvaluationError::Overflow))?,
433 Some(other) => return sum_type_mismatch("Decimal", other),
434 };
435 let sum = crate::storage::DecimalValue::new(coefficient, *scale);
436 if !sum.fits_precision(*precision) {
437 return Err(ExecutorError::Evaluation(EvaluationError::Overflow));
438 }
439 SqlValue::Decimal(sum)
440 }
441 _ => {
442 let value = numeric_to_f64(&value)?;
443 let sum = match self.sum.as_ref() {
444 None => value,
445 Some(SqlValue::Double(current)) => *current + value,
446 Some(other) => return sum_type_mismatch("Double", other),
447 };
448 SqlValue::Double(sum)
449 }
450 };
451 self.sum = Some(next);
452 Ok(())
453 }
454}
455
456impl Default for SumAccumulator {
457 fn default() -> Self {
458 Self::new()
459 }
460}
461
462impl Accumulator for SumAccumulator {
463 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
464 let Some(value) = value else {
465 return Ok(());
466 };
467 if value.is_null() {
468 return Ok(());
469 }
470 if !distinct_allows(&mut self.distinct_values, &value)? {
471 return Ok(());
472 }
473 self.add_value(value)
474 }
475
476 fn finalize(&self) -> Result<SqlValue> {
477 Ok(self.sum.clone().unwrap_or(SqlValue::Null))
478 }
479
480 fn state(&self) -> Result<Vec<SqlValue>> {
481 Ok(vec![self.sum.clone().unwrap_or(SqlValue::Null)])
482 }
483
484 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
485 expect_state_arity("sum", state, 1)?;
486 if state[0].is_null() {
487 return Ok(());
488 }
489 self.add_value(state[0].clone())
490 }
491
492 fn clone_box(&self) -> Box<dyn Accumulator> {
493 Box::new(self.clone())
494 }
495
496 fn retained_bytes(&self) -> u64 {
497 estimated_distinct_retained_bytes(&self.distinct_values).saturating_add(
498 self.sum
499 .as_ref()
500 .map(ByteSized::estimated_bytes)
501 .unwrap_or(0),
502 )
503 }
504}
505
506#[derive(Debug, Clone)]
508pub struct TotalAccumulator {
509 sum: Option<f64>,
510}
511
512impl TotalAccumulator {
513 pub fn new() -> Self {
515 Self { sum: None }
516 }
517}
518
519impl Default for TotalAccumulator {
520 fn default() -> Self {
521 Self::new()
522 }
523}
524
525impl Accumulator for TotalAccumulator {
526 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
527 let Some(value) = value else {
528 return Ok(());
529 };
530 if value.is_null() {
531 return Ok(());
532 }
533 let numeric = numeric_to_f64(&value)?;
534 self.sum = Some(self.sum.unwrap_or(0.0) + numeric);
535 Ok(())
536 }
537
538 fn finalize(&self) -> Result<SqlValue> {
539 Ok(SqlValue::Double(self.sum.unwrap_or(0.0)))
540 }
541
542 fn state(&self) -> Result<Vec<SqlValue>> {
543 Ok(vec![SqlValue::Double(self.sum.unwrap_or(0.0))])
544 }
545
546 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
547 expect_state_arity("total", state, 1)?;
548 let value = state_double("total", &state[0], 0)?;
549 self.sum = Some(self.sum.unwrap_or(0.0) + value);
550 Ok(())
551 }
552
553 fn clone_box(&self) -> Box<dyn Accumulator> {
554 Box::new(self.clone())
555 }
556}
557
558#[derive(Debug, Clone)]
560pub struct AvgAccumulator {
561 sum: SumAccumulator,
562 result_type: ResolvedType,
563 count: usize,
564 distinct_values: Option<HashSet<Vec<u8>>>,
565}
566
567impl AvgAccumulator {
568 pub fn new() -> Self {
570 Self::with_distinct(false)
571 }
572
573 pub fn with_distinct(distinct: bool) -> Self {
574 Self::with_distinct_for_type(distinct, ResolvedType::Double)
575 }
576
577 pub fn with_distinct_for_type(distinct: bool, result_type: ResolvedType) -> Self {
578 Self {
579 sum: SumAccumulator::with_distinct_for_type(false, result_type.clone()),
580 result_type,
581 count: 0,
582 distinct_values: if distinct { Some(HashSet::new()) } else { None },
583 }
584 }
585}
586
587impl Default for AvgAccumulator {
588 fn default() -> Self {
589 Self::new()
590 }
591}
592
593impl Accumulator for AvgAccumulator {
594 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
595 let Some(value) = value else {
596 return Ok(());
597 };
598 if value.is_null() {
599 return Ok(());
600 }
601 if !distinct_allows(&mut self.distinct_values, &value)? {
602 return Ok(());
603 }
604 self.sum.add_value(value)?;
605 self.count += 1;
606 Ok(())
607 }
608
609 fn finalize(&self) -> Result<SqlValue> {
610 if self.count == 0 {
611 return Ok(SqlValue::Null);
612 }
613 match self.sum.finalize()? {
614 SqlValue::Decimal(sum) => {
615 let divisor = self.count as i128;
616 let quotient = sum.coefficient / divisor;
617 let remainder = sum.coefficient % divisor;
618 let rounded = if remainder.abs().saturating_mul(2) >= divisor {
619 quotient
620 .checked_add(sum.coefficient.signum())
621 .ok_or(ExecutorError::Evaluation(EvaluationError::Overflow))?
622 } else {
623 quotient
624 };
625 Ok(SqlValue::Decimal(crate::storage::DecimalValue::new(
626 rounded, sum.scale,
627 )))
628 }
629 SqlValue::Double(sum) => Ok(SqlValue::Double(sum / self.count as f64)),
630 other => sum_type_mismatch(self.result_type.type_name(), &other),
631 }
632 }
633
634 fn state(&self) -> Result<Vec<SqlValue>> {
635 let sum = match self.sum.finalize()? {
636 SqlValue::Null => match self.result_type {
637 ResolvedType::Decimal { scale, .. } => {
638 SqlValue::Decimal(crate::storage::DecimalValue::new(0, scale))
639 }
640 _ => SqlValue::Double(0.0),
641 },
642 value => value,
643 };
644 Ok(vec![sum, SqlValue::BigInt(self.count as i64)])
645 }
646
647 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
648 expect_state_arity("avg", state, 2)?;
649 let count = state_bigint("avg", &state[1], 1)?;
650 if count < 0 {
651 return Err(invalid_aggregate_state(
652 "avg",
653 "state count must be non-negative",
654 ));
655 }
656 if !state[0].is_null() {
657 self.sum.add_value(state[0].clone())?;
658 }
659 self.count = self.count.saturating_add(count as usize);
660 Ok(())
661 }
662
663 fn clone_box(&self) -> Box<dyn Accumulator> {
664 Box::new(self.clone())
665 }
666
667 fn retained_bytes(&self) -> u64 {
668 estimated_distinct_retained_bytes(&self.distinct_values)
669 }
670}
671
672fn numeric_to_f64(value: &SqlValue) -> Result<f64> {
673 match value {
674 SqlValue::Integer(v) => Ok(*v as f64),
675 SqlValue::BigInt(v) => Ok(*v as f64),
676 SqlValue::Float(v) => Ok(*v as f64),
677 SqlValue::Double(v) => Ok(*v),
678 _ => Err(ExecutorError::Evaluation(
679 crate::executor::EvaluationError::TypeMismatch {
680 expected: "numeric".into(),
681 actual: value.type_name().into(),
682 },
683 )),
684 }
685}
686
687fn sum_type_mismatch<T>(expected: &str, actual: &SqlValue) -> Result<T> {
688 Err(ExecutorError::Evaluation(EvaluationError::TypeMismatch {
689 expected: expected.into(),
690 actual: actual.type_name().into(),
691 }))
692}
693
694#[derive(Debug, Clone)]
696pub struct MinMaxAccumulator {
697 value: Option<SqlValue>,
698 is_min: bool,
699 distinct_values: Option<HashSet<Vec<u8>>>,
700}
701
702impl MinMaxAccumulator {
703 pub fn new(is_min: bool) -> Self {
705 Self::with_distinct(is_min, false)
706 }
707
708 pub fn with_distinct(is_min: bool, distinct: bool) -> Self {
709 Self {
710 value: None,
711 is_min,
712 distinct_values: if distinct { Some(HashSet::new()) } else { None },
713 }
714 }
715}
716
717impl Accumulator for MinMaxAccumulator {
718 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
719 let Some(value) = value else {
720 return Ok(());
721 };
722 if value.is_null() {
723 return Ok(());
724 }
725 if !distinct_allows(&mut self.distinct_values, &value)? {
726 return Ok(());
727 }
728
729 match &self.value {
730 None => {
731 self.value = Some(value);
732 }
733 Some(current) => {
734 if std::mem::discriminant(current) != std::mem::discriminant(&value) {
735 return Err(ExecutorError::Evaluation(
736 crate::executor::EvaluationError::TypeMismatch {
737 expected: current.type_name().into(),
738 actual: value.type_name().into(),
739 },
740 ));
741 }
742 let ordering = value.partial_cmp(current).ok_or_else(|| {
743 ExecutorError::Evaluation(crate::executor::EvaluationError::TypeMismatch {
744 expected: current.type_name().into(),
745 actual: value.type_name().into(),
746 })
747 })?;
748 let should_replace = matches!(
749 (self.is_min, ordering),
750 (true, Ordering::Less) | (false, Ordering::Greater)
751 );
752 if should_replace {
753 self.value = Some(value);
754 }
755 }
756 }
757 Ok(())
758 }
759
760 fn finalize(&self) -> Result<SqlValue> {
761 Ok(self.value.clone().unwrap_or(SqlValue::Null))
762 }
763
764 fn state(&self) -> Result<Vec<SqlValue>> {
765 Ok(vec![self.value.clone().unwrap_or(SqlValue::Null)])
766 }
767
768 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
769 expect_state_arity(if self.is_min { "min" } else { "max" }, state, 1)?;
770 if state[0].is_null() {
771 return Ok(());
772 }
773 self.update(Some(state[0].clone()))
774 }
775
776 fn clone_box(&self) -> Box<dyn Accumulator> {
777 Box::new(self.clone())
778 }
779
780 fn retained_bytes(&self) -> u64 {
781 estimated_distinct_retained_bytes(&self.distinct_values).saturating_add(
782 self.value
783 .as_ref()
784 .map(ByteSized::estimated_bytes)
785 .unwrap_or(0),
786 )
787 }
788}
789
790fn compare_ordered_keys(left: &[SqlValue], right: &[SqlValue], specs: &[(bool, bool)]) -> Ordering {
793 for (idx, (asc, nulls_first)) in specs.iter().enumerate() {
794 let left_value = left.get(idx).unwrap_or(&SqlValue::Null);
795 let right_value = right.get(idx).unwrap_or(&SqlValue::Null);
796 let cmp = super::iterator::compare_single(left_value, right_value, *asc, *nulls_first);
797 if cmp != Ordering::Equal {
798 return cmp;
799 }
800 }
801 Ordering::Equal
802}
803
804fn estimated_ordered_string_bytes(values: &[(Vec<SqlValue>, String)]) -> u64 {
805 values.iter().fold(0u64, |total, (keys, value)| {
806 let key_bytes: u64 = keys.iter().map(ByteSized::estimated_bytes).sum();
807 total
808 .saturating_add(key_bytes)
809 .saturating_add(u64::try_from(value.capacity()).unwrap_or(u64::MAX))
810 })
811}
812
813#[derive(Debug, Clone)]
815pub struct GroupConcatAccumulator {
816 values: Vec<String>,
817 separator: String,
818 distinct_values: Option<HashSet<Vec<u8>>>,
819 sort_specs: Vec<(bool, bool)>,
822 ordered_values: Vec<(Vec<SqlValue>, String)>,
823}
824
825impl GroupConcatAccumulator {
826 pub fn new(separator: String) -> Self {
828 Self::with_distinct(separator, false)
829 }
830
831 pub fn with_distinct(separator: String, distinct: bool) -> Self {
832 Self::with_order(separator, distinct, Vec::new())
833 }
834
835 pub fn with_order(separator: String, distinct: bool, sort_specs: Vec<(bool, bool)>) -> Self {
836 Self {
837 values: Vec::new(),
838 separator,
839 distinct_values: if distinct { Some(HashSet::new()) } else { None },
840 sort_specs,
841 ordered_values: Vec::new(),
842 }
843 }
844}
845
846impl Accumulator for GroupConcatAccumulator {
847 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
848 if !self.sort_specs.is_empty() {
849 return Err(invalid_aggregate_state(
850 "group_concat",
851 "ordered aggregation requires the sort keys of every row",
852 ));
853 }
854 let Some(value) = value else {
855 return Ok(());
856 };
857 match value {
858 SqlValue::Null => Ok(()),
859 SqlValue::Text(text) => {
860 let value = SqlValue::Text(text.clone());
861 if !distinct_allows(&mut self.distinct_values, &value)? {
862 return Ok(());
863 }
864 self.values.push(text);
865 Ok(())
866 }
867 other => Err(ExecutorError::Evaluation(
868 crate::executor::EvaluationError::TypeMismatch {
869 expected: "Text".into(),
870 actual: other.type_name().into(),
871 },
872 )),
873 }
874 }
875
876 fn update_ordered(&mut self, value: Option<SqlValue>, sort_keys: &[SqlValue]) -> Result<()> {
877 if self.sort_specs.is_empty() {
878 return self.update(value);
879 }
880 let Some(value) = value else {
881 return Ok(());
882 };
883 match value {
884 SqlValue::Null => Ok(()),
885 SqlValue::Text(text) => {
886 let value = SqlValue::Text(text.clone());
887 if !distinct_allows(&mut self.distinct_values, &value)? {
888 return Ok(());
889 }
890 self.ordered_values.push((sort_keys.to_vec(), text));
891 Ok(())
892 }
893 other => Err(ExecutorError::Evaluation(
894 crate::executor::EvaluationError::TypeMismatch {
895 expected: "Text".into(),
896 actual: other.type_name().into(),
897 },
898 )),
899 }
900 }
901
902 fn finalize(&self) -> Result<SqlValue> {
903 if !self.sort_specs.is_empty() {
904 if self.ordered_values.is_empty() {
905 return Ok(SqlValue::Null);
906 }
907 let mut sorted = self.ordered_values.clone();
908 sorted.sort_by(|left, right| compare_ordered_keys(&left.0, &right.0, &self.sort_specs));
909 let joined = sorted
910 .into_iter()
911 .map(|(_, value)| value)
912 .collect::<Vec<_>>()
913 .join(&self.separator);
914 return Ok(SqlValue::Text(joined));
915 }
916 if self.values.is_empty() {
917 return Ok(SqlValue::Null);
918 }
919 Ok(SqlValue::Text(self.values.join(&self.separator)))
920 }
921
922 fn state(&self) -> Result<Vec<SqlValue>> {
923 if !self.sort_specs.is_empty() {
924 return Err(invalid_aggregate_state(
925 "group_concat",
926 "ordered aggregation cannot produce partial state",
927 ));
928 }
929 Ok(vec![
930 if self.values.is_empty() {
931 SqlValue::Null
932 } else {
933 SqlValue::Text(self.values.join(&self.separator))
934 },
935 SqlValue::Text(self.separator.clone()),
936 ])
937 }
938
939 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
940 if !self.sort_specs.is_empty() {
941 return Err(invalid_aggregate_state(
942 "group_concat",
943 "ordered aggregation cannot merge partial state",
944 ));
945 }
946 expect_state_arity("group_concat", state, 2)?;
947 let separator = state_text("group_concat", &state[1], 1)?;
948 if separator != self.separator {
949 return Err(invalid_aggregate_state(
950 "group_concat",
951 "state separator differs from accumulator separator",
952 ));
953 }
954 match &state[0] {
955 SqlValue::Null => Ok(()),
956 SqlValue::Text(text) => {
957 self.values.push(text.clone());
958 Ok(())
959 }
960 other => Err(invalid_aggregate_state(
961 "group_concat",
962 format!(
963 "state value 0 expected Text or Null, got {}",
964 other.type_name()
965 ),
966 )),
967 }
968 }
969
970 fn clone_box(&self) -> Box<dyn Accumulator> {
971 Box::new(self.clone())
972 }
973
974 fn retained_bytes(&self) -> u64 {
975 estimated_distinct_retained_bytes(&self.distinct_values)
976 .saturating_add(estimated_string_collection_bytes(
977 &self.values,
978 self.values.capacity(),
979 self.separator.capacity(),
980 ))
981 .saturating_add(estimated_ordered_string_bytes(&self.ordered_values))
982 }
983}
984
985#[derive(Debug, Clone)]
987pub struct StringAggAccumulator {
988 values: Vec<String>,
989 separator: String,
990 distinct_values: Option<HashSet<Vec<u8>>>,
991 sort_specs: Vec<(bool, bool)>,
993 ordered_values: Vec<(Vec<SqlValue>, String)>,
994}
995
996impl StringAggAccumulator {
997 pub fn new(separator: String) -> Self {
999 Self::with_distinct(separator, false)
1000 }
1001
1002 pub fn with_distinct(separator: String, distinct: bool) -> Self {
1003 Self::with_order(separator, distinct, Vec::new())
1004 }
1005
1006 pub fn with_order(separator: String, distinct: bool, sort_specs: Vec<(bool, bool)>) -> Self {
1007 Self {
1008 values: Vec::new(),
1009 separator,
1010 distinct_values: if distinct { Some(HashSet::new()) } else { None },
1011 sort_specs,
1012 ordered_values: Vec::new(),
1013 }
1014 }
1015}
1016
1017impl Accumulator for StringAggAccumulator {
1018 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1019 if !self.sort_specs.is_empty() {
1020 return Err(invalid_aggregate_state(
1021 "string_agg",
1022 "ordered aggregation requires the sort keys of every row",
1023 ));
1024 }
1025 let Some(value) = value else {
1026 return Ok(());
1027 };
1028 match value {
1029 SqlValue::Null => Ok(()),
1030 SqlValue::Text(s) => {
1031 let value = SqlValue::Text(s.clone());
1032 if !distinct_allows(&mut self.distinct_values, &value)? {
1033 return Ok(());
1034 }
1035 self.values.push(s);
1036 Ok(())
1037 }
1038 other => Err(ExecutorError::Evaluation(
1039 crate::executor::EvaluationError::TypeMismatch {
1040 expected: "Text".into(),
1041 actual: other.type_name().into(),
1042 },
1043 )),
1044 }
1045 }
1046
1047 fn update_ordered(&mut self, value: Option<SqlValue>, sort_keys: &[SqlValue]) -> Result<()> {
1048 if self.sort_specs.is_empty() {
1049 return self.update(value);
1050 }
1051 let Some(value) = value else {
1052 return Ok(());
1053 };
1054 match value {
1055 SqlValue::Null => Ok(()),
1056 SqlValue::Text(s) => {
1057 let value = SqlValue::Text(s.clone());
1058 if !distinct_allows(&mut self.distinct_values, &value)? {
1059 return Ok(());
1060 }
1061 self.ordered_values.push((sort_keys.to_vec(), s));
1062 Ok(())
1063 }
1064 other => Err(ExecutorError::Evaluation(
1065 crate::executor::EvaluationError::TypeMismatch {
1066 expected: "Text".into(),
1067 actual: other.type_name().into(),
1068 },
1069 )),
1070 }
1071 }
1072
1073 fn finalize(&self) -> Result<SqlValue> {
1074 if !self.sort_specs.is_empty() {
1075 if self.ordered_values.is_empty() {
1076 return Ok(SqlValue::Null);
1077 }
1078 let mut sorted = self.ordered_values.clone();
1079 sorted.sort_by(|left, right| compare_ordered_keys(&left.0, &right.0, &self.sort_specs));
1080 let joined = sorted
1081 .into_iter()
1082 .map(|(_, value)| value)
1083 .collect::<Vec<_>>()
1084 .join(&self.separator);
1085 return Ok(SqlValue::Text(joined));
1086 }
1087 if self.values.is_empty() {
1088 return Ok(SqlValue::Null);
1089 }
1090 Ok(SqlValue::Text(self.values.join(&self.separator)))
1091 }
1092
1093 fn state(&self) -> Result<Vec<SqlValue>> {
1094 if !self.sort_specs.is_empty() {
1095 return Err(invalid_aggregate_state(
1096 "string_agg",
1097 "ordered aggregation cannot produce partial state",
1098 ));
1099 }
1100 Ok(vec![
1101 if self.values.is_empty() {
1102 SqlValue::Null
1103 } else {
1104 SqlValue::Text(self.values.join(&self.separator))
1105 },
1106 SqlValue::Text(self.separator.clone()),
1107 ])
1108 }
1109
1110 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
1111 if !self.sort_specs.is_empty() {
1112 return Err(invalid_aggregate_state(
1113 "string_agg",
1114 "ordered aggregation cannot merge partial state",
1115 ));
1116 }
1117 expect_state_arity("string_agg", state, 2)?;
1118 let separator = state_text("string_agg", &state[1], 1)?;
1119 if separator != self.separator {
1120 return Err(invalid_aggregate_state(
1121 "string_agg",
1122 "state separator differs from accumulator separator",
1123 ));
1124 }
1125 match &state[0] {
1126 SqlValue::Null => Ok(()),
1127 SqlValue::Text(text) => {
1128 self.values.push(text.clone());
1129 Ok(())
1130 }
1131 other => Err(invalid_aggregate_state(
1132 "string_agg",
1133 format!(
1134 "state value 0 expected Text or Null, got {}",
1135 other.type_name()
1136 ),
1137 )),
1138 }
1139 }
1140
1141 fn clone_box(&self) -> Box<dyn Accumulator> {
1142 Box::new(self.clone())
1143 }
1144
1145 fn retained_bytes(&self) -> u64 {
1146 estimated_distinct_retained_bytes(&self.distinct_values)
1147 .saturating_add(estimated_string_collection_bytes(
1148 &self.values,
1149 self.values.capacity(),
1150 self.separator.capacity(),
1151 ))
1152 .saturating_add(estimated_ordered_string_bytes(&self.ordered_values))
1153 }
1154}
1155
1156#[derive(Debug, Clone)]
1164pub struct PercentileDiscAccumulator {
1165 fraction: f64,
1166 sort_specs: Vec<(bool, bool)>,
1167 values: Vec<(Vec<SqlValue>, SqlValue)>,
1168}
1169
1170impl PercentileDiscAccumulator {
1171 pub fn new(fraction: f64, sort_specs: Vec<(bool, bool)>) -> Self {
1172 let sort_specs = if sort_specs.is_empty() {
1173 vec![(true, false)]
1174 } else {
1175 sort_specs
1176 };
1177 Self {
1178 fraction,
1179 sort_specs,
1180 values: Vec::new(),
1181 }
1182 }
1183}
1184
1185impl Accumulator for PercentileDiscAccumulator {
1186 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1187 let keys = match &value {
1190 Some(inner) if !inner.is_null() => vec![inner.clone()],
1191 _ => return Ok(()),
1192 };
1193 self.update_ordered(value, &keys)
1194 }
1195
1196 fn update_ordered(&mut self, value: Option<SqlValue>, sort_keys: &[SqlValue]) -> Result<()> {
1197 let Some(value) = value else {
1198 return Ok(());
1199 };
1200 if value.is_null() {
1201 return Ok(());
1202 }
1203 self.values.push((sort_keys.to_vec(), value));
1204 Ok(())
1205 }
1206
1207 fn finalize(&self) -> Result<SqlValue> {
1208 if self.values.is_empty() {
1209 return Ok(SqlValue::Null);
1210 }
1211 let mut sorted = self.values.clone();
1212 sorted.sort_by(|left, right| compare_ordered_keys(&left.0, &right.0, &self.sort_specs));
1213 let count = sorted.len();
1214 let index = (self.fraction * count as f64).ceil() as usize;
1215 let index = index.saturating_sub(1).min(count - 1);
1216 Ok(sorted[index].1.clone())
1217 }
1218
1219 fn state(&self) -> Result<Vec<SqlValue>> {
1220 Err(invalid_aggregate_state(
1221 "percentile_disc",
1222 "ordered-set aggregation cannot produce partial state",
1223 ))
1224 }
1225
1226 fn merge(&mut self, _state: &[SqlValue]) -> Result<()> {
1227 Err(invalid_aggregate_state(
1228 "percentile_disc",
1229 "ordered-set aggregation cannot merge partial state",
1230 ))
1231 }
1232
1233 fn clone_box(&self) -> Box<dyn Accumulator> {
1234 Box::new(self.clone())
1235 }
1236
1237 fn retained_bytes(&self) -> u64 {
1238 self.values.iter().fold(0u64, |total, (keys, value)| {
1239 let key_bytes: u64 = keys.iter().map(ByteSized::estimated_bytes).sum();
1240 total
1241 .saturating_add(key_bytes)
1242 .saturating_add(value.estimated_bytes())
1243 })
1244 }
1245}
1246
1247#[derive(Debug, Clone, Copy)]
1248enum StatisticsKind {
1249 Variance(bool),
1250 Stddev(bool),
1251 Covariance(bool),
1252 Corr,
1253 RegrCount,
1254 RegrAvgX,
1255 RegrAvgY,
1256 RegrSxx,
1257 RegrSyy,
1258 RegrSxy,
1259 RegrSlope,
1260 RegrIntercept,
1261 RegrR2,
1262}
1263
1264#[derive(Debug, Clone)]
1266struct StatisticsAccumulator {
1267 kind: StatisticsKind,
1268 count: u64,
1269 mean_x: f64,
1270 mean_y: f64,
1271 m2_x: f64,
1272 m2_y: f64,
1273 co_moment: f64,
1274}
1275
1276impl StatisticsAccumulator {
1277 fn new(kind: StatisticsKind) -> Self {
1278 Self {
1279 kind,
1280 count: 0,
1281 mean_x: 0.0,
1282 mean_y: 0.0,
1283 m2_x: 0.0,
1284 m2_y: 0.0,
1285 co_moment: 0.0,
1286 }
1287 }
1288
1289 fn update_pair(&mut self, y: f64, x: f64) {
1290 self.count += 1;
1291 let count = self.count as f64;
1292 let dx = x - self.mean_x;
1293 let dy = y - self.mean_y;
1294 self.mean_x += dx / count;
1295 self.mean_y += dy / count;
1296 self.m2_x += dx * (x - self.mean_x);
1297 self.m2_y += dy * (y - self.mean_y);
1298 self.co_moment += dx * (y - self.mean_y);
1299 }
1300
1301 fn null_or(&self, value: f64) -> SqlValue {
1302 if self.count == 0 {
1303 SqlValue::Null
1304 } else {
1305 SqlValue::Double(value)
1306 }
1307 }
1308}
1309
1310impl Accumulator for StatisticsAccumulator {
1311 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1312 let Some(value) = value.filter(|value| !value.is_null()) else {
1313 return Ok(());
1314 };
1315 let value = numeric_to_f64(&value)?;
1316 self.update_pair(value, value);
1317 Ok(())
1318 }
1319
1320 fn update_values(&mut self, values: &[SqlValue]) -> Result<()> {
1321 if values.len() == 1 {
1322 return self.update(values.first().cloned());
1323 }
1324 let [y, x] = values else {
1325 return Err(invalid_aggregate_state(
1326 "statistics",
1327 format!("expected one or two inputs, got {}", values.len()),
1328 ));
1329 };
1330 if y.is_null() || x.is_null() {
1331 return Ok(());
1332 }
1333 self.update_pair(numeric_to_f64(y)?, numeric_to_f64(x)?);
1334 Ok(())
1335 }
1336
1337 fn state(&self) -> Result<Vec<SqlValue>> {
1338 Ok(vec![
1339 SqlValue::BigInt(self.count as i64),
1340 SqlValue::Double(self.mean_x),
1341 SqlValue::Double(self.mean_y),
1342 SqlValue::Double(self.m2_x),
1343 SqlValue::Double(self.m2_y),
1344 SqlValue::Double(self.co_moment),
1345 ])
1346 }
1347
1348 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
1349 expect_state_arity("statistics", state, 6)?;
1350 let other_count = state_bigint("statistics", &state[0], 0)?;
1351 if other_count < 0 {
1352 return Err(invalid_aggregate_state(
1353 "statistics",
1354 "state count must be non-negative",
1355 ));
1356 }
1357 let other_count = other_count as u64;
1358 if other_count == 0 {
1359 return Ok(());
1360 }
1361 let other_mean_x = state_double("statistics", &state[1], 1)?;
1362 let other_mean_y = state_double("statistics", &state[2], 2)?;
1363 let other_m2_x = state_double("statistics", &state[3], 3)?;
1364 let other_m2_y = state_double("statistics", &state[4], 4)?;
1365 let other_co_moment = state_double("statistics", &state[5], 5)?;
1366 if self.count == 0 {
1367 self.count = other_count;
1368 self.mean_x = other_mean_x;
1369 self.mean_y = other_mean_y;
1370 self.m2_x = other_m2_x;
1371 self.m2_y = other_m2_y;
1372 self.co_moment = other_co_moment;
1373 return Ok(());
1374 }
1375 let total = self.count + other_count;
1376 let left = self.count as f64;
1377 let right = other_count as f64;
1378 let total_f = total as f64;
1379 let dx = other_mean_x - self.mean_x;
1380 let dy = other_mean_y - self.mean_y;
1381 self.m2_x += other_m2_x + dx * dx * left * right / total_f;
1382 self.m2_y += other_m2_y + dy * dy * left * right / total_f;
1383 self.co_moment += other_co_moment + dx * dy * left * right / total_f;
1384 self.mean_x += dx * right / total_f;
1385 self.mean_y += dy * right / total_f;
1386 self.count = total;
1387 Ok(())
1388 }
1389
1390 fn finalize(&self) -> Result<SqlValue> {
1391 let sample_divisor = || (self.count > 1).then(|| (self.count - 1) as f64);
1392 let population_divisor = || (self.count > 0).then_some(self.count as f64);
1393 let value = match self.kind {
1394 StatisticsKind::Variance(sample) | StatisticsKind::Stddev(sample) => {
1395 let divisor = if sample {
1396 sample_divisor()
1397 } else {
1398 population_divisor()
1399 };
1400 let Some(divisor) = divisor else {
1401 return Ok(SqlValue::Null);
1402 };
1403 let variance = self.m2_x / divisor;
1404 if matches!(self.kind, StatisticsKind::Stddev(_)) {
1405 variance.sqrt()
1406 } else {
1407 variance
1408 }
1409 }
1410 StatisticsKind::Covariance(sample) => {
1411 let divisor = if sample {
1412 sample_divisor()
1413 } else {
1414 population_divisor()
1415 };
1416 let Some(divisor) = divisor else {
1417 return Ok(SqlValue::Null);
1418 };
1419 self.co_moment / divisor
1420 }
1421 StatisticsKind::Corr => {
1422 let divisor = (self.m2_x * self.m2_y).sqrt();
1423 if self.count == 0 || divisor == 0.0 {
1424 return Ok(SqlValue::Null);
1425 }
1426 self.co_moment / divisor
1427 }
1428 StatisticsKind::RegrCount => return Ok(SqlValue::BigInt(self.count as i64)),
1429 StatisticsKind::RegrAvgX => return Ok(self.null_or(self.mean_x)),
1430 StatisticsKind::RegrAvgY => return Ok(self.null_or(self.mean_y)),
1431 StatisticsKind::RegrSxx => return Ok(self.null_or(self.m2_x)),
1432 StatisticsKind::RegrSyy => return Ok(self.null_or(self.m2_y)),
1433 StatisticsKind::RegrSxy => return Ok(self.null_or(self.co_moment)),
1434 StatisticsKind::RegrSlope => {
1435 if self.count == 0 || self.m2_x == 0.0 {
1436 return Ok(SqlValue::Null);
1437 }
1438 self.co_moment / self.m2_x
1439 }
1440 StatisticsKind::RegrIntercept => {
1441 if self.count == 0 || self.m2_x == 0.0 {
1442 return Ok(SqlValue::Null);
1443 }
1444 self.mean_y - (self.co_moment / self.m2_x) * self.mean_x
1445 }
1446 StatisticsKind::RegrR2 => {
1447 if self.count == 0 || self.m2_x == 0.0 {
1448 return Ok(SqlValue::Null);
1449 }
1450 if self.m2_y == 0.0 {
1451 1.0
1452 } else {
1453 self.co_moment * self.co_moment / (self.m2_x * self.m2_y)
1454 }
1455 }
1456 };
1457 Ok(SqlValue::Double(value))
1458 }
1459
1460 fn clone_box(&self) -> Box<dyn Accumulator> {
1461 Box::new(self.clone())
1462 }
1463}
1464
1465#[derive(Debug, Clone)]
1466struct PercentileContAccumulator {
1467 fraction: f64,
1468 ascending: bool,
1469 values: Vec<f64>,
1470}
1471
1472impl PercentileContAccumulator {
1473 fn new(fraction: f64, ascending: bool) -> Self {
1474 Self {
1475 fraction,
1476 ascending,
1477 values: Vec::new(),
1478 }
1479 }
1480}
1481
1482impl Accumulator for PercentileContAccumulator {
1483 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1484 let Some(value) = value.filter(|value| !value.is_null()) else {
1485 return Ok(());
1486 };
1487 self.values.push(numeric_to_f64(&value)?);
1488 Ok(())
1489 }
1490
1491 fn state(&self) -> Result<Vec<SqlValue>> {
1492 Err(invalid_aggregate_state(
1493 "percentile_cont",
1494 "ordered aggregation cannot produce partial state",
1495 ))
1496 }
1497
1498 fn merge(&mut self, _state: &[SqlValue]) -> Result<()> {
1499 Err(invalid_aggregate_state(
1500 "percentile_cont",
1501 "ordered aggregation cannot merge partial state",
1502 ))
1503 }
1504
1505 fn finalize(&self) -> Result<SqlValue> {
1506 if self.values.is_empty() {
1507 return Ok(SqlValue::Null);
1508 }
1509 let mut values = self.values.clone();
1510 values.sort_by(f64::total_cmp);
1511 if !self.ascending {
1512 values.reverse();
1513 }
1514 let position = self.fraction * (values.len() - 1) as f64;
1515 let lower = position.floor() as usize;
1516 let upper = position.ceil() as usize;
1517 if lower == upper {
1518 return Ok(SqlValue::Double(values[lower]));
1519 }
1520 let weight = position - lower as f64;
1521 Ok(SqlValue::Double(
1522 values[lower] + (values[upper] - values[lower]) * weight,
1523 ))
1524 }
1525
1526 fn clone_box(&self) -> Box<dyn Accumulator> {
1527 Box::new(self.clone())
1528 }
1529
1530 fn retained_bytes(&self) -> u64 {
1531 u64::try_from(
1532 self.values
1533 .capacity()
1534 .saturating_mul(std::mem::size_of::<f64>()),
1535 )
1536 .unwrap_or(u64::MAX)
1537 }
1538}
1539
1540#[derive(Debug, Clone)]
1541struct ModeAccumulator {
1542 sort_specs: Vec<(bool, bool)>,
1543 values: Vec<(Vec<SqlValue>, SqlValue)>,
1544}
1545
1546impl ModeAccumulator {
1547 fn new(sort_specs: Vec<(bool, bool)>) -> Self {
1548 Self {
1549 sort_specs: if sort_specs.is_empty() {
1550 vec![(true, false)]
1551 } else {
1552 sort_specs
1553 },
1554 values: Vec::new(),
1555 }
1556 }
1557}
1558
1559impl Accumulator for ModeAccumulator {
1560 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1561 let Some(value) = value.filter(|value| !value.is_null()) else {
1562 return Ok(());
1563 };
1564 self.values.push((vec![value.clone()], value));
1565 Ok(())
1566 }
1567
1568 fn update_ordered(&mut self, value: Option<SqlValue>, sort_keys: &[SqlValue]) -> Result<()> {
1569 let Some(value) = value.filter(|value| !value.is_null()) else {
1570 return Ok(());
1571 };
1572 self.values.push((sort_keys.to_vec(), value));
1573 Ok(())
1574 }
1575
1576 fn state(&self) -> Result<Vec<SqlValue>> {
1577 Err(invalid_aggregate_state(
1578 "mode",
1579 "ordered aggregation cannot produce partial state",
1580 ))
1581 }
1582
1583 fn merge(&mut self, _state: &[SqlValue]) -> Result<()> {
1584 Err(invalid_aggregate_state(
1585 "mode",
1586 "ordered aggregation cannot merge partial state",
1587 ))
1588 }
1589
1590 fn finalize(&self) -> Result<SqlValue> {
1591 if self.values.is_empty() {
1592 return Ok(SqlValue::Null);
1593 }
1594 let mut values = self.values.clone();
1595 values.sort_by(|left, right| compare_ordered_keys(&left.0, &right.0, &self.sort_specs));
1596 let mut best_start = 0;
1597 let mut best_count = 0;
1598 let mut start = 0;
1599 while start < values.len() {
1600 let mut end = start + 1;
1601 while end < values.len()
1602 && compare_ordered_keys(&values[start].0, &values[end].0, &self.sort_specs)
1603 == Ordering::Equal
1604 {
1605 end += 1;
1606 }
1607 if end - start > best_count {
1608 best_start = start;
1609 best_count = end - start;
1610 }
1611 start = end;
1612 }
1613 Ok(values[best_start].1.clone())
1614 }
1615
1616 fn clone_box(&self) -> Box<dyn Accumulator> {
1617 Box::new(self.clone())
1618 }
1619
1620 fn retained_bytes(&self) -> u64 {
1621 self.values.iter().fold(0, |total, (keys, value)| {
1622 total
1623 .saturating_add(keys.iter().map(ByteSized::estimated_bytes).sum::<u64>())
1624 .saturating_add(value.estimated_bytes())
1625 })
1626 }
1627}
1628
1629#[derive(Debug, Clone, Copy)]
1630enum ValueKind {
1631 Any,
1632 First,
1633 Last,
1634 ArgMin,
1635 ArgMax,
1636}
1637
1638#[derive(Debug, Clone)]
1639struct ValueAccumulator {
1640 kind: ValueKind,
1641 sort_specs: Vec<(bool, bool)>,
1642 chosen: Option<(Vec<SqlValue>, SqlValue)>,
1643}
1644
1645impl ValueAccumulator {
1646 fn new(kind: ValueKind, sort_specs: Vec<(bool, bool)>) -> Self {
1647 Self {
1648 kind,
1649 sort_specs,
1650 chosen: None,
1651 }
1652 }
1653
1654 fn select(&mut self, keys: Vec<SqlValue>, value: SqlValue) {
1655 let replace = match &self.chosen {
1656 None => true,
1657 Some((current, _)) => match self.kind {
1658 ValueKind::Any | ValueKind::First => false,
1659 ValueKind::Last => true,
1660 ValueKind::ArgMin => {
1661 compare_ordered_keys(&keys, current, &[(true, false)]) == Ordering::Less
1662 }
1663 ValueKind::ArgMax => {
1664 compare_ordered_keys(&keys, current, &[(true, false)]) == Ordering::Greater
1665 }
1666 },
1667 };
1668 if replace {
1669 self.chosen = Some((keys, value));
1670 }
1671 }
1672}
1673
1674impl Accumulator for ValueAccumulator {
1675 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1676 let Some(value) = value else {
1677 return Ok(());
1678 };
1679 if matches!(self.kind, ValueKind::Any) && value.is_null() {
1680 return Ok(());
1681 }
1682 self.select(Vec::new(), value);
1683 Ok(())
1684 }
1685
1686 fn update_values(&mut self, values: &[SqlValue]) -> Result<()> {
1687 if matches!(self.kind, ValueKind::ArgMin | ValueKind::ArgMax) {
1688 let [value, key] = values else {
1689 return Err(invalid_aggregate_state(
1690 "arg_min/max",
1691 format!("expected two inputs, got {}", values.len()),
1692 ));
1693 };
1694 if value.is_null() || key.is_null() {
1695 return Ok(());
1696 }
1697 self.select(vec![key.clone()], value.clone());
1698 return Ok(());
1699 }
1700 self.update(values.first().cloned())
1701 }
1702
1703 fn update_ordered(&mut self, value: Option<SqlValue>, sort_keys: &[SqlValue]) -> Result<()> {
1704 let Some(value) = value else {
1705 return Ok(());
1706 };
1707 match &self.chosen {
1708 None => self.chosen = Some((sort_keys.to_vec(), value)),
1709 Some((keys, _)) => {
1710 let ordering = compare_ordered_keys(sort_keys, keys, &self.sort_specs);
1711 let replace = matches!(
1712 (self.kind, ordering),
1713 (ValueKind::First, Ordering::Less) | (ValueKind::Last, Ordering::Greater)
1714 );
1715 if replace {
1716 self.chosen = Some((sort_keys.to_vec(), value));
1717 }
1718 }
1719 }
1720 Ok(())
1721 }
1722
1723 fn state(&self) -> Result<Vec<SqlValue>> {
1724 Ok(vec![
1725 self.chosen
1726 .as_ref()
1727 .map(|(_, value)| value.clone())
1728 .unwrap_or(SqlValue::Null),
1729 ])
1730 }
1731
1732 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
1733 expect_state_arity("value aggregate", state, 1)?;
1734 self.update(Some(state[0].clone()))
1735 }
1736
1737 fn finalize(&self) -> Result<SqlValue> {
1738 Ok(self
1739 .chosen
1740 .as_ref()
1741 .map(|(_, value)| value.clone())
1742 .unwrap_or(SqlValue::Null))
1743 }
1744
1745 fn clone_box(&self) -> Box<dyn Accumulator> {
1746 Box::new(self.clone())
1747 }
1748
1749 fn retained_bytes(&self) -> u64 {
1750 self.chosen
1751 .as_ref()
1752 .map(|(keys, value)| {
1753 keys.iter()
1754 .map(ByteSized::estimated_bytes)
1755 .sum::<u64>()
1756 .saturating_add(value.estimated_bytes())
1757 })
1758 .unwrap_or(0)
1759 }
1760}
1761
1762#[derive(Debug, Clone, Copy)]
1763enum BitKind {
1764 And,
1765 Or,
1766 Xor,
1767}
1768
1769#[derive(Debug, Clone)]
1770struct BitAccumulator {
1771 kind: BitKind,
1772 value: Option<SqlValue>,
1773}
1774
1775impl BitAccumulator {
1776 fn new(kind: BitKind) -> Self {
1777 Self { kind, value: None }
1778 }
1779}
1780
1781impl Accumulator for BitAccumulator {
1782 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1783 let Some(value) = value.filter(|value| !value.is_null()) else {
1784 return Ok(());
1785 };
1786 self.value = Some(match (self.value.take(), value) {
1787 (None, value) => value,
1788 (Some(SqlValue::Integer(left)), SqlValue::Integer(right)) => {
1789 SqlValue::Integer(match self.kind {
1790 BitKind::And => left & right,
1791 BitKind::Or => left | right,
1792 BitKind::Xor => left ^ right,
1793 })
1794 }
1795 (Some(SqlValue::BigInt(left)), SqlValue::BigInt(right)) => {
1796 SqlValue::BigInt(match self.kind {
1797 BitKind::And => left & right,
1798 BitKind::Or => left | right,
1799 BitKind::Xor => left ^ right,
1800 })
1801 }
1802 (Some(left), right) => {
1803 return Err(ExecutorError::Evaluation(EvaluationError::TypeMismatch {
1804 expected: "matching integer types".into(),
1805 actual: format!("{} vs {}", left.type_name(), right.type_name()),
1806 }));
1807 }
1808 });
1809 Ok(())
1810 }
1811
1812 fn state(&self) -> Result<Vec<SqlValue>> {
1813 Ok(vec![self.value.clone().unwrap_or(SqlValue::Null)])
1814 }
1815
1816 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
1817 expect_state_arity("bit aggregate", state, 1)?;
1818 self.update(Some(state[0].clone()))
1819 }
1820
1821 fn finalize(&self) -> Result<SqlValue> {
1822 Ok(self.value.clone().unwrap_or(SqlValue::Null))
1823 }
1824
1825 fn clone_box(&self) -> Box<dyn Accumulator> {
1826 Box::new(self.clone())
1827 }
1828}
1829
1830#[derive(Debug, Clone)]
1831struct BoolAccumulator {
1832 and: bool,
1833 value: Option<bool>,
1834}
1835
1836impl BoolAccumulator {
1837 fn new(and: bool) -> Self {
1838 Self { and, value: None }
1839 }
1840}
1841
1842impl Accumulator for BoolAccumulator {
1843 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1844 match value {
1845 None | Some(SqlValue::Null) => Ok(()),
1846 Some(SqlValue::Boolean(value)) => {
1847 self.value = Some(match self.value {
1848 None => value,
1849 Some(current) if self.and => current && value,
1850 Some(current) => current || value,
1851 });
1852 Ok(())
1853 }
1854 Some(other) => Err(ExecutorError::Evaluation(EvaluationError::TypeMismatch {
1855 expected: "Boolean".into(),
1856 actual: other.type_name().into(),
1857 })),
1858 }
1859 }
1860
1861 fn state(&self) -> Result<Vec<SqlValue>> {
1862 Ok(vec![
1863 self.value.map(SqlValue::Boolean).unwrap_or(SqlValue::Null),
1864 ])
1865 }
1866
1867 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
1868 expect_state_arity("boolean aggregate", state, 1)?;
1869 self.update(Some(state[0].clone()))
1870 }
1871
1872 fn finalize(&self) -> Result<SqlValue> {
1873 Ok(self.value.map(SqlValue::Boolean).unwrap_or(SqlValue::Null))
1874 }
1875
1876 fn clone_box(&self) -> Box<dyn Accumulator> {
1877 Box::new(self.clone())
1878 }
1879}
1880
1881#[derive(Debug, Clone)]
1882struct ArrayAccumulator {
1883 values: Vec<SqlValue>,
1884 distinct: bool,
1885 seen: HashSet<Vec<u8>>,
1886}
1887
1888impl ArrayAccumulator {
1889 fn new(distinct: bool) -> Self {
1890 Self {
1891 values: Vec::new(),
1892 distinct,
1893 seen: HashSet::new(),
1894 }
1895 }
1896}
1897
1898impl Accumulator for ArrayAccumulator {
1899 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1900 let value = value.unwrap_or(SqlValue::Null);
1901 if !self.distinct
1902 || self
1903 .seen
1904 .insert(encode_group_key(std::slice::from_ref(&value))?)
1905 {
1906 self.values.push(value);
1907 }
1908 Ok(())
1909 }
1910
1911 fn state(&self) -> Result<Vec<SqlValue>> {
1912 Ok(vec![SqlValue::Array(self.values.clone())])
1913 }
1914
1915 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
1916 expect_state_arity("ARRAY_AGG", state, 1)?;
1917 let SqlValue::Array(values) = &state[0] else {
1918 return Err(invalid_aggregate_state(
1919 "ARRAY_AGG",
1920 "partial state must be ARRAY",
1921 ));
1922 };
1923 for value in values {
1924 self.update(Some(value.clone()))?;
1925 }
1926 Ok(())
1927 }
1928
1929 fn finalize(&self) -> Result<SqlValue> {
1930 Ok(SqlValue::Array(self.values.clone()))
1931 }
1932
1933 fn clone_box(&self) -> Box<dyn Accumulator> {
1934 Box::new(self.clone())
1935 }
1936}
1937
1938#[derive(Debug, Clone)]
1939struct JsonArrayAccumulator {
1940 values: Vec<SqlValue>,
1941 distinct: bool,
1942 seen: HashSet<Vec<u8>>,
1943 native: bool,
1944}
1945
1946impl JsonArrayAccumulator {
1947 fn new(distinct: bool, native: bool) -> Self {
1948 Self {
1949 values: Vec::new(),
1950 distinct,
1951 seen: HashSet::new(),
1952 native,
1953 }
1954 }
1955}
1956
1957impl Accumulator for JsonArrayAccumulator {
1958 fn update(&mut self, value: Option<SqlValue>) -> Result<()> {
1959 let value = value.unwrap_or(SqlValue::Null);
1960 if !self.distinct
1961 || self
1962 .seen
1963 .insert(encode_group_key(std::slice::from_ref(&value))?)
1964 {
1965 self.values.push(value);
1966 }
1967 Ok(())
1968 }
1969
1970 fn state(&self) -> Result<Vec<SqlValue>> {
1971 Ok(vec![SqlValue::Text(
1972 crate::executor::evaluator::json::json_group_array(&self.values)?,
1973 )])
1974 }
1975
1976 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
1977 expect_state_arity("JSON_GROUP_ARRAY", state, 1)?;
1978 let SqlValue::Text(json) = &state[0] else {
1979 return Err(invalid_aggregate_state(
1980 "JSON_GROUP_ARRAY",
1981 "partial state must be TEXT",
1982 ));
1983 };
1984 let serde_json::Value::Array(values) =
1985 crate::executor::evaluator::json::parse_json("JSON_GROUP_ARRAY", json)?
1986 else {
1987 return Err(invalid_aggregate_state(
1988 "JSON_GROUP_ARRAY",
1989 "partial state must be a JSON array",
1990 ));
1991 };
1992 for value in values {
1993 self.update(Some(crate::executor::evaluator::json::json_to_sql(&value)?))?;
1994 }
1995 Ok(())
1996 }
1997
1998 fn finalize(&self) -> Result<SqlValue> {
1999 let value = crate::executor::evaluator::json::json_group_array(&self.values)?;
2000 if self.native {
2001 Ok(SqlValue::Json(
2002 crate::storage::JsonValue::parse(&value).expect("aggregate emits JSON"),
2003 ))
2004 } else {
2005 Ok(SqlValue::Text(value))
2006 }
2007 }
2008
2009 fn clone_box(&self) -> Box<dyn Accumulator> {
2010 Box::new(self.clone())
2011 }
2012 fn retained_bytes(&self) -> u64 {
2013 self.values.iter().map(ByteSized::estimated_bytes).sum()
2014 }
2015}
2016
2017#[derive(Debug, Clone)]
2018struct JsonObjectAccumulator {
2019 values: Vec<(String, SqlValue)>,
2020 distinct: bool,
2021 seen: HashSet<Vec<u8>>,
2022 native: bool,
2023}
2024
2025impl JsonObjectAccumulator {
2026 fn new(distinct: bool, native: bool) -> Self {
2027 Self {
2028 values: Vec::new(),
2029 distinct,
2030 seen: HashSet::new(),
2031 native,
2032 }
2033 }
2034}
2035
2036impl Accumulator for JsonObjectAccumulator {
2037 fn update(&mut self, _value: Option<SqlValue>) -> Result<()> {
2038 Err(invalid_aggregate_state(
2039 "JSON_GROUP_OBJECT",
2040 "requires two arguments",
2041 ))
2042 }
2043
2044 fn update_values(&mut self, values: &[SqlValue]) -> Result<()> {
2045 expect_state_arity("JSON_GROUP_OBJECT", values, 2)?;
2046 let key = match &values[0] {
2047 SqlValue::Null => return Ok(()),
2048 SqlValue::Text(key) => key.clone(),
2049 other => {
2050 return Err(invalid_aggregate_state(
2051 "JSON_GROUP_OBJECT",
2052 format!("object label must be TEXT, found {}", other.type_name()),
2053 ));
2054 }
2055 };
2056 if !self.distinct || self.seen.insert(encode_group_key(values)?) {
2057 self.values.push((key, values[1].clone()));
2058 }
2059 Ok(())
2060 }
2061
2062 fn state(&self) -> Result<Vec<SqlValue>> {
2063 let state = serde_json::to_string(&self.values).map_err(|error| {
2064 invalid_aggregate_state("JSON_GROUP_OBJECT", format!("cannot encode state: {error}"))
2065 })?;
2066 if state.len() > crate::executor::evaluator::json::MAX_JSON_BYTES {
2067 return Err(invalid_aggregate_state(
2068 "JSON_GROUP_OBJECT",
2069 "partial state exceeds 1048576 bytes",
2070 ));
2071 }
2072 Ok(vec![SqlValue::Text(state)])
2073 }
2074
2075 fn merge(&mut self, state: &[SqlValue]) -> Result<()> {
2076 expect_state_arity("JSON_GROUP_OBJECT", state, 1)?;
2077 let SqlValue::Text(state) = &state[0] else {
2078 return Err(invalid_aggregate_state(
2079 "JSON_GROUP_OBJECT",
2080 "partial state must be TEXT",
2081 ));
2082 };
2083 let values: Vec<(String, SqlValue)> = serde_json::from_str(state).map_err(|error| {
2084 invalid_aggregate_state("JSON_GROUP_OBJECT", format!("invalid state: {error}"))
2085 })?;
2086 for (key, value) in values {
2087 self.update_values(&[SqlValue::Text(key), value])?;
2088 }
2089 Ok(())
2090 }
2091
2092 fn finalize(&self) -> Result<SqlValue> {
2093 let value = crate::executor::evaluator::json::json_group_object(&self.values)?;
2094 if self.native {
2095 Ok(SqlValue::Json(
2096 crate::storage::JsonValue::parse(&value).expect("aggregate emits JSON"),
2097 ))
2098 } else {
2099 Ok(SqlValue::Text(value))
2100 }
2101 }
2102
2103 fn clone_box(&self) -> Box<dyn Accumulator> {
2104 Box::new(self.clone())
2105 }
2106 fn retained_bytes(&self) -> u64 {
2107 self.values
2108 .iter()
2109 .map(|(key, value)| key.capacity() as u64 + value.estimated_bytes())
2110 .sum()
2111 }
2112}
2113
2114pub fn create_accumulator(function: &AggregateFunction, distinct: bool) -> Box<dyn Accumulator> {
2116 match function {
2117 AggregateFunction::Count => Box::new(CountAccumulator::new(distinct)),
2118 AggregateFunction::Sum => Box::new(SumAccumulator::with_distinct(distinct)),
2119 AggregateFunction::Total => Box::new(TotalAccumulator::new()),
2120 AggregateFunction::Avg => Box::new(AvgAccumulator::with_distinct(distinct)),
2121 AggregateFunction::Min => Box::new(MinMaxAccumulator::with_distinct(true, distinct)),
2122 AggregateFunction::Max => Box::new(MinMaxAccumulator::with_distinct(false, distinct)),
2123 AggregateFunction::GroupConcat { separator } => {
2124 let sep = separator.clone().unwrap_or_else(|| ",".to_string());
2125 Box::new(GroupConcatAccumulator::with_distinct(sep, distinct))
2126 }
2127 AggregateFunction::StringAgg { separator } => {
2128 let sep = separator.clone().unwrap_or_else(|| ",".to_string());
2129 Box::new(StringAggAccumulator::with_distinct(sep, distinct))
2130 }
2131 AggregateFunction::JsonGroupArray => Box::new(JsonArrayAccumulator::new(distinct, false)),
2132 AggregateFunction::ArrayAgg => Box::new(ArrayAccumulator::new(distinct)),
2133 AggregateFunction::JsonGroupObject => Box::new(JsonObjectAccumulator::new(distinct, false)),
2134 AggregateFunction::JsonbAgg => Box::new(JsonArrayAccumulator::new(distinct, true)),
2135 AggregateFunction::JsonbObjectAgg => Box::new(JsonObjectAccumulator::new(distinct, true)),
2136 AggregateFunction::PercentileDisc { fraction } => {
2137 Box::new(PercentileDiscAccumulator::new(*fraction, Vec::new()))
2138 }
2139 AggregateFunction::PercentileCont { fraction }
2140 | AggregateFunction::QuantileCont { fraction } => {
2141 Box::new(PercentileContAccumulator::new(*fraction, true))
2142 }
2143 AggregateFunction::Variance { sample } => Box::new(StatisticsAccumulator::new(
2144 StatisticsKind::Variance(*sample),
2145 )),
2146 AggregateFunction::Stddev { sample } => {
2147 Box::new(StatisticsAccumulator::new(StatisticsKind::Stddev(*sample)))
2148 }
2149 AggregateFunction::Covariance { sample } => Box::new(StatisticsAccumulator::new(
2150 StatisticsKind::Covariance(*sample),
2151 )),
2152 AggregateFunction::Corr => Box::new(StatisticsAccumulator::new(StatisticsKind::Corr)),
2153 AggregateFunction::Median => Box::new(PercentileContAccumulator::new(0.5, true)),
2154 AggregateFunction::Mode => Box::new(ModeAccumulator::new(Vec::new())),
2155 AggregateFunction::RegrCount => {
2156 Box::new(StatisticsAccumulator::new(StatisticsKind::RegrCount))
2157 }
2158 AggregateFunction::RegrAvgX => {
2159 Box::new(StatisticsAccumulator::new(StatisticsKind::RegrAvgX))
2160 }
2161 AggregateFunction::RegrAvgY => {
2162 Box::new(StatisticsAccumulator::new(StatisticsKind::RegrAvgY))
2163 }
2164 AggregateFunction::RegrSxx => Box::new(StatisticsAccumulator::new(StatisticsKind::RegrSxx)),
2165 AggregateFunction::RegrSyy => Box::new(StatisticsAccumulator::new(StatisticsKind::RegrSyy)),
2166 AggregateFunction::RegrSxy => Box::new(StatisticsAccumulator::new(StatisticsKind::RegrSxy)),
2167 AggregateFunction::RegrSlope => {
2168 Box::new(StatisticsAccumulator::new(StatisticsKind::RegrSlope))
2169 }
2170 AggregateFunction::RegrIntercept => {
2171 Box::new(StatisticsAccumulator::new(StatisticsKind::RegrIntercept))
2172 }
2173 AggregateFunction::RegrR2 => Box::new(StatisticsAccumulator::new(StatisticsKind::RegrR2)),
2174 AggregateFunction::AnyValue => Box::new(ValueAccumulator::new(ValueKind::Any, Vec::new())),
2175 AggregateFunction::First => Box::new(ValueAccumulator::new(ValueKind::First, Vec::new())),
2176 AggregateFunction::Last => Box::new(ValueAccumulator::new(ValueKind::Last, Vec::new())),
2177 AggregateFunction::ArgMin => Box::new(ValueAccumulator::new(ValueKind::ArgMin, Vec::new())),
2178 AggregateFunction::ArgMax => Box::new(ValueAccumulator::new(ValueKind::ArgMax, Vec::new())),
2179 AggregateFunction::BitAnd => Box::new(BitAccumulator::new(BitKind::And)),
2180 AggregateFunction::BitOr => Box::new(BitAccumulator::new(BitKind::Or)),
2181 AggregateFunction::BitXor => Box::new(BitAccumulator::new(BitKind::Xor)),
2182 AggregateFunction::BoolAnd => Box::new(BoolAccumulator::new(true)),
2183 AggregateFunction::BoolOr => Box::new(BoolAccumulator::new(false)),
2184 }
2185}
2186
2187fn aggregate_sort_specs(aggregate: &AggregateExpr) -> Vec<(bool, bool)> {
2188 aggregate
2189 .order_by
2190 .iter()
2191 .map(|sort| (sort.asc, sort.nulls_first))
2192 .collect()
2193}
2194
2195pub fn create_accumulator_for_aggregate(aggregate: &AggregateExpr) -> Box<dyn Accumulator> {
2198 match &aggregate.function {
2199 AggregateFunction::Sum => Box::new(SumAccumulator::with_distinct_for_type(
2200 aggregate.distinct,
2201 aggregate.result_type.clone(),
2202 )),
2203 AggregateFunction::Avg => Box::new(AvgAccumulator::with_distinct_for_type(
2204 aggregate.distinct,
2205 aggregate.result_type.clone(),
2206 )),
2207 AggregateFunction::GroupConcat { separator } if !aggregate.order_by.is_empty() => {
2208 let sep = separator.clone().unwrap_or_else(|| ",".to_string());
2209 Box::new(GroupConcatAccumulator::with_order(
2210 sep,
2211 aggregate.distinct,
2212 aggregate_sort_specs(aggregate),
2213 ))
2214 }
2215 AggregateFunction::StringAgg { separator } if !aggregate.order_by.is_empty() => {
2216 let sep = separator.clone().unwrap_or_else(|| ",".to_string());
2217 Box::new(StringAggAccumulator::with_order(
2218 sep,
2219 aggregate.distinct,
2220 aggregate_sort_specs(aggregate),
2221 ))
2222 }
2223 AggregateFunction::PercentileDisc { fraction } => Box::new(PercentileDiscAccumulator::new(
2224 *fraction,
2225 aggregate_sort_specs(aggregate),
2226 )),
2227 AggregateFunction::PercentileCont { fraction }
2228 | AggregateFunction::QuantileCont { fraction } => Box::new(PercentileContAccumulator::new(
2229 *fraction,
2230 aggregate_sort_specs(aggregate)
2231 .first()
2232 .is_none_or(|(ascending, _)| *ascending),
2233 )),
2234 AggregateFunction::Mode if !aggregate.order_by.is_empty() => {
2235 Box::new(ModeAccumulator::new(aggregate_sort_specs(aggregate)))
2236 }
2237 AggregateFunction::First if !aggregate.order_by.is_empty() => Box::new(
2238 ValueAccumulator::new(ValueKind::First, aggregate_sort_specs(aggregate)),
2239 ),
2240 AggregateFunction::Last if !aggregate.order_by.is_empty() => Box::new(
2241 ValueAccumulator::new(ValueKind::Last, aggregate_sort_specs(aggregate)),
2242 ),
2243 _ => create_accumulator(&aggregate.function, aggregate.distinct),
2244 }
2245}
2246
2247pub fn exact_partial_aggregate_is_proven(aggregate: &AggregateExpr) -> bool {
2255 !aggregate.distinct
2256 && aggregate.order_by.is_empty()
2257 && matches!(
2258 aggregate.function,
2259 AggregateFunction::Count | AggregateFunction::Min | AggregateFunction::Max
2260 )
2261}
2262
2263pub fn merge_exact_aggregate_states(
2267 aggregates: &[AggregateExpr],
2268 partial_rows: impl IntoIterator<Item = Vec<Vec<SqlValue>>>,
2269) -> Result<Vec<SqlValue>> {
2270 if let Some(aggregate) = aggregates
2271 .iter()
2272 .find(|aggregate| !exact_partial_aggregate_is_proven(aggregate))
2273 {
2274 return Err(ExecutorError::InvalidOperation {
2275 operation: "distributed aggregate merge".into(),
2276 reason: format!(
2277 "{:?} requires ordered input replay rather than an exact partial merge",
2278 aggregate.function
2279 ),
2280 });
2281 }
2282
2283 let mut accumulators = aggregates
2284 .iter()
2285 .map(create_accumulator_for_aggregate)
2286 .collect::<Vec<_>>();
2287 for states in partial_rows {
2288 if states.len() != accumulators.len() {
2289 return Err(ExecutorError::InvalidOperation {
2290 operation: "distributed aggregate merge".into(),
2291 reason: format!(
2292 "partial state has {} aggregate(s), expected {}",
2293 states.len(),
2294 accumulators.len()
2295 ),
2296 });
2297 }
2298 for (accumulator, state) in accumulators.iter_mut().zip(states) {
2299 accumulator.merge(&state)?;
2300 }
2301 }
2302 accumulators
2303 .iter()
2304 .map(|accumulator| accumulator.finalize())
2305 .collect()
2306}
2307
2308const DEFAULT_GROUP_LIMIT: usize = 1_000_000;
2309const AGGREGATE_ACCUMULATOR_OVERHEAD_BYTES: u64 = 32;
2310
2311#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2313pub enum AggregateMode {
2314 Partial,
2316 Final,
2318 Single,
2320}
2321
2322struct AggregateGroup {
2323 key_values: Vec<SqlValue>,
2324 accumulators: Vec<Box<dyn Accumulator>>,
2325 grouping_id: Option<i64>,
2328}
2329
2330pub struct AggregateIterator<'a> {
2332 input: Box<dyn RowIterator + 'a>,
2333 group_keys: Vec<TypedExpr>,
2334 aggregates: Vec<AggregateExpr>,
2335 having: Option<TypedExpr>,
2336 mode: AggregateMode,
2337 hash_table: Option<HashMap<GroupKeyBytes, AggregateGroup>>,
2338 result_rows: Vec<Row>,
2339 index: usize,
2340 schema: Vec<ColumnMetadata>,
2341 group_limit: usize,
2342 memory_tracker: Option<MemoryTracker>,
2343 shared_group_counter: Option<Arc<AtomicUsize>>,
2344 grouping_sets: Option<Vec<u64>>,
2348}
2349
2350impl<'a> AggregateIterator<'a> {
2351 pub fn new(
2353 input: Box<dyn RowIterator + 'a>,
2354 group_keys: Vec<TypedExpr>,
2355 aggregates: Vec<AggregateExpr>,
2356 having: Option<TypedExpr>,
2357 schema: Vec<ColumnMetadata>,
2358 ) -> Self {
2359 Self {
2360 input,
2361 group_keys,
2362 aggregates,
2363 having,
2364 mode: AggregateMode::Single,
2365 hash_table: None,
2366 result_rows: Vec::new(),
2367 index: 0,
2368 schema,
2369 group_limit: DEFAULT_GROUP_LIMIT,
2370 memory_tracker: None,
2371 shared_group_counter: None,
2372 grouping_sets: None,
2373 }
2374 }
2375
2376 pub fn with_group_limit(mut self, limit: usize) -> Self {
2378 self.group_limit = limit;
2379 self
2380 }
2381
2382 pub fn with_grouping_sets(mut self, grouping_sets: Option<Vec<u64>>) -> Self {
2390 self.grouping_sets = grouping_sets;
2391 self
2392 }
2393
2394 pub fn with_mode(mut self, mode: AggregateMode) -> Self {
2396 self.mode = mode;
2397 self
2398 }
2399
2400 pub fn with_memory_policy(mut self, policy: Option<MemoryPolicy>) -> Self {
2402 self.memory_tracker = policy.map(MemoryTracker::new);
2403 self
2404 }
2405
2406 pub fn with_shared_group_counter(mut self, counter: Option<Arc<AtomicUsize>>) -> Self {
2408 self.shared_group_counter = counter;
2409 self
2410 }
2411
2412 fn build_hash_table(&mut self) -> Result<()> {
2413 let mut table: HashMap<GroupKeyBytes, AggregateGroup> = HashMap::new();
2414 let mut next_row_id = 0u64;
2415
2416 while let Some(result) = self.input.next_row() {
2417 let row = result?;
2418 let (key_values, key_bytes) = match self.mode {
2419 AggregateMode::Final => {
2420 let key_values = row
2421 .values
2422 .get(..self.group_keys.len())
2423 .ok_or_else(|| {
2424 invalid_aggregate_state(
2425 "aggregate",
2426 "partial state row is missing group key values",
2427 )
2428 })?
2429 .to_vec();
2430 let key_bytes = encode_group_key(&key_values)?;
2431 (key_values, key_bytes)
2432 }
2433 AggregateMode::Partial | AggregateMode::Single => {
2434 let ctx = EvalContext::new(&row.values);
2435 let mut key_values = Vec::with_capacity(self.group_keys.len());
2436 for expr in &self.group_keys {
2437 key_values.push(crate::executor::evaluator::evaluate(expr, &ctx)?);
2438 }
2439 let key_bytes = encode_group_key(&key_values)?;
2440 (key_values, key_bytes)
2441 }
2442 };
2443
2444 let variants: Vec<(Vec<SqlValue>, GroupKeyBytes, Option<i64>)> =
2449 if let Some(sets) = &self.grouping_sets {
2450 let key_count = self.group_keys.len();
2451 let mut variants = Vec::with_capacity(sets.len());
2452 for (set_id, mask) in sets.iter().enumerate() {
2453 let mut masked = key_values.clone();
2454 for (position, value) in masked.iter_mut().enumerate() {
2455 if (mask >> (key_count - 1 - position)) & 1 == 1 {
2456 *value = SqlValue::Null;
2457 }
2458 }
2459 let mut bytes = Vec::with_capacity(4 + key_bytes.len());
2460 bytes.extend_from_slice(&(set_id as u32).to_le_bytes());
2461 bytes.extend_from_slice(&encode_group_key(&masked)?);
2462 variants.push((masked, bytes, Some(*mask as i64)));
2463 }
2464 variants
2465 } else {
2466 vec![(key_values, key_bytes, None)]
2467 };
2468
2469 for (key_values, key_bytes, grouping_id) in variants {
2470 if !table.contains_key(&key_bytes) {
2471 self.reserve_group_slot(table.len())?;
2472 if let Some(tracker) = &mut self.memory_tracker {
2473 tracker
2474 .add_values(&key_values)
2475 .map_err(map_core_memory_error)?;
2476 tracker
2477 .add_bytes(
2478 self.aggregates.len() as u64 * AGGREGATE_ACCUMULATOR_OVERHEAD_BYTES,
2479 )
2480 .map_err(map_core_memory_error)?;
2481 }
2482 let accumulators = self
2483 .aggregates
2484 .iter()
2485 .map(|agg| {
2486 let mut aggregate = agg.clone();
2487 aggregate.distinct =
2488 matches!(self.mode, AggregateMode::Single) && agg.distinct;
2489 create_accumulator_for_aggregate(&aggregate)
2490 })
2491 .collect::<Vec<_>>();
2492 table.insert(
2493 key_bytes.clone(),
2494 AggregateGroup {
2495 key_values: key_values.clone(),
2496 accumulators,
2497 grouping_id,
2498 },
2499 );
2500 }
2501
2502 if let Some(group) = table.get_mut(&key_bytes) {
2503 match self.mode {
2504 AggregateMode::Final => {
2505 let mut offset = self.group_keys.len();
2506 for (idx, agg) in self.aggregates.iter().enumerate() {
2507 let arity = aggregate_state_types(agg).len();
2508 let state = row.values.get(offset..offset + arity).ok_or_else(|| {
2509 invalid_aggregate_state(
2510 "aggregate",
2511 format!(
2512 "partial state row is missing state values for aggregate {idx}"
2513 ),
2514 )
2515 })?;
2516 group.accumulators[idx].merge(state)?;
2517 offset += arity;
2518 }
2519 if offset != row.values.len() {
2520 return Err(invalid_aggregate_state(
2521 "aggregate",
2522 format!(
2523 "partial state row has {} trailing value(s)",
2524 row.values.len() - offset
2525 ),
2526 ));
2527 }
2528 }
2529 AggregateMode::Partial | AggregateMode::Single => {
2530 let ctx = EvalContext::new(&row.values);
2531 for (idx, agg) in self.aggregates.iter().enumerate() {
2532 if !aggregate_filter_accepts(agg, &ctx)? {
2536 continue;
2537 }
2538 let values = evaluate_aggregate_values(agg, &ctx)?;
2539 if let Some(tracker) = &mut self.memory_tracker
2540 && matches!(
2541 agg.function,
2542 AggregateFunction::GroupConcat { .. }
2543 | AggregateFunction::StringAgg { .. }
2544 | AggregateFunction::JsonGroupArray
2545 | AggregateFunction::JsonGroupObject
2546 | AggregateFunction::JsonbAgg
2547 | AggregateFunction::JsonbObjectAgg
2548 | AggregateFunction::PercentileDisc { .. }
2549 | AggregateFunction::PercentileCont { .. }
2550 | AggregateFunction::QuantileCont { .. }
2551 | AggregateFunction::Median
2552 | AggregateFunction::Mode
2553 )
2554 && let Some(value_ref) = values.first()
2555 {
2556 tracker
2557 .add_value(value_ref)
2558 .map_err(map_core_memory_error)?;
2559 }
2560 if agg.order_by.is_empty() {
2561 group.accumulators[idx].update_values(&values)?;
2562 } else {
2563 let keys = evaluate_sort_keys(agg, &ctx)?;
2564 group.accumulators[idx]
2565 .update_ordered_values(&values, &keys)?;
2566 }
2567 }
2568 }
2569 }
2570 }
2571 }
2572 }
2573
2574 if let Some(sets) = self.grouping_sets.clone() {
2575 let key_count = self.group_keys.len();
2579 let full_mask = if key_count == 0 {
2580 0
2581 } else {
2582 (1u64 << key_count) - 1
2583 };
2584 if table.is_empty() {
2585 for (set_id, mask) in sets.iter().enumerate() {
2586 if *mask != full_mask {
2587 continue;
2588 }
2589 if let Some(tracker) = &mut self.memory_tracker {
2590 tracker
2591 .add_bytes(
2592 self.aggregates.len() as u64 * AGGREGATE_ACCUMULATOR_OVERHEAD_BYTES,
2593 )
2594 .map_err(map_core_memory_error)?;
2595 }
2596 let accumulators = self
2597 .aggregates
2598 .iter()
2599 .map(|agg| {
2600 let mut aggregate = agg.clone();
2601 aggregate.distinct =
2602 matches!(self.mode, AggregateMode::Single) && agg.distinct;
2603 create_accumulator_for_aggregate(&aggregate)
2604 })
2605 .collect::<Vec<_>>();
2606 let key_values = vec![SqlValue::Null; key_count];
2607 let mut bytes = Vec::with_capacity(4);
2608 bytes.extend_from_slice(&(set_id as u32).to_le_bytes());
2609 bytes.extend_from_slice(&encode_group_key(&key_values)?);
2610 table.insert(
2611 bytes,
2612 AggregateGroup {
2613 key_values,
2614 accumulators,
2615 grouping_id: Some(*mask as i64),
2616 },
2617 );
2618 }
2619 }
2620 } else if table.is_empty() && self.group_keys.is_empty() {
2621 if let Some(tracker) = &mut self.memory_tracker {
2622 tracker
2623 .add_bytes(self.aggregates.len() as u64 * AGGREGATE_ACCUMULATOR_OVERHEAD_BYTES)
2624 .map_err(map_core_memory_error)?;
2625 }
2626 let accumulators = self
2627 .aggregates
2628 .iter()
2629 .map(|agg| {
2630 let mut aggregate = agg.clone();
2631 aggregate.distinct = matches!(self.mode, AggregateMode::Single) && agg.distinct;
2632 create_accumulator_for_aggregate(&aggregate)
2633 })
2634 .collect::<Vec<_>>();
2635 table.insert(
2636 Vec::new(),
2637 AggregateGroup {
2638 key_values: Vec::new(),
2639 accumulators,
2640 grouping_id: None,
2641 },
2642 );
2643 }
2644
2645 let mut rows = Vec::with_capacity(table.len());
2646 for group in table.values() {
2647 let mut values = Vec::with_capacity(self.group_keys.len() + self.aggregates.len() + 1);
2648 values.extend(group.key_values.iter().cloned());
2649 for acc in &group.accumulators {
2650 match self.mode {
2651 AggregateMode::Partial => values.extend(acc.state()?),
2652 AggregateMode::Final | AggregateMode::Single => values.push(acc.finalize()?),
2653 }
2654 }
2655 if let Some(grouping_id) = group.grouping_id {
2658 values.push(SqlValue::BigInt(grouping_id));
2659 }
2660 let row = Row::new(next_row_id, values);
2661 next_row_id += 1;
2662 if let Some(tracker) = &mut self.memory_tracker {
2663 tracker
2664 .add_row(&row.values)
2665 .map_err(map_core_memory_error)?;
2666 }
2667
2668 if self.mode != AggregateMode::Partial
2669 && let Some(having) = &self.having
2670 {
2671 let ctx = EvalContext::new(&row.values);
2672 match crate::executor::evaluator::evaluate(having, &ctx)? {
2673 SqlValue::Boolean(true) => rows.push(row),
2674 SqlValue::Boolean(false) | SqlValue::Null => {}
2675 other => {
2676 return Err(ExecutorError::Evaluation(
2677 crate::executor::EvaluationError::TypeMismatch {
2678 expected: "Boolean".into(),
2679 actual: other.type_name().into(),
2680 },
2681 ));
2682 }
2683 }
2684 } else {
2685 rows.push(row);
2686 }
2687 }
2688
2689 self.hash_table = Some(table);
2690 self.result_rows = rows;
2691 Ok(())
2692 }
2693
2694 fn reserve_group_slot(&self, local_group_count: usize) -> Result<()> {
2695 let next_count = if let Some(counter) = &self.shared_group_counter {
2696 counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + 1
2697 } else {
2698 local_group_count + 1
2699 };
2700 if next_count > self.group_limit {
2701 return Err(ExecutorError::ResourceExhausted {
2702 message: format!(
2703 "GROUP BY result exceeds memory limit (max groups: {})",
2704 self.group_limit
2705 ),
2706 });
2707 }
2708 Ok(())
2709 }
2710}
2711
2712impl<'a> RowIterator for AggregateIterator<'a> {
2713 fn next_row(&mut self) -> Option<Result<Row>> {
2714 if self.hash_table.is_none()
2715 && let Err(err) = self.build_hash_table()
2716 {
2717 return Some(Err(err));
2718 }
2719
2720 if self.index >= self.result_rows.len() {
2721 return None;
2722 }
2723 let row = self.result_rows[self.index].clone();
2724 self.index += 1;
2725 Some(Ok(row))
2726 }
2727
2728 fn schema(&self) -> &[ColumnMetadata] {
2729 &self.schema
2730 }
2731}
2732
2733pub struct StreamingAggregateIterator<'a> {
2735 input: Box<dyn RowIterator + 'a>,
2736 group_keys: Vec<TypedExpr>,
2737 aggregates: Vec<AggregateExpr>,
2738 having: Option<TypedExpr>,
2739 schema: Vec<ColumnMetadata>,
2740 current_key: Option<Vec<SqlValue>>,
2741 accumulators: Vec<Box<dyn Accumulator>>,
2742 pending_row: Option<Row>,
2743 finished: bool,
2744 next_row_id: u64,
2745 saw_row: bool,
2746}
2747
2748impl<'a> StreamingAggregateIterator<'a> {
2749 pub fn new(
2750 input: Box<dyn RowIterator + 'a>,
2751 group_keys: Vec<TypedExpr>,
2752 aggregates: Vec<AggregateExpr>,
2753 having: Option<TypedExpr>,
2754 schema: Vec<ColumnMetadata>,
2755 ) -> Self {
2756 Self {
2757 input,
2758 group_keys,
2759 aggregates,
2760 having,
2761 schema,
2762 current_key: None,
2763 accumulators: Vec::new(),
2764 pending_row: None,
2765 finished: false,
2766 next_row_id: 0,
2767 saw_row: false,
2768 }
2769 }
2770
2771 fn init_accumulators(&self) -> Vec<Box<dyn Accumulator>> {
2772 self.aggregates
2773 .iter()
2774 .map(create_accumulator_for_aggregate)
2775 .collect()
2776 }
2777
2778 fn update_accumulators(&mut self, ctx: &EvalContext<'_>) -> Result<()> {
2779 for (idx, agg) in self.aggregates.iter().enumerate() {
2780 if !aggregate_filter_accepts(agg, ctx)? {
2781 continue;
2782 }
2783 let values = evaluate_aggregate_values(agg, ctx)?;
2784 if agg.order_by.is_empty() {
2785 self.accumulators[idx].update_values(&values)?;
2786 } else {
2787 let keys = evaluate_sort_keys(agg, ctx)?;
2788 self.accumulators[idx].update_ordered_values(&values, &keys)?;
2789 }
2790 }
2791 Ok(())
2792 }
2793
2794 fn finalize_group(&mut self, key_values: &[SqlValue]) -> Result<Option<Row>> {
2795 let mut values = Vec::with_capacity(self.group_keys.len() + self.aggregates.len());
2796 values.extend(key_values.iter().cloned());
2797 for acc in &self.accumulators {
2798 values.push(acc.finalize()?);
2799 }
2800 let row = Row::new(self.next_row_id, values);
2801 self.next_row_id = self.next_row_id.saturating_add(1);
2802
2803 if let Some(having) = &self.having {
2804 let ctx = EvalContext::new(&row.values);
2805 match crate::executor::evaluator::evaluate(having, &ctx)? {
2806 SqlValue::Boolean(true) => Ok(Some(row)),
2807 SqlValue::Boolean(false) | SqlValue::Null => Ok(None),
2808 other => Err(ExecutorError::Evaluation(
2809 crate::executor::EvaluationError::TypeMismatch {
2810 expected: "Boolean".into(),
2811 actual: other.type_name().into(),
2812 },
2813 )),
2814 }
2815 } else {
2816 Ok(Some(row))
2817 }
2818 }
2819}
2820
2821impl<'a> RowIterator for StreamingAggregateIterator<'a> {
2822 fn next_row(&mut self) -> Option<Result<Row>> {
2823 if let Some(row) = self.pending_row.take() {
2824 return Some(Ok(row));
2825 }
2826 if self.finished {
2827 return None;
2828 }
2829
2830 loop {
2831 match self.input.next_row() {
2832 Some(Ok(row)) => {
2833 self.saw_row = true;
2834 let ctx = EvalContext::new(&row.values);
2835 let mut key_values = Vec::with_capacity(self.group_keys.len());
2836 for expr in &self.group_keys {
2837 match crate::executor::evaluator::evaluate(expr, &ctx) {
2838 Ok(value) => key_values.push(value),
2839 Err(err) => return Some(Err(err)),
2840 }
2841 }
2842
2843 match &self.current_key {
2844 None => {
2845 self.current_key = Some(key_values);
2846 self.accumulators = self.init_accumulators();
2847 if let Err(err) = self.update_accumulators(&ctx) {
2848 return Some(Err(err));
2849 }
2850 }
2851 Some(current_key) if *current_key == key_values => {
2852 if let Err(err) = self.update_accumulators(&ctx) {
2853 return Some(Err(err));
2854 }
2855 }
2856 Some(_) => {
2857 let current_key = self.current_key.clone().unwrap_or_default();
2858 let output = match self.finalize_group(¤t_key) {
2859 Ok(value) => value,
2860 Err(err) => return Some(Err(err)),
2861 };
2862 self.current_key = Some(key_values);
2863 self.accumulators = self.init_accumulators();
2864 if let Err(err) = self.update_accumulators(&ctx) {
2865 return Some(Err(err));
2866 }
2867 if let Some(row) = output {
2868 return Some(Ok(row));
2869 }
2870 }
2871 }
2872 }
2873 Some(Err(err)) => return Some(Err(err)),
2874 None => {
2875 self.finished = true;
2876 if let Some(current_key) = self.current_key.take() {
2877 return match self.finalize_group(¤t_key) {
2878 Ok(Some(row)) => Some(Ok(row)),
2879 Ok(None) => None,
2880 Err(err) => Some(Err(err)),
2881 };
2882 }
2883
2884 if self.group_keys.is_empty() && !self.saw_row {
2885 self.accumulators = self.init_accumulators();
2886 return match self.finalize_group(&[]) {
2887 Ok(Some(row)) => Some(Ok(row)),
2888 Ok(None) => None,
2889 Err(err) => Some(Err(err)),
2890 };
2891 }
2892
2893 return None;
2894 }
2895 }
2896 }
2897 }
2898
2899 fn schema(&self) -> &[ColumnMetadata] {
2900 &self.schema
2901 }
2902}
2903
2904fn aggregate_state_types(agg: &AggregateExpr) -> Vec<ResolvedType> {
2905 match &agg.function {
2906 AggregateFunction::Count => vec![ResolvedType::BigInt],
2907 AggregateFunction::Sum => vec![agg.result_type.clone()],
2908 AggregateFunction::Total => vec![ResolvedType::Double],
2909 AggregateFunction::Avg => vec![agg.result_type.clone(), ResolvedType::BigInt],
2910 AggregateFunction::Min | AggregateFunction::Max => vec![agg.result_type.clone()],
2911 AggregateFunction::GroupConcat { .. } | AggregateFunction::StringAgg { .. } => {
2912 vec![ResolvedType::Text, ResolvedType::Text]
2913 }
2914 AggregateFunction::ArrayAgg => vec![agg.result_type.clone()],
2915 AggregateFunction::JsonGroupArray
2916 | AggregateFunction::JsonGroupObject
2917 | AggregateFunction::JsonbAgg
2918 | AggregateFunction::JsonbObjectAgg => {
2919 vec![ResolvedType::Text]
2920 }
2921 AggregateFunction::PercentileDisc { .. } => vec![agg.result_type.clone()],
2924 AggregateFunction::PercentileCont { .. }
2925 | AggregateFunction::QuantileCont { .. }
2926 | AggregateFunction::Median
2927 | AggregateFunction::Mode => vec![agg.result_type.clone()],
2928 AggregateFunction::Variance { .. }
2929 | AggregateFunction::Stddev { .. }
2930 | AggregateFunction::Covariance { .. }
2931 | AggregateFunction::Corr
2932 | AggregateFunction::RegrCount
2933 | AggregateFunction::RegrAvgX
2934 | AggregateFunction::RegrAvgY
2935 | AggregateFunction::RegrSxx
2936 | AggregateFunction::RegrSyy
2937 | AggregateFunction::RegrSxy
2938 | AggregateFunction::RegrSlope
2939 | AggregateFunction::RegrIntercept
2940 | AggregateFunction::RegrR2 => vec![
2941 ResolvedType::BigInt,
2942 ResolvedType::Double,
2943 ResolvedType::Double,
2944 ResolvedType::Double,
2945 ResolvedType::Double,
2946 ResolvedType::Double,
2947 ],
2948 AggregateFunction::AnyValue
2949 | AggregateFunction::First
2950 | AggregateFunction::Last
2951 | AggregateFunction::ArgMin
2952 | AggregateFunction::ArgMax
2953 | AggregateFunction::BitAnd
2954 | AggregateFunction::BitOr
2955 | AggregateFunction::BitXor
2956 | AggregateFunction::BoolAnd
2957 | AggregateFunction::BoolOr => vec![agg.result_type.clone()],
2958 }
2959}
2960
2961fn aggregate_filter_accepts(agg: &AggregateExpr, ctx: &EvalContext<'_>) -> Result<bool> {
2964 let Some(filter) = &agg.filter else {
2965 return Ok(true);
2966 };
2967 match crate::executor::evaluator::evaluate(filter, ctx)? {
2968 SqlValue::Boolean(true) => Ok(true),
2969 SqlValue::Boolean(false) | SqlValue::Null => Ok(false),
2970 other => Err(ExecutorError::Evaluation(
2971 crate::executor::EvaluationError::TypeMismatch {
2972 expected: "Boolean".into(),
2973 actual: other.type_name().into(),
2974 },
2975 )),
2976 }
2977}
2978
2979fn evaluate_sort_keys(agg: &AggregateExpr, ctx: &EvalContext<'_>) -> Result<Vec<SqlValue>> {
2981 agg.order_by
2982 .iter()
2983 .map(|sort| crate::executor::evaluator::evaluate(&sort.expr, ctx))
2984 .collect()
2985}
2986
2987fn evaluate_aggregate_values(agg: &AggregateExpr, ctx: &EvalContext<'_>) -> Result<Vec<SqlValue>> {
2988 agg.arg
2989 .iter()
2990 .chain(&agg.extra_args)
2991 .map(|expr| crate::executor::evaluator::evaluate(expr, ctx))
2992 .collect()
2993}
2994
2995pub fn build_aggregate_schema(
2997 group_keys: &[TypedExpr],
2998 aggregates: &[AggregateExpr],
2999) -> Vec<ColumnMetadata> {
3000 let mut schema = Vec::new();
3001 for (idx, key) in group_keys.iter().enumerate() {
3002 let name = match &key.kind {
3003 crate::planner::typed_expr::TypedExprKind::ColumnRef { column, .. } => column.clone(),
3004 _ => format!("group_{idx}"),
3005 };
3006 schema.push(ColumnMetadata::new(name, key.resolved_type.clone()));
3007 }
3008 for (idx, agg) in aggregates.iter().enumerate() {
3009 let name = match &agg.function {
3010 AggregateFunction::Count => format!("count_{idx}"),
3011 AggregateFunction::Sum => format!("sum_{idx}"),
3012 AggregateFunction::Total => format!("total_{idx}"),
3013 AggregateFunction::Avg => format!("avg_{idx}"),
3014 AggregateFunction::Min => format!("min_{idx}"),
3015 AggregateFunction::Max => format!("max_{idx}"),
3016 AggregateFunction::GroupConcat { .. } => format!("group_concat_{idx}"),
3017 AggregateFunction::StringAgg { .. } => format!("string_agg_{idx}"),
3018 AggregateFunction::ArrayAgg => format!("array_agg_{idx}"),
3019 AggregateFunction::JsonGroupArray => format!("json_group_array_{idx}"),
3020 AggregateFunction::JsonGroupObject => format!("json_group_object_{idx}"),
3021 AggregateFunction::JsonbAgg => format!("jsonb_agg_{idx}"),
3022 AggregateFunction::JsonbObjectAgg => format!("jsonb_object_agg_{idx}"),
3023 AggregateFunction::PercentileDisc { .. } => format!("percentile_disc_{idx}"),
3024 AggregateFunction::PercentileCont { .. } => format!("percentile_cont_{idx}"),
3025 AggregateFunction::QuantileCont { .. } => format!("quantile_cont_{idx}"),
3026 AggregateFunction::Variance { sample } => {
3027 format!("var_{}_{idx}", if *sample { "samp" } else { "pop" })
3028 }
3029 AggregateFunction::Stddev { sample } => {
3030 format!("stddev_{}_{idx}", if *sample { "samp" } else { "pop" })
3031 }
3032 AggregateFunction::Covariance { sample } => {
3033 format!("covar_{}_{idx}", if *sample { "samp" } else { "pop" })
3034 }
3035 AggregateFunction::Corr => format!("corr_{idx}"),
3036 AggregateFunction::Median => format!("median_{idx}"),
3037 AggregateFunction::Mode => format!("mode_{idx}"),
3038 AggregateFunction::RegrCount => format!("regr_count_{idx}"),
3039 AggregateFunction::RegrAvgX => format!("regr_avgx_{idx}"),
3040 AggregateFunction::RegrAvgY => format!("regr_avgy_{idx}"),
3041 AggregateFunction::RegrSxx => format!("regr_sxx_{idx}"),
3042 AggregateFunction::RegrSyy => format!("regr_syy_{idx}"),
3043 AggregateFunction::RegrSxy => format!("regr_sxy_{idx}"),
3044 AggregateFunction::RegrSlope => format!("regr_slope_{idx}"),
3045 AggregateFunction::RegrIntercept => format!("regr_intercept_{idx}"),
3046 AggregateFunction::RegrR2 => format!("regr_r2_{idx}"),
3047 AggregateFunction::AnyValue => format!("any_value_{idx}"),
3048 AggregateFunction::First => format!("first_{idx}"),
3049 AggregateFunction::Last => format!("last_{idx}"),
3050 AggregateFunction::ArgMin => format!("arg_min_{idx}"),
3051 AggregateFunction::ArgMax => format!("arg_max_{idx}"),
3052 AggregateFunction::BitAnd => format!("bit_and_{idx}"),
3053 AggregateFunction::BitOr => format!("bit_or_{idx}"),
3054 AggregateFunction::BitXor => format!("bit_xor_{idx}"),
3055 AggregateFunction::BoolAnd => format!("bool_and_{idx}"),
3056 AggregateFunction::BoolOr => format!("bool_or_{idx}"),
3057 };
3058 schema.push(ColumnMetadata::new(name, agg.result_type.clone()));
3059 }
3060 schema
3061}
3062
3063pub fn build_partial_aggregate_schema(
3065 group_keys: &[TypedExpr],
3066 aggregates: &[AggregateExpr],
3067) -> Vec<ColumnMetadata> {
3068 let mut schema = Vec::new();
3069 for (idx, key) in group_keys.iter().enumerate() {
3070 let name = match &key.kind {
3071 crate::planner::typed_expr::TypedExprKind::ColumnRef { column, .. } => column.clone(),
3072 _ => format!("group_{idx}"),
3073 };
3074 schema.push(ColumnMetadata::new(name, key.resolved_type.clone()));
3075 }
3076 for (agg_idx, agg) in aggregates.iter().enumerate() {
3077 for (state_idx, state_type) in aggregate_state_types(agg).into_iter().enumerate() {
3078 schema.push(ColumnMetadata::new(
3079 format!("__agg{agg_idx}_state{state_idx}"),
3080 state_type,
3081 ));
3082 }
3083 }
3084 schema
3085}
3086
3087pub fn should_use_single_for_parallel(parallelism: usize, aggregates: &[AggregateExpr]) -> bool {
3093 parallelism <= 1
3094 || aggregates.iter().any(|agg| {
3095 agg.distinct
3096 || !agg.order_by.is_empty()
3097 || matches!(agg.function, AggregateFunction::PercentileDisc { .. })
3098 || matches!(
3099 agg.function,
3100 AggregateFunction::PercentileCont { .. }
3101 | AggregateFunction::QuantileCont { .. }
3102 | AggregateFunction::Median
3103 | AggregateFunction::Mode
3104 | AggregateFunction::AnyValue
3105 | AggregateFunction::First
3106 | AggregateFunction::Last
3107 | AggregateFunction::ArgMin
3108 | AggregateFunction::ArgMax
3109 )
3110 })
3111}
3112
3113fn collect_iterator_rows(iter: &mut dyn RowIterator) -> Result<Vec<Row>> {
3114 let mut rows = Vec::new();
3115 while let Some(result) = iter.next_row() {
3116 rows.push(result?);
3117 }
3118 Ok(rows)
3119}
3120
3121struct ChainRowIterator<'a> {
3122 prefix: std::vec::IntoIter<Row>,
3123 tail: Box<dyn RowIterator + 'a>,
3124 schema: Vec<ColumnMetadata>,
3125}
3126
3127impl<'a> ChainRowIterator<'a> {
3128 fn new(prefix: Vec<Row>, tail: Box<dyn RowIterator + 'a>, schema: Vec<ColumnMetadata>) -> Self {
3129 Self {
3130 prefix: prefix.into_iter(),
3131 tail,
3132 schema,
3133 }
3134 }
3135}
3136
3137impl RowIterator for ChainRowIterator<'_> {
3138 fn next_row(&mut self) -> Option<Result<Row>> {
3139 if let Some(row) = self.prefix.next() {
3140 return Some(Ok(row));
3141 }
3142 self.tail.next_row()
3143 }
3144
3145 fn schema(&self) -> &[ColumnMetadata] {
3146 &self.schema
3147 }
3148}
3149
3150fn estimate_row_bytes(row: &Row) -> u64 {
3151 row.values.iter().map(ByteSized::estimated_bytes).sum()
3152}
3153
3154fn split_contiguous_partitions(rows: Vec<Row>, parallelism: usize) -> Vec<Vec<Row>> {
3155 let requested = parallelism.max(1);
3156 if rows.is_empty() {
3157 return (0..requested).map(|_| Vec::new()).collect();
3158 }
3159 let partitions = requested.min(rows.len());
3160 let total = rows.len();
3161 let mut tail = rows;
3162 let mut output = Vec::with_capacity(partitions);
3163 for partition in (0..partitions).rev() {
3164 let start = partition * total / partitions;
3165 output.push(tail.split_off(start));
3166 }
3167 output.reverse();
3168 output
3169}
3170
3171#[allow(clippy::too_many_arguments)]
3172fn execute_partial_partition(
3173 partition_index: usize,
3174 rows: Vec<Row>,
3175 input_schema: Vec<ColumnMetadata>,
3176 group_keys: Vec<TypedExpr>,
3177 aggregates: Vec<AggregateExpr>,
3178 partial_schema: Vec<ColumnMetadata>,
3179 group_limit: usize,
3180 shared_group_counter: Arc<AtomicUsize>,
3181 shared_memory_counter: Arc<AtomicU64>,
3182 memory_limit: Option<u64>,
3183) -> Result<(usize, Vec<Row>)> {
3184 let input = VecIterator::new(rows, input_schema);
3185 let mut iter = AggregateIterator::new(
3186 Box::new(input),
3187 group_keys,
3188 aggregates,
3189 None,
3190 partial_schema,
3191 )
3192 .with_mode(AggregateMode::Partial)
3193 .with_group_limit(group_limit)
3194 .with_shared_group_counter(Some(shared_group_counter));
3195 let rows = collect_iterator_rows(&mut iter)?;
3196 for row in &rows {
3197 let used = shared_memory_counter
3198 .fetch_add(estimate_row_bytes(row), std::sync::atomic::Ordering::SeqCst)
3199 .saturating_add(estimate_row_bytes(row));
3200 if let Some(limit) = memory_limit
3201 && used > limit
3202 {
3203 return Err(ExecutorError::ResourceExhausted {
3204 message: format!(
3205 "parallel aggregate memory limit exceeded: {used} bytes (limit {limit})"
3206 ),
3207 });
3208 }
3209 }
3210 Ok((partition_index, rows))
3211}
3212
3213fn recv_partition_results(
3214 receiver: std::sync::mpsc::Receiver<Result<(usize, Vec<Row>)>>,
3215 expected: usize,
3216) -> Result<Vec<(usize, Vec<Row>)>> {
3217 let mut outputs = Vec::with_capacity(expected);
3218 for _ in 0..expected {
3219 let result = receiver
3220 .recv()
3221 .map_err(|err| ExecutorError::InvalidOperation {
3222 operation: "parallel aggregate".into(),
3223 reason: format!("partition worker failed to report result: {err}"),
3224 })?;
3225 outputs.push(result?);
3226 }
3227 outputs.sort_by_key(|(idx, _)| *idx);
3228 Ok(outputs)
3229}
3230
3231#[cfg(feature = "tokio")]
3232#[allow(clippy::too_many_arguments)]
3233fn run_partial_partitions(
3234 partitions: Vec<Vec<Row>>,
3235 input_schema: Vec<ColumnMetadata>,
3236 group_keys: Vec<TypedExpr>,
3237 aggregates: Vec<AggregateExpr>,
3238 partial_schema: Vec<ColumnMetadata>,
3239 group_limit: usize,
3240 shared_group_counter: Arc<AtomicUsize>,
3241 shared_memory_counter: Arc<AtomicU64>,
3242 memory_limit: Option<u64>,
3243) -> Result<Vec<(usize, Vec<Row>)>> {
3244 if let Ok(handle) = tokio::runtime::Handle::try_current() {
3245 let expected = partitions.len();
3246 let (sender, receiver) = std::sync::mpsc::channel();
3247 for (partition_index, rows) in partitions.into_iter().enumerate() {
3248 let sender = sender.clone();
3249 let input_schema = input_schema.clone();
3250 let group_keys = group_keys.clone();
3251 let aggregates = aggregates.clone();
3252 let partial_schema = partial_schema.clone();
3253 let shared_group_counter = Arc::clone(&shared_group_counter);
3254 let shared_memory_counter = Arc::clone(&shared_memory_counter);
3255 handle.spawn_blocking(move || {
3256 let result = execute_partial_partition(
3257 partition_index,
3258 rows,
3259 input_schema,
3260 group_keys,
3261 aggregates,
3262 partial_schema,
3263 group_limit,
3264 shared_group_counter,
3265 shared_memory_counter,
3266 memory_limit,
3267 );
3268 let _ = sender.send(result);
3269 });
3270 }
3271 drop(sender);
3272 return recv_partition_results(receiver, expected);
3273 }
3274
3275 run_partial_partitions_on_threads(
3276 partitions,
3277 input_schema,
3278 group_keys,
3279 aggregates,
3280 partial_schema,
3281 group_limit,
3282 shared_group_counter,
3283 shared_memory_counter,
3284 memory_limit,
3285 )
3286}
3287
3288#[cfg(not(feature = "tokio"))]
3289#[allow(clippy::too_many_arguments)]
3290fn run_partial_partitions(
3291 partitions: Vec<Vec<Row>>,
3292 input_schema: Vec<ColumnMetadata>,
3293 group_keys: Vec<TypedExpr>,
3294 aggregates: Vec<AggregateExpr>,
3295 partial_schema: Vec<ColumnMetadata>,
3296 group_limit: usize,
3297 shared_group_counter: Arc<AtomicUsize>,
3298 shared_memory_counter: Arc<AtomicU64>,
3299 memory_limit: Option<u64>,
3300) -> Result<Vec<(usize, Vec<Row>)>> {
3301 run_partial_partitions_on_threads(
3302 partitions,
3303 input_schema,
3304 group_keys,
3305 aggregates,
3306 partial_schema,
3307 group_limit,
3308 shared_group_counter,
3309 shared_memory_counter,
3310 memory_limit,
3311 )
3312}
3313
3314#[allow(clippy::too_many_arguments)]
3315fn run_partial_partitions_on_threads(
3316 partitions: Vec<Vec<Row>>,
3317 input_schema: Vec<ColumnMetadata>,
3318 group_keys: Vec<TypedExpr>,
3319 aggregates: Vec<AggregateExpr>,
3320 partial_schema: Vec<ColumnMetadata>,
3321 group_limit: usize,
3322 shared_group_counter: Arc<AtomicUsize>,
3323 shared_memory_counter: Arc<AtomicU64>,
3324 memory_limit: Option<u64>,
3325) -> Result<Vec<(usize, Vec<Row>)>> {
3326 let expected = partitions.len();
3327 let (sender, receiver) = std::sync::mpsc::channel();
3328 std::thread::scope(|scope| {
3329 for (partition_index, rows) in partitions.into_iter().enumerate() {
3330 let sender = sender.clone();
3331 let input_schema = input_schema.clone();
3332 let group_keys = group_keys.clone();
3333 let aggregates = aggregates.clone();
3334 let partial_schema = partial_schema.clone();
3335 let shared_group_counter = Arc::clone(&shared_group_counter);
3336 let shared_memory_counter = Arc::clone(&shared_memory_counter);
3337 scope.spawn(move || {
3338 let result = execute_partial_partition(
3339 partition_index,
3340 rows,
3341 input_schema,
3342 group_keys,
3343 aggregates,
3344 partial_schema,
3345 group_limit,
3346 shared_group_counter,
3347 shared_memory_counter,
3348 memory_limit,
3349 );
3350 let _ = sender.send(result);
3351 });
3352 }
3353 });
3354 drop(sender);
3355 recv_partition_results(receiver, expected)
3356}
3357
3358pub fn execute_parallel_aggregate_rows<'a>(
3360 input: Box<dyn RowIterator + 'a>,
3361 group_keys: Vec<TypedExpr>,
3362 aggregates: Vec<AggregateExpr>,
3363 having: Option<TypedExpr>,
3364 final_schema: Vec<ColumnMetadata>,
3365 parallelism: usize,
3366) -> Result<Vec<Row>> {
3367 execute_parallel_aggregate_rows_with_policy(
3368 input,
3369 group_keys,
3370 aggregates,
3371 having,
3372 final_schema,
3373 parallelism,
3374 None,
3375 DEFAULT_GROUP_LIMIT,
3376 )
3377}
3378
3379#[allow(clippy::too_many_arguments)]
3381pub fn execute_parallel_aggregate_rows_with_policy<'a>(
3382 mut input: Box<dyn RowIterator + 'a>,
3383 group_keys: Vec<TypedExpr>,
3384 aggregates: Vec<AggregateExpr>,
3385 having: Option<TypedExpr>,
3386 final_schema: Vec<ColumnMetadata>,
3387 parallelism: usize,
3388 memory: Option<MemoryPolicy>,
3389 group_limit: usize,
3390) -> Result<Vec<Row>> {
3391 if parallelism <= 1 {
3392 return execute_single_aggregate_rows(
3393 input,
3394 group_keys,
3395 aggregates,
3396 having,
3397 final_schema,
3398 memory,
3399 group_limit,
3400 );
3401 }
3402
3403 let input_schema = input.schema().to_vec();
3404 let mut input_rows = Vec::new();
3405 let mut materialized_bytes = 0u64;
3406 let materialize_threshold = memory
3407 .as_ref()
3408 .and_then(MemoryPolicy::limit_bytes)
3409 .map(|limit| (limit / 2).max(1));
3410
3411 while let Some(result) = input.next_row() {
3412 let row = result?;
3413 let row_bytes = materialize_threshold.map(|_| estimate_row_bytes(&row));
3414 if let (Some(threshold), Some(row_bytes)) = (materialize_threshold, row_bytes)
3415 && materialized_bytes.saturating_add(row_bytes) > threshold
3416 {
3417 input_rows.push(row);
3418 let chained = ChainRowIterator::new(input_rows, input, input_schema.clone());
3419 return execute_single_aggregate_rows(
3420 Box::new(chained),
3421 group_keys,
3422 aggregates,
3423 having,
3424 final_schema,
3425 memory,
3426 group_limit,
3427 );
3428 }
3429 if let Some(row_bytes) = row_bytes {
3430 materialized_bytes = materialized_bytes.saturating_add(row_bytes);
3431 }
3432 input_rows.push(row);
3433 }
3434
3435 let fallback_rows = if memory.is_some() || group_limit < input_rows.len() {
3436 Some(input_rows.clone())
3437 } else {
3438 None
3439 };
3440 let result = execute_parallel_aggregate_rows_from_materialized(
3441 input_rows,
3442 input_schema.clone(),
3443 group_keys.clone(),
3444 aggregates.clone(),
3445 having.clone(),
3446 final_schema.clone(),
3447 parallelism,
3448 group_limit,
3449 materialized_bytes,
3450 memory.as_ref().and_then(MemoryPolicy::limit_bytes),
3451 );
3452 match result {
3453 Ok(rows) => Ok(rows),
3454 Err(ExecutorError::ResourceExhausted { .. }) => {
3455 if let Some(fallback_rows) = fallback_rows {
3456 execute_single_aggregate_rows(
3457 Box::new(VecIterator::new(fallback_rows, input_schema)),
3458 group_keys,
3459 aggregates,
3460 having,
3461 final_schema,
3462 memory,
3463 group_limit,
3464 )
3465 } else {
3466 Err(ExecutorError::ResourceExhausted {
3467 message: format!(
3468 "parallel aggregate exceeded group limit {group_limit}; no fallback rows retained"
3469 ),
3470 })
3471 }
3472 }
3473 Err(err) => Err(err),
3474 }
3475}
3476
3477#[allow(clippy::too_many_arguments)]
3478fn execute_parallel_aggregate_rows_from_materialized(
3479 input_rows: Vec<Row>,
3480 input_schema: Vec<ColumnMetadata>,
3481 group_keys: Vec<TypedExpr>,
3482 aggregates: Vec<AggregateExpr>,
3483 having: Option<TypedExpr>,
3484 final_schema: Vec<ColumnMetadata>,
3485 parallelism: usize,
3486 group_limit: usize,
3487 materialized_bytes: u64,
3488 memory_limit: Option<u64>,
3489) -> Result<Vec<Row>> {
3490 let partial_schema = build_partial_aggregate_schema(&group_keys, &aggregates);
3491 let partitions = split_contiguous_partitions(input_rows, parallelism);
3492 let shared_group_counter = Arc::new(AtomicUsize::new(0));
3493 let shared_memory_counter = Arc::new(AtomicU64::new(materialized_bytes));
3494 let partial_results = run_partial_partitions(
3495 partitions,
3496 input_schema,
3497 group_keys.clone(),
3498 aggregates.clone(),
3499 partial_schema.clone(),
3500 group_limit,
3501 shared_group_counter,
3502 shared_memory_counter,
3503 memory_limit,
3504 )?;
3505
3506 let partial_rows = partial_results
3507 .into_iter()
3508 .flat_map(|(_, rows)| rows)
3509 .collect::<Vec<_>>();
3510 let final_input = VecIterator::new(partial_rows, partial_schema);
3511 let mut final_iter = AggregateIterator::new(
3512 Box::new(final_input),
3513 group_keys,
3514 aggregates,
3515 having,
3516 final_schema,
3517 )
3518 .with_mode(AggregateMode::Final)
3519 .with_group_limit(group_limit);
3520 collect_iterator_rows(&mut final_iter)
3521}
3522
3523fn execute_single_aggregate_rows<'a>(
3524 input: Box<dyn RowIterator + 'a>,
3525 group_keys: Vec<TypedExpr>,
3526 aggregates: Vec<AggregateExpr>,
3527 having: Option<TypedExpr>,
3528 final_schema: Vec<ColumnMetadata>,
3529 memory: Option<MemoryPolicy>,
3530 group_limit: usize,
3531) -> Result<Vec<Row>> {
3532 let mut iter = AggregateIterator::new(input, group_keys, aggregates, having, final_schema)
3533 .with_group_limit(group_limit)
3534 .with_memory_policy(memory);
3535 collect_iterator_rows(&mut iter)
3536}
3537
3538#[cfg(test)]
3539mod tests {
3540 use super::*;
3541 use crate::ast::span::Span;
3542 use crate::executor::memory::SpillPolicy;
3543 use crate::planner::typed_expr::TypedExprKind;
3544
3545 fn apply_values(acc: &mut dyn Accumulator, values: &[Option<SqlValue>]) {
3546 for value in values {
3547 acc.update(value.clone()).unwrap();
3548 }
3549 }
3550
3551 fn single_result(
3552 make_accumulator: impl Fn() -> Box<dyn Accumulator>,
3553 partitions: &[Vec<Option<SqlValue>>],
3554 ) -> SqlValue {
3555 let mut acc = make_accumulator();
3556 for partition in partitions {
3557 apply_values(acc.as_mut(), partition);
3558 }
3559 acc.finalize().unwrap()
3560 }
3561
3562 fn merged_result(
3563 make_partial: impl Fn() -> Box<dyn Accumulator>,
3564 make_final: impl Fn() -> Box<dyn Accumulator>,
3565 partitions: &[Vec<Option<SqlValue>>],
3566 merge_order: &[usize],
3567 ) -> SqlValue {
3568 let states = partitions
3569 .iter()
3570 .map(|partition| {
3571 let mut acc = make_partial();
3572 apply_values(acc.as_mut(), partition);
3573 acc.state().unwrap()
3574 })
3575 .collect::<Vec<_>>();
3576
3577 let mut final_acc = make_final();
3578 for idx in merge_order {
3579 final_acc.merge(&states[*idx]).unwrap();
3580 }
3581 final_acc.finalize().unwrap()
3582 }
3583
3584 fn assert_single_equals_merged(
3585 make_accumulator: impl Fn() -> Box<dyn Accumulator> + Copy,
3586 partitions: Vec<Vec<Option<SqlValue>>>,
3587 ) {
3588 let merge_order = (0..partitions.len()).collect::<Vec<_>>();
3589 let single = single_result(make_accumulator, &partitions);
3590 let merged = merged_result(
3591 make_accumulator,
3592 make_accumulator,
3593 &partitions,
3594 &merge_order,
3595 );
3596 assert_eq!(single, merged);
3597 }
3598
3599 fn assert_merge_order_invariant(
3600 make_accumulator: impl Fn() -> Box<dyn Accumulator> + Copy,
3601 partitions: Vec<Vec<Option<SqlValue>>>,
3602 merge_orders: &[Vec<usize>],
3603 ) {
3604 let single = single_result(make_accumulator, &partitions);
3605 for order in merge_orders {
3606 let merged = merged_result(make_accumulator, make_accumulator, &partitions, order);
3607 assert_eq!(single, merged, "merge order {order:?}");
3608 }
3609 }
3610
3611 fn column_expr(index: usize, name: &str, resolved_type: ResolvedType) -> TypedExpr {
3612 TypedExpr {
3613 kind: TypedExprKind::ColumnRef {
3614 table: "t".into(),
3615 column: name.into(),
3616 column_index: index,
3617 },
3618 resolved_type,
3619 span: Span::default(),
3620 }
3621 }
3622
3623 fn sample_aggregate_schema() -> Vec<ColumnMetadata> {
3624 vec![
3625 ColumnMetadata::new("category", ResolvedType::Text),
3626 ColumnMetadata::new("price", ResolvedType::Double),
3627 ColumnMetadata::new("label", ResolvedType::Text),
3628 ]
3629 }
3630
3631 fn sample_aggregate_rows() -> Vec<Row> {
3632 vec![
3633 Row::new(
3634 0,
3635 vec![
3636 SqlValue::Text("book".into()),
3637 SqlValue::Double(10.0),
3638 SqlValue::Text("a".into()),
3639 ],
3640 ),
3641 Row::new(
3642 1,
3643 vec![
3644 SqlValue::Text("book".into()),
3645 SqlValue::Double(15.0),
3646 SqlValue::Text("b".into()),
3647 ],
3648 ),
3649 Row::new(
3650 2,
3651 vec![
3652 SqlValue::Text("game".into()),
3653 SqlValue::Double(20.0),
3654 SqlValue::Text("c".into()),
3655 ],
3656 ),
3657 Row::new(
3658 3,
3659 vec![
3660 SqlValue::Text("book".into()),
3661 SqlValue::Null,
3662 SqlValue::Text("a".into()),
3663 ],
3664 ),
3665 Row::new(
3666 4,
3667 vec![
3668 SqlValue::Text("toy".into()),
3669 SqlValue::Double(3.0),
3670 SqlValue::Text("d".into()),
3671 ],
3672 ),
3673 ]
3674 }
3675
3676 fn sample_aggregates() -> Vec<AggregateExpr> {
3677 let price = column_expr(1, "price", ResolvedType::Double);
3678 let label = column_expr(2, "label", ResolvedType::Text);
3679 vec![
3680 AggregateExpr::count_star(),
3681 AggregateExpr::sum(price.clone()),
3682 AggregateExpr::avg(price),
3683 AggregateExpr {
3684 function: AggregateFunction::GroupConcat {
3685 separator: Some("|".into()),
3686 },
3687 arg: Some(label),
3688 extra_args: Vec::new(),
3689 distinct: false,
3690 result_type: ResolvedType::Text,
3691 filter: None,
3692 order_by: Vec::new(),
3693 },
3694 ]
3695 }
3696
3697 fn collect_single_aggregate(
3698 group_keys: Vec<TypedExpr>,
3699 aggregates: Vec<AggregateExpr>,
3700 ) -> Vec<Vec<SqlValue>> {
3701 let input = VecIterator::new(sample_aggregate_rows(), sample_aggregate_schema());
3702 let schema = build_aggregate_schema(&group_keys, &aggregates);
3703 let mut iter =
3704 AggregateIterator::new(Box::new(input), group_keys, aggregates, None, schema);
3705 collect_iterator_rows(&mut iter)
3706 .unwrap()
3707 .into_iter()
3708 .map(|row| row.values)
3709 .collect()
3710 }
3711
3712 fn collect_parallel_aggregate(
3713 group_keys: Vec<TypedExpr>,
3714 aggregates: Vec<AggregateExpr>,
3715 parallelism: usize,
3716 ) -> Vec<Vec<SqlValue>> {
3717 let input = VecIterator::new(sample_aggregate_rows(), sample_aggregate_schema());
3718 let schema = build_aggregate_schema(&group_keys, &aggregates);
3719 execute_parallel_aggregate_rows(
3720 Box::new(input),
3721 group_keys,
3722 aggregates,
3723 None,
3724 schema,
3725 parallelism,
3726 )
3727 .unwrap()
3728 .into_iter()
3729 .map(|row| row.values)
3730 .collect()
3731 }
3732
3733 fn sort_rows(mut rows: Vec<Vec<SqlValue>>) -> Vec<Vec<SqlValue>> {
3734 rows.sort_by(|left, right| format!("{left:?}").cmp(&format!("{right:?}")));
3735 rows
3736 }
3737
3738 #[test]
3739 fn grouping_sets_accumulate_each_row_once_per_set() {
3740 let category = column_expr(0, "category", ResolvedType::Text);
3741 let group_keys = vec![category];
3742 let aggregates = vec![AggregateExpr::count_star()];
3743 let input = VecIterator::new(sample_aggregate_rows(), sample_aggregate_schema());
3744 let mut schema = build_aggregate_schema(&group_keys, &aggregates);
3745 schema.push(ColumnMetadata::new("__grouping_id", ResolvedType::BigInt));
3746 let mut iter =
3748 AggregateIterator::new(Box::new(input), group_keys, aggregates, None, schema)
3749 .with_grouping_sets(Some(vec![0b0, 0b1]));
3750 let rows = sort_rows(
3751 collect_iterator_rows(&mut iter)
3752 .unwrap()
3753 .into_iter()
3754 .map(|row| row.values)
3755 .collect(),
3756 );
3757
3758 assert_eq!(
3759 rows,
3760 sort_rows(vec![
3761 vec![
3762 SqlValue::Text("book".into()),
3763 SqlValue::BigInt(3),
3764 SqlValue::BigInt(0),
3765 ],
3766 vec![
3767 SqlValue::Text("game".into()),
3768 SqlValue::BigInt(1),
3769 SqlValue::BigInt(0),
3770 ],
3771 vec![
3772 SqlValue::Text("toy".into()),
3773 SqlValue::BigInt(1),
3774 SqlValue::BigInt(0),
3775 ],
3776 vec![SqlValue::Null, SqlValue::BigInt(5), SqlValue::BigInt(1)],
3777 ])
3778 );
3779 }
3780
3781 #[test]
3782 fn grouping_sets_group_limit_applies_across_all_sets() {
3783 let category = column_expr(0, "category", ResolvedType::Text);
3784 let group_keys = vec![category];
3785 let aggregates = vec![AggregateExpr::count_star()];
3786 let input = VecIterator::new(sample_aggregate_rows(), sample_aggregate_schema());
3787 let mut schema = build_aggregate_schema(&group_keys, &aggregates);
3788 schema.push(ColumnMetadata::new("__grouping_id", ResolvedType::BigInt));
3789 let mut iter =
3793 AggregateIterator::new(Box::new(input), group_keys, aggregates, None, schema)
3794 .with_grouping_sets(Some(vec![0b0, 0b1]))
3795 .with_group_limit(3);
3796 let error = collect_iterator_rows(&mut iter).unwrap_err();
3797 assert!(matches!(error, ExecutorError::ResourceExhausted { .. }));
3798 }
3799
3800 #[test]
3801 fn partial_schema_uses_group_keys_and_state_columns() {
3802 let category = column_expr(0, "category", ResolvedType::Text);
3803 let price = column_expr(1, "price", ResolvedType::Double);
3804 let aggregates = vec![AggregateExpr::count_star(), AggregateExpr::avg(price)];
3805
3806 let schema = build_partial_aggregate_schema(&[category], &aggregates);
3807 let names = schema
3808 .iter()
3809 .map(|column| column.name.as_str())
3810 .collect::<Vec<_>>();
3811 assert_eq!(
3812 names,
3813 vec![
3814 "category",
3815 "__agg0_state0",
3816 "__agg1_state0",
3817 "__agg1_state1"
3818 ]
3819 );
3820 assert_eq!(schema[1].data_type, ResolvedType::BigInt);
3821 assert_eq!(schema[2].data_type, ResolvedType::Double);
3822 assert_eq!(schema[3].data_type, ResolvedType::BigInt);
3823 }
3824
3825 #[test]
3826 fn parallel_aggregate_matches_single_with_group_by() {
3827 let group_keys = vec![column_expr(0, "category", ResolvedType::Text)];
3828 let aggregates = sample_aggregates();
3829
3830 let single = sort_rows(collect_single_aggregate(
3831 group_keys.clone(),
3832 aggregates.clone(),
3833 ));
3834 let parallel = sort_rows(collect_parallel_aggregate(group_keys, aggregates, 3));
3835
3836 assert_eq!(parallel, single);
3837 }
3838
3839 #[test]
3840 fn parallel_aggregate_matches_single_without_group_by() {
3841 let aggregates = sample_aggregates();
3842
3843 let single = collect_single_aggregate(Vec::new(), aggregates.clone());
3844 let parallel = collect_parallel_aggregate(Vec::new(), aggregates, 4);
3845
3846 assert_eq!(parallel, single);
3847 }
3848
3849 #[test]
3850 fn distinct_aggregates_force_single_parallel_mode() {
3851 let price = column_expr(1, "price", ResolvedType::Double);
3852 let aggregates = vec![AggregateExpr {
3853 distinct: true,
3854 ..AggregateExpr::sum(price)
3855 }];
3856
3857 assert!(should_use_single_for_parallel(4, &aggregates));
3858 assert!(should_use_single_for_parallel(1, &sample_aggregates()));
3859 assert!(!should_use_single_for_parallel(2, &sample_aggregates()));
3860 }
3861
3862 #[test]
3863 fn parallel_group_counter_exhaustion_falls_back_to_single() {
3864 let schema = vec![ColumnMetadata::new("category", ResolvedType::Text)];
3865 let rows = vec![
3866 Row::new(0, vec![SqlValue::Text("a".into())]),
3867 Row::new(1, vec![SqlValue::Text("b".into())]),
3868 Row::new(2, vec![SqlValue::Text("a".into())]),
3869 Row::new(3, vec![SqlValue::Text("b".into())]),
3870 ];
3871 let group_keys = vec![column_expr(0, "category", ResolvedType::Text)];
3872 let aggregates = vec![AggregateExpr::count_star()];
3873 let final_schema = build_aggregate_schema(&group_keys, &aggregates);
3874
3875 let single_values = {
3876 let input = VecIterator::new(rows.clone(), schema.clone());
3877 execute_single_aggregate_rows(
3878 Box::new(input),
3879 group_keys.clone(),
3880 aggregates.clone(),
3881 None,
3882 final_schema.clone(),
3883 None,
3884 2,
3885 )
3886 .unwrap()
3887 .into_iter()
3888 .map(|row| row.values)
3889 .collect::<Vec<_>>()
3890 };
3891
3892 let parallel_values = execute_parallel_aggregate_rows_with_policy(
3893 Box::new(VecIterator::new(rows, schema)),
3894 group_keys,
3895 aggregates,
3896 None,
3897 final_schema,
3898 2,
3899 None,
3900 2,
3901 )
3902 .unwrap()
3903 .into_iter()
3904 .map(|row| row.values)
3905 .collect::<Vec<_>>();
3906
3907 assert_eq!(sort_rows(parallel_values), sort_rows(single_values));
3908 }
3909
3910 #[test]
3911 fn materialize_limit_exhaustion_falls_back_to_streaming_single() {
3912 let schema = vec![ColumnMetadata::new("payload", ResolvedType::Text)];
3913 let rows = (0..4)
3914 .map(|idx| Row::new(idx, vec![SqlValue::Text("x".repeat(40))]))
3915 .collect::<Vec<_>>();
3916 let aggregates = vec![AggregateExpr::count_star()];
3917 let final_schema = build_aggregate_schema(&[], &aggregates);
3918 let policy = MemoryPolicy::new(Some(100), SpillPolicy::FailFast);
3919
3920 let result = execute_parallel_aggregate_rows_with_policy(
3921 Box::new(VecIterator::new(rows, schema)),
3922 Vec::new(),
3923 aggregates,
3924 None,
3925 final_schema,
3926 4,
3927 Some(policy),
3928 DEFAULT_GROUP_LIMIT,
3929 )
3930 .unwrap();
3931
3932 assert_eq!(result.len(), 1);
3933 assert_eq!(result[0].values, vec![SqlValue::BigInt(4)]);
3934 }
3935
3936 #[test]
3937 fn streaming_aggregate_respects_distinct_accumulators() {
3938 let schema = sample_aggregate_schema();
3939 let rows = vec![
3940 Row::new(
3941 0,
3942 vec![
3943 SqlValue::Text("book".into()),
3944 SqlValue::Double(10.0),
3945 SqlValue::Text("a".into()),
3946 ],
3947 ),
3948 Row::new(
3949 1,
3950 vec![
3951 SqlValue::Text("book".into()),
3952 SqlValue::Double(10.0),
3953 SqlValue::Text("a".into()),
3954 ],
3955 ),
3956 Row::new(
3957 2,
3958 vec![
3959 SqlValue::Text("book".into()),
3960 SqlValue::Double(15.0),
3961 SqlValue::Text("b".into()),
3962 ],
3963 ),
3964 ];
3965 let group_keys = vec![column_expr(0, "category", ResolvedType::Text)];
3966 let price = column_expr(1, "price", ResolvedType::Double);
3967 let label = column_expr(2, "label", ResolvedType::Text);
3968 let aggregates = vec![
3969 AggregateExpr {
3970 distinct: true,
3971 ..AggregateExpr::sum(price)
3972 },
3973 AggregateExpr {
3974 function: AggregateFunction::GroupConcat {
3975 separator: Some("|".into()),
3976 },
3977 arg: Some(label),
3978 extra_args: Vec::new(),
3979 distinct: true,
3980 result_type: ResolvedType::Text,
3981 filter: None,
3982 order_by: Vec::new(),
3983 },
3984 ];
3985 let output_schema = build_aggregate_schema(&group_keys, &aggregates);
3986 let input = VecIterator::new(rows, schema);
3987 let mut iter = StreamingAggregateIterator::new(
3988 Box::new(input),
3989 group_keys,
3990 aggregates,
3991 None,
3992 output_schema,
3993 );
3994 let rows = collect_iterator_rows(&mut iter).unwrap();
3995
3996 assert_eq!(rows.len(), 1);
3997 assert_eq!(rows[0].values[1], SqlValue::Double(25.0));
3998 assert_eq!(rows[0].values[2], SqlValue::Text("a|b".into()));
3999 }
4000
4001 #[test]
4002 fn partial_state_matches_single_for_count_sum_total_avg_min_max() {
4003 assert_single_equals_merged(
4004 || Box::new(CountAccumulator::new(false)),
4005 vec![
4006 vec![
4007 Some(SqlValue::Integer(1)),
4008 Some(SqlValue::BigInt(2)),
4009 Some(SqlValue::Text("x".into())),
4010 Some(SqlValue::Null),
4011 ],
4012 vec![Some(SqlValue::Integer(3))],
4013 ],
4014 );
4015 assert_single_equals_merged(
4016 || Box::new(SumAccumulator::new()),
4017 vec![
4018 vec![
4019 Some(SqlValue::Integer(1)),
4020 Some(SqlValue::BigInt(2)),
4021 Some(SqlValue::Float(3.5)),
4022 ],
4023 vec![Some(SqlValue::Double(4.5)), Some(SqlValue::Null)],
4024 ],
4025 );
4026 assert_single_equals_merged(
4027 || Box::new(TotalAccumulator::new()),
4028 vec![
4029 vec![Some(SqlValue::Integer(1)), Some(SqlValue::Null)],
4030 vec![Some(SqlValue::Double(2.5))],
4031 ],
4032 );
4033 assert_single_equals_merged(
4034 || Box::new(AvgAccumulator::new()),
4035 vec![
4036 vec![Some(SqlValue::Integer(2)), Some(SqlValue::Double(4.0))],
4037 vec![Some(SqlValue::Null), Some(SqlValue::Double(6.0))],
4038 ],
4039 );
4040 assert_single_equals_merged(
4041 || Box::new(MinMaxAccumulator::new(true)),
4042 vec![
4043 vec![Some(SqlValue::Integer(3)), Some(SqlValue::Integer(1))],
4044 vec![Some(SqlValue::Integer(2)), Some(SqlValue::Null)],
4045 ],
4046 );
4047 assert_single_equals_merged(
4048 || Box::new(MinMaxAccumulator::new(false)),
4049 vec![
4050 vec![
4051 Some(SqlValue::Text("b".into())),
4052 Some(SqlValue::Text("a".into())),
4053 ],
4054 vec![Some(SqlValue::Text("c".into())), Some(SqlValue::Null)],
4055 ],
4056 );
4057 }
4058
4059 #[test]
4060 fn partial_state_matches_single_for_ordered_string_aggregates() {
4061 assert_single_equals_merged(
4062 || Box::new(GroupConcatAccumulator::new("|".into())),
4063 vec![
4064 vec![Some(SqlValue::Text("a".into())), Some(SqlValue::Null)],
4065 vec![
4066 Some(SqlValue::Text("b".into())),
4067 Some(SqlValue::Text("c".into())),
4068 ],
4069 ],
4070 );
4071 assert_single_equals_merged(
4072 || Box::new(StringAggAccumulator::new("::".into())),
4073 vec![
4074 vec![Some(SqlValue::Text("a".into()))],
4075 vec![Some(SqlValue::Text("b".into())), Some(SqlValue::Null)],
4076 ],
4077 );
4078 }
4079
4080 #[test]
4081 fn partial_state_handles_empty_all_null_single_and_mixed_boundaries() {
4082 assert_single_equals_merged(
4083 || Box::new(CountAccumulator::new(false)),
4084 vec![vec![], vec![]],
4085 );
4086 assert_single_equals_merged(|| Box::new(SumAccumulator::new()), vec![vec![], vec![]]);
4087 assert_single_equals_merged(|| Box::new(TotalAccumulator::new()), vec![vec![], vec![]]);
4088 assert_single_equals_merged(|| Box::new(AvgAccumulator::new()), vec![vec![], vec![]]);
4089 assert_single_equals_merged(
4090 || Box::new(MinMaxAccumulator::new(true)),
4091 vec![vec![], vec![]],
4092 );
4093 assert_single_equals_merged(
4094 || Box::new(MinMaxAccumulator::new(false)),
4095 vec![vec![], vec![]],
4096 );
4097 assert_single_equals_merged(
4098 || Box::new(GroupConcatAccumulator::new(",".into())),
4099 vec![vec![], vec![]],
4100 );
4101 assert_single_equals_merged(
4102 || Box::new(StringAggAccumulator::new(",".into())),
4103 vec![vec![], vec![]],
4104 );
4105 assert_single_equals_merged(
4106 || Box::new(CountAccumulator::new(false)),
4107 vec![vec![Some(SqlValue::Null)], vec![Some(SqlValue::Null)]],
4108 );
4109 assert_single_equals_merged(
4110 || Box::new(SumAccumulator::new()),
4111 vec![vec![Some(SqlValue::Null)], vec![Some(SqlValue::Null)]],
4112 );
4113 assert_single_equals_merged(
4114 || Box::new(TotalAccumulator::new()),
4115 vec![vec![Some(SqlValue::Null)], vec![Some(SqlValue::Null)]],
4116 );
4117 assert_single_equals_merged(
4118 || Box::new(AvgAccumulator::new()),
4119 vec![vec![Some(SqlValue::Null)], vec![Some(SqlValue::Null)]],
4120 );
4121 assert_single_equals_merged(
4122 || Box::new(MinMaxAccumulator::new(true)),
4123 vec![vec![Some(SqlValue::Null)], vec![Some(SqlValue::Null)]],
4124 );
4125 assert_single_equals_merged(
4126 || Box::new(MinMaxAccumulator::new(false)),
4127 vec![vec![Some(SqlValue::Null)], vec![Some(SqlValue::Null)]],
4128 );
4129 assert_single_equals_merged(
4130 || Box::new(GroupConcatAccumulator::new(",".into())),
4131 vec![vec![Some(SqlValue::Null)], vec![Some(SqlValue::Null)]],
4132 );
4133 assert_single_equals_merged(
4134 || Box::new(StringAggAccumulator::new(",".into())),
4135 vec![vec![Some(SqlValue::Null)], vec![Some(SqlValue::Null)]],
4136 );
4137 assert_single_equals_merged(
4138 || Box::new(SumAccumulator::new()),
4139 vec![vec![Some(SqlValue::Integer(7))]],
4140 );
4141 assert_single_equals_merged(
4142 || Box::new(AvgAccumulator::new()),
4143 vec![
4144 vec![Some(SqlValue::Null)],
4145 vec![Some(SqlValue::Double(8.0))],
4146 ],
4147 );
4148 }
4149
4150 #[test]
4151 fn commutative_accumulators_are_merge_order_invariant() {
4152 let orders = vec![
4153 vec![1, 3, 0, 2],
4154 vec![3, 2, 1, 0],
4155 vec![0, 1, 2, 3],
4156 vec![2, 0, 3, 1],
4157 ];
4158 assert_merge_order_invariant(
4159 || Box::new(CountAccumulator::new(false)),
4160 vec![vec![Some(SqlValue::Integer(1))]],
4161 &[vec![0]],
4162 );
4163 assert_merge_order_invariant(
4164 || Box::new(SumAccumulator::new()),
4165 vec![
4166 vec![Some(SqlValue::Integer(1))],
4167 vec![Some(SqlValue::Integer(2))],
4168 ],
4169 &[vec![0, 1], vec![1, 0]],
4170 );
4171 assert_merge_order_invariant(
4172 || Box::new(AvgAccumulator::new()),
4173 vec![
4174 vec![Some(SqlValue::Integer(1))],
4175 vec![Some(SqlValue::Integer(2))],
4176 vec![Some(SqlValue::Integer(3))],
4177 ],
4178 &[vec![0, 1, 2], vec![2, 1, 0]],
4179 );
4180 let numeric_partitions = vec![
4181 vec![Some(SqlValue::Integer(1)), Some(SqlValue::Null)],
4182 vec![Some(SqlValue::BigInt(2))],
4183 vec![],
4184 vec![Some(SqlValue::Double(3.0))],
4185 ];
4186 assert_merge_order_invariant(
4187 || Box::new(CountAccumulator::new(false)),
4188 numeric_partitions.clone(),
4189 &orders,
4190 );
4191 assert_merge_order_invariant(
4192 || Box::new(SumAccumulator::new()),
4193 numeric_partitions.clone(),
4194 &orders,
4195 );
4196 assert_merge_order_invariant(
4197 || Box::new(TotalAccumulator::new()),
4198 numeric_partitions.clone(),
4199 &orders,
4200 );
4201 assert_merge_order_invariant(
4202 || Box::new(AvgAccumulator::new()),
4203 numeric_partitions.clone(),
4204 &orders,
4205 );
4206 let integer_partitions = vec![
4207 vec![Some(SqlValue::Integer(3)), Some(SqlValue::Null)],
4208 vec![Some(SqlValue::Integer(1))],
4209 vec![],
4210 vec![Some(SqlValue::Integer(2))],
4211 ];
4212 assert_merge_order_invariant(
4213 || Box::new(MinMaxAccumulator::new(true)),
4214 integer_partitions.clone(),
4215 &orders,
4216 );
4217 assert_merge_order_invariant(
4218 || Box::new(MinMaxAccumulator::new(false)),
4219 integer_partitions,
4220 &orders,
4221 );
4222 }
4223
4224 #[test]
4225 fn avg_partial_state_uses_sum_count_and_never_divides_by_zero_during_merge() {
4226 let empty = {
4227 let acc = AvgAccumulator::new();
4228 acc.state().unwrap()
4229 };
4230 assert_eq!(empty, vec![SqlValue::Double(0.0), SqlValue::BigInt(0)]);
4231
4232 let mut partial = AvgAccumulator::new();
4233 partial.update(Some(SqlValue::Integer(2))).unwrap();
4234 partial.update(Some(SqlValue::Double(4.0))).unwrap();
4235 assert_eq!(
4236 partial.state().unwrap(),
4237 vec![SqlValue::Double(6.0), SqlValue::BigInt(2)]
4238 );
4239
4240 let mut final_acc = AvgAccumulator::new();
4241 final_acc.merge(&empty).unwrap();
4242 assert_eq!(final_acc.finalize().unwrap(), SqlValue::Null);
4243 final_acc.merge(&partial.state().unwrap()).unwrap();
4244 assert_eq!(final_acc.finalize().unwrap(), SqlValue::Double(3.0));
4245 }
4246
4247 #[test]
4248 fn merge_rejects_invalid_state_contracts_without_panicking() {
4249 let mut count = CountAccumulator::new(false);
4250 assert!(count.merge(&[]).is_err());
4251 assert!(count.merge(&[SqlValue::Text("bad".into())]).is_err());
4252
4253 let mut avg = AvgAccumulator::new();
4254 assert!(avg.merge(&[SqlValue::Double(1.0)]).is_err());
4255 assert!(
4256 avg.merge(&[SqlValue::Double(1.0), SqlValue::Text("bad".into())])
4257 .is_err()
4258 );
4259
4260 let mut concat = GroupConcatAccumulator::new("|".into());
4261 assert!(
4262 concat
4263 .merge(&[SqlValue::Text("a".into()), SqlValue::Text(",".into())])
4264 .is_err()
4265 );
4266 }
4267
4268 #[test]
4269 fn count_accumulator_counts_rows_and_skips_nulls() {
4270 let mut acc = CountAccumulator::new(false);
4271 acc.update(None).unwrap();
4272 acc.update(Some(SqlValue::Null)).unwrap();
4273 acc.update(Some(SqlValue::Integer(1))).unwrap();
4274 assert_eq!(acc.finalize().unwrap(), SqlValue::BigInt(2));
4275 }
4276
4277 #[test]
4278 fn count_accumulator_distinct_deduplicates() {
4279 let mut acc = CountAccumulator::new(true);
4280 acc.update(Some(SqlValue::Integer(1))).unwrap();
4281 acc.update(Some(SqlValue::Integer(1))).unwrap();
4282 acc.update(Some(SqlValue::Integer(2))).unwrap();
4283 assert_eq!(acc.finalize().unwrap(), SqlValue::BigInt(2));
4284 }
4285
4286 #[test]
4287 fn count_distinct_uses_group_key_equality_boundaries() {
4288 let mut acc = CountAccumulator::new(true);
4289 let nan_a = f64::from_bits(0x7ff8_0000_0000_0001);
4290 let nan_b = f64::from_bits(0x7ff8_0000_0000_0002);
4291 for value in [
4292 SqlValue::Null,
4293 SqlValue::Null,
4294 SqlValue::Integer(1),
4295 SqlValue::Integer(1),
4296 SqlValue::Double(1.0),
4297 SqlValue::Double(-0.0),
4298 SqlValue::Double(0.0),
4299 SqlValue::Double(nan_a),
4300 SqlValue::Double(nan_a),
4301 SqlValue::Double(nan_b),
4302 SqlValue::Text("same".into()),
4303 SqlValue::Text("same".into()),
4304 SqlValue::Blob(vec![1, 2]),
4305 SqlValue::Blob(vec![1, 2]),
4306 SqlValue::Blob(vec![1, 3]),
4307 ] {
4308 acc.update(Some(value)).unwrap();
4309 }
4310 assert_eq!(acc.finalize().unwrap(), SqlValue::BigInt(9));
4311 }
4312
4313 #[test]
4314 fn distinct_non_count_accumulators_deduplicate_non_null_values() {
4315 let mut sum = SumAccumulator::with_distinct(true);
4316 for value in [
4317 SqlValue::Integer(1),
4318 SqlValue::Integer(1),
4319 SqlValue::Double(1.0),
4320 SqlValue::Integer(2),
4321 SqlValue::Null,
4322 ] {
4323 sum.update(Some(value)).unwrap();
4324 }
4325 assert_eq!(sum.finalize().unwrap(), SqlValue::Double(4.0));
4326
4327 let mut avg = AvgAccumulator::with_distinct(true);
4328 for value in [
4329 SqlValue::Integer(1),
4330 SqlValue::Integer(1),
4331 SqlValue::Integer(3),
4332 SqlValue::Null,
4333 ] {
4334 avg.update(Some(value)).unwrap();
4335 }
4336 assert_eq!(avg.finalize().unwrap(), SqlValue::Double(2.0));
4337
4338 let mut min = MinMaxAccumulator::with_distinct(true, true);
4339 let mut max = MinMaxAccumulator::with_distinct(false, true);
4340 for value in [
4341 SqlValue::Text("b".into()),
4342 SqlValue::Text("a".into()),
4343 SqlValue::Text("a".into()),
4344 SqlValue::Text("c".into()),
4345 ] {
4346 min.update(Some(value.clone())).unwrap();
4347 max.update(Some(value)).unwrap();
4348 }
4349 assert_eq!(min.finalize().unwrap(), SqlValue::Text("a".into()));
4350 assert_eq!(max.finalize().unwrap(), SqlValue::Text("c".into()));
4351
4352 let mut group_concat = GroupConcatAccumulator::with_distinct("|".into(), true);
4353 let mut string_agg = StringAggAccumulator::with_distinct(";".into(), true);
4354 for value in [
4355 SqlValue::Text("a".into()),
4356 SqlValue::Text("a".into()),
4357 SqlValue::Null,
4358 SqlValue::Text("b".into()),
4359 ] {
4360 group_concat.update(Some(value.clone())).unwrap();
4361 string_agg.update(Some(value)).unwrap();
4362 }
4363 assert_eq!(
4364 group_concat.finalize().unwrap(),
4365 SqlValue::Text("a|b".into())
4366 );
4367 assert_eq!(string_agg.finalize().unwrap(), SqlValue::Text("a;b".into()));
4368 }
4369
4370 #[test]
4371 fn sum_accumulator_aggregates_numeric_values() {
4372 let mut acc = SumAccumulator::new();
4373 acc.update(Some(SqlValue::Integer(2))).unwrap();
4374 acc.update(Some(SqlValue::Double(3.5))).unwrap();
4375 acc.update(Some(SqlValue::Null)).unwrap();
4376 assert_eq!(acc.finalize().unwrap(), SqlValue::Double(5.5));
4377 }
4378
4379 #[test]
4380 fn total_accumulator_returns_zero_for_empty() {
4381 let acc = TotalAccumulator::new();
4382 assert_eq!(acc.finalize().unwrap(), SqlValue::Double(0.0));
4383 }
4384
4385 #[test]
4386 fn total_accumulator_aggregates_numeric_values() {
4387 let mut acc = TotalAccumulator::new();
4388 acc.update(Some(SqlValue::Integer(2))).unwrap();
4389 acc.update(Some(SqlValue::Null)).unwrap();
4390 acc.update(Some(SqlValue::Double(1.5))).unwrap();
4391 assert_eq!(acc.finalize().unwrap(), SqlValue::Double(3.5));
4392 }
4393
4394 #[test]
4395 fn avg_accumulator_handles_empty_and_nulls() {
4396 let mut acc = AvgAccumulator::new();
4397 assert_eq!(acc.finalize().unwrap(), SqlValue::Null);
4398 acc.update(Some(SqlValue::Null)).unwrap();
4399 acc.update(Some(SqlValue::BigInt(4))).unwrap();
4400 acc.update(Some(SqlValue::Integer(2))).unwrap();
4401 assert_eq!(acc.finalize().unwrap(), SqlValue::Double(3.0));
4402 }
4403
4404 #[test]
4405 fn min_max_accumulator_tracks_extremes() {
4406 let mut min_acc = MinMaxAccumulator::new(true);
4407 let mut max_acc = MinMaxAccumulator::new(false);
4408 for value in [3, 1, 2] {
4409 min_acc.update(Some(SqlValue::Integer(value))).unwrap();
4410 max_acc.update(Some(SqlValue::Integer(value))).unwrap();
4411 }
4412 assert_eq!(min_acc.finalize().unwrap(), SqlValue::Integer(1));
4413 assert_eq!(max_acc.finalize().unwrap(), SqlValue::Integer(3));
4414 }
4415
4416 #[test]
4417 fn min_max_accumulator_rejects_type_mismatch() {
4418 let mut acc = MinMaxAccumulator::new(true);
4419 acc.update(Some(SqlValue::Integer(1))).unwrap();
4420 let err = acc.update(Some(SqlValue::Text("bad".into()))).unwrap_err();
4421 match err {
4422 ExecutorError::Evaluation(crate::executor::EvaluationError::TypeMismatch {
4423 ..
4424 }) => {}
4425 other => panic!("unexpected error {:?}", other),
4426 }
4427 }
4428
4429 #[test]
4430 fn group_concat_accumulator_joins_values() {
4431 let mut acc = GroupConcatAccumulator::new("|".into());
4432 acc.update(Some(SqlValue::Text("a".into()))).unwrap();
4433 acc.update(Some(SqlValue::Null)).unwrap();
4434 acc.update(Some(SqlValue::Text("b".into()))).unwrap();
4435 assert_eq!(acc.finalize().unwrap(), SqlValue::Text("a|b".into()));
4436 }
4437
4438 #[test]
4439 fn group_concat_accumulator_empty_returns_null() {
4440 let acc = GroupConcatAccumulator::new(",".into());
4441 assert_eq!(acc.finalize().unwrap(), SqlValue::Null);
4442 }
4443
4444 #[test]
4445 fn string_agg_accumulator_joins_values() {
4446 let mut acc = StringAggAccumulator::new("::".into());
4447 acc.update(Some(SqlValue::Text("a".into()))).unwrap();
4448 acc.update(Some(SqlValue::Null)).unwrap();
4449 acc.update(Some(SqlValue::Text("b".into()))).unwrap();
4450 assert_eq!(acc.finalize().unwrap(), SqlValue::Text("a::b".into()));
4451 }
4452
4453 #[test]
4454 fn string_agg_accumulator_empty_returns_null() {
4455 let acc = StringAggAccumulator::new(",".into());
4456 assert_eq!(acc.finalize().unwrap(), SqlValue::Null);
4457 }
4458
4459 #[test]
4460 fn encode_group_key_is_deterministic() {
4461 let values = vec![
4462 SqlValue::Integer(1),
4463 SqlValue::Text("a".into()),
4464 SqlValue::Null,
4465 ];
4466 let first = encode_group_key(&values).unwrap();
4467 let second = encode_group_key(&values).unwrap();
4468 assert_eq!(first, second);
4469 }
4470
4471 #[test]
4472 fn percentile_disc_accumulator_follows_postgres_selection_rule() {
4473 let values = [1i64, 2, 2, 3];
4475 for (fraction, expected) in [(0.0, 1i64), (0.25, 1), (0.5, 2), (0.75, 2), (1.0, 3)] {
4476 let mut acc = PercentileDiscAccumulator::new(fraction, vec![(true, false)]);
4477 for value in values {
4478 let value = SqlValue::Integer(value as i32);
4479 acc.update_ordered(Some(value.clone()), std::slice::from_ref(&value))
4480 .unwrap();
4481 }
4482 acc.update_ordered(Some(SqlValue::Null), &[SqlValue::Null])
4484 .unwrap();
4485 assert_eq!(
4486 acc.finalize().unwrap(),
4487 SqlValue::Integer(expected as i32),
4488 "fraction {fraction}"
4489 );
4490 }
4491
4492 let empty = PercentileDiscAccumulator::new(0.5, vec![(true, false)]);
4493 assert_eq!(empty.finalize().unwrap(), SqlValue::Null);
4494
4495 let acc = PercentileDiscAccumulator::new(0.5, vec![(true, false)]);
4496 assert!(acc.state().is_err(), "ordered-set partial state is invalid");
4497 }
4498
4499 #[test]
4500 fn ordered_string_accumulators_sort_stably_and_reject_partial_state() {
4501 let mut acc = StringAggAccumulator::with_order(",".into(), false, vec![(false, false)]);
4502 for (key, value) in [(2, "b"), (1, "a"), (3, "c"), (2, "d")] {
4503 acc.update_ordered(
4504 Some(SqlValue::Text(value.into())),
4505 &[SqlValue::Integer(key)],
4506 )
4507 .unwrap();
4508 }
4509 assert_eq!(acc.finalize().unwrap(), SqlValue::Text("c,b,d,a".into()));
4511 assert!(acc.state().is_err());
4512 assert!(acc.merge(&[]).is_err());
4513
4514 let mut concat = GroupConcatAccumulator::with_order("|".into(), true, vec![(true, false)]);
4515 for (key, value) in [(2, "x"), (1, "y"), (3, "x")] {
4516 concat
4517 .update_ordered(
4518 Some(SqlValue::Text(value.into())),
4519 &[SqlValue::Integer(key)],
4520 )
4521 .unwrap();
4522 }
4523 assert_eq!(concat.finalize().unwrap(), SqlValue::Text("y|x".into()));
4525 }
4526
4527 #[test]
4528 fn stable_moments_merge_and_preserve_sample_boundaries() {
4529 let mut whole = StatisticsAccumulator::new(StatisticsKind::Variance(true));
4530 let mut left = whole.clone();
4531 let mut right = whole.clone();
4532 for (index, value) in [1.0e12, 1.0e12 + 1.0, 1.0e12 + 2.0, 1.0e12 + 3.0]
4533 .into_iter()
4534 .enumerate()
4535 {
4536 whole.update(Some(SqlValue::Double(value))).unwrap();
4537 if index < 2 {
4538 left.update(Some(SqlValue::Double(value))).unwrap();
4539 } else {
4540 right.update(Some(SqlValue::Double(value))).unwrap();
4541 }
4542 }
4543 left.merge(&right.state().unwrap()).unwrap();
4544 assert_eq!(whole.finalize().unwrap(), left.finalize().unwrap());
4545 assert_eq!(whole.finalize().unwrap(), SqlValue::Double(5.0 / 3.0));
4546
4547 let empty = StatisticsAccumulator::new(StatisticsKind::Variance(true));
4548 assert_eq!(empty.finalize().unwrap(), SqlValue::Null);
4549 let mut singleton = empty.clone();
4550 singleton.update(Some(SqlValue::Integer(7))).unwrap();
4551 assert_eq!(singleton.finalize().unwrap(), SqlValue::Null);
4552 singleton.kind = StatisticsKind::Variance(false);
4553 assert_eq!(singleton.finalize().unwrap(), SqlValue::Double(0.0));
4554 }
4555
4556 #[test]
4557 fn continuous_percentiles_preserve_non_finite_endpoints() {
4558 for (fraction, expected) in [(0.0, f64::NEG_INFINITY), (1.0, f64::INFINITY)] {
4559 let mut acc = PercentileContAccumulator::new(fraction, true);
4560 acc.update(Some(SqlValue::Double(f64::NEG_INFINITY)))
4561 .unwrap();
4562 acc.update(Some(SqlValue::Double(0.0))).unwrap();
4563 acc.update(Some(SqlValue::Double(f64::INFINITY))).unwrap();
4564 assert_eq!(acc.finalize().unwrap(), SqlValue::Double(expected));
4565 }
4566
4567 let mut acc = PercentileContAccumulator::new(1.0, true);
4568 acc.update(Some(SqlValue::Double(f64::NAN))).unwrap();
4569 let SqlValue::Double(value) = acc.finalize().unwrap() else {
4570 panic!("continuous percentile must return DOUBLE");
4571 };
4572 assert!(value.is_nan());
4573 }
4574}