1use std::collections::HashMap;
2
3use linkrs_core::columnar::{MaterializedBatch, RowKey};
4use linkrs_core::error::QueryError;
5use linkrs_core::types::expr::Expression;
6use linkrs_core::types::operators::AggregateFunction;
7use linkrs_core::value::NullType;
8use linkrs_core::Value;
9
10use crate::executor::base::{MemoryBudget, MemoryTracker};
11use crate::executor::expression::evaluator::ExpressionEvaluator;
12use crate::executor::streaming::chunk::DataChunk;
13use crate::executor::streaming::executor::{StreamingExecutor, ValueRowContext};
14use crate::executor::streaming::helpers::accumulator_states::{
15 accumulator_to_value, AggregateAccumulator,
16};
17use crate::executor::streaming::spill::{
18 finalize_partitions_with_runtime, HashPartitionConfig, HashPartitionSpiller, SpillManager,
19};
20
21use super::aggregate::{
22 value_to_partial_accumulator, AggregateState, FinalAggregateState, GroupByState,
23 PartialAggregateState, ACCUMULATOR_OVERHEAD_BYTES,
24};
25use super::helpers::{
26 aggregate_arg_field_name, count_identity_arg, emit_batch_slice, BlockingContext,
27};
28
29type BatchEvalResult = Option<(Vec<Vec<Value>>, Vec<Vec<Value>>)>;
30
31fn eval_group_key(
39 row: &[Value],
40 col_names: &[String],
41 group_by_expressions: &[Expression],
42) -> Vec<Value> {
43 group_by_expressions
44 .iter()
45 .map(|expr| {
46 let mut ctx = ValueRowContext::from_names(row.to_vec(), col_names.to_vec());
47 ExpressionEvaluator::evaluate(expr, &mut ctx).unwrap_or(Value::Null(NullType::Null))
48 })
49 .collect()
50}
51
52pub(super) fn open_aggregate(state: &mut Option<AggregateState>, num_agg_funcs: usize) {
53 *state = Some(AggregateState {
54 group_map: HashMap::new(),
55 accumulator_overhead: num_agg_funcs * ACCUMULATOR_OVERHEAD_BYTES,
56 result_batch: MaterializedBatch::new(0, 0),
57 emitted_offset: 0,
58 partition_spiller: None,
59 spilled_runs: vec![],
60 current_partition: 0,
61 has_spilled: false,
62 output_complete: false,
63 col_names: vec![],
64 });
65}
66
67pub(super) fn open_groupby(state: &mut Option<GroupByState>) {
68 *state = Some(GroupByState {
69 batch: MaterializedBatch::new(0, 0),
70 col_names: vec![],
71 result_batch: MaterializedBatch::new(0, 0),
72 emitted_offset: 0,
73 partition_spiller: None,
74 spilled_runs: vec![],
75 current_partition: 0,
76 has_spilled: false,
77 output_complete: false,
78 });
79}
80
81pub(super) fn open_partial_aggregate(state: &mut Option<PartialAggregateState>) {
82 *state = Some(PartialAggregateState {
83 group_map: HashMap::new(),
84 col_names: vec![],
85 result_batch: MaterializedBatch::new(0, 0),
86 emitted_offset: 0,
87 });
88}
89
90pub(super) fn open_final_aggregate(state: &mut Option<FinalAggregateState>) {
91 *state = Some(FinalAggregateState {
92 group_map: HashMap::new(),
93 col_names: vec![],
94 result_batch: MaterializedBatch::new(0, 0),
95 emitted_offset: 0,
96 });
97}
98
99pub(super) fn next_aggregate(
100 group_by_expressions: &[Expression],
101 aggregate_functions: &[(AggregateFunction, Vec<Expression>)],
102 memory_tracker: &mut MemoryTracker,
103 state: &mut AggregateState,
104 ctx: &BlockingContext<'_>,
105 input: &mut StreamingExecutor,
106) -> Result<Option<DataChunk>, QueryError> {
107 let num_group_keys = group_by_expressions.len();
108 let has_group_keys = num_group_keys > 0;
109 let group_overhead = state.accumulator_overhead;
110
111 loop {
112 if state.emitted_offset < state.result_batch.num_rows() {
114 return Ok(Some(emit_batch_slice(
115 &state.result_batch,
116 &mut state.emitted_offset,
117 ctx,
118 )));
119 }
120 if state.emitted_offset > 0 {
121 state.emitted_offset = 0;
122 state.result_batch.clear();
123 if !state.has_spilled || state.current_partition >= state.spilled_runs.len() {
124 state.output_complete = true;
125 return Ok(None);
126 }
127 }
128
129 if state.has_spilled && state.partition_spiller.is_none() {
131 while state.current_partition < state.spilled_runs.len() {
132 if let Some(rt) = ctx.runtime.as_ref() {
133 rt.ensure_not_cancelled()?;
134 }
135
136 let run = match &state.spilled_runs[state.current_partition] {
137 Some(r) => r,
138 None => {
139 state.current_partition += 1;
140 continue;
141 }
142 };
143
144 let mut reader = crate::executor::streaming::spill::RunReader::open(run)?;
145 let mut partition_results = Vec::new();
146 let mut group_map: HashMap<RowKey, Vec<AggregateAccumulator>> = HashMap::new();
147 while let Some(row) = reader.read_row()? {
148 let group_key: Vec<Value> = row.iter().take(num_group_keys).cloned().collect();
149 let accs = group_map.entry(group_key).or_insert_with(|| {
150 aggregate_functions
151 .iter()
152 .map(|(f, args)| {
153 AggregateAccumulator::for_function(f, args)
154 .expect("every aggregate function has an accumulator")
155 })
156 .collect()
157 });
158 for (i, func) in aggregate_functions.iter().enumerate() {
159 if let Some(acc) = accs.get_mut(i) {
160 let partial_value = row
161 .get(num_group_keys + i)
162 .cloned()
163 .unwrap_or(Value::Null(NullType::Null));
164 if let Some(other) =
165 value_to_partial_accumulator(&func.0, &func.1, &partial_value)
166 {
167 acc.merge(&other);
168 }
169 }
170 }
171 }
172 for (group_key, accs) in group_map {
173 let mut result_row = if has_group_keys {
174 group_key
175 } else {
176 Vec::new()
177 };
178 for acc in accs {
179 result_row.push(acc.finalize());
180 }
181 partition_results.push(result_row);
182 }
183
184 let _ = std::fs::remove_file(&run.path);
185 state.current_partition += 1;
186
187 if !partition_results.is_empty() {
188 state.result_batch.clear();
189 state.emitted_offset = 0;
190 for result_row in partition_results {
191 state.result_batch.append_row(result_row);
192 }
193 return Ok(Some(emit_batch_slice(
194 &state.result_batch,
195 &mut state.emitted_offset,
196 ctx,
197 )));
198 }
199 }
200 state.output_complete = true;
201 return Ok(None);
202 }
203
204 let mut accumulating = true;
206 while accumulating {
207 match input.advance()? {
208 Some(mut chunk) => {
209 if let Some(rt) = ctx.runtime.as_ref() {
210 rt.ensure_not_cancelled()?;
211 }
212 let _ = chunk.expand_multiplicity_in_place();
216 let count_units: Vec<bool> = aggregate_functions
220 .iter()
221 .map(|(func, func_args)| count_identity_arg(func, func_args, &chunk))
222 .collect();
223 if state.col_names.is_empty() {
224 state.col_names = chunk.col_names();
225 }
226 let sm = ctx.runtime.as_ref().and_then(|rt| rt.get_spill_manager());
227 let rowless_units: Option<usize> = if chunk.rows.is_empty()
237 && !has_group_keys
238 && aggregate_functions
239 .iter()
240 .enumerate()
241 .all(|(i, (func, args))| {
242 matches!(func, AggregateFunction::Count)
243 && (count_units[i] || args.is_empty())
244 }) {
245 chunk.typed_len()
246 } else {
247 None
248 };
249 let batch_eval: BatchEvalResult = if chunk.selection.is_none()
250 && (!chunk.rows.is_empty() || rowless_units.is_some())
251 {
252 match chunk.evaluate_expressions(group_by_expressions, None) {
253 Ok(keys) => {
254 let mut args = Vec::with_capacity(aggregate_functions.len());
255 let mut ok = true;
256 for (i, (_func, func_args)) in
257 aggregate_functions.iter().enumerate()
258 {
259 if count_units[i] {
260 args.push(vec![
266 Value::Int(1);
267 rowless_units.unwrap_or(chunk.rows.len())
268 ]);
269 continue;
270 }
271 if let Some(expr) = func_args.first() {
272 match chunk.evaluate_expression(expr, None) {
273 Ok(col) => args.push(col),
274 Err(_) => {
275 ok = false;
276 break;
277 }
278 }
279 } else {
280 ok = false;
281 break;
282 }
283 }
284 if ok {
285 Some((keys, args))
286 } else {
287 None
288 }
289 }
290 Err(_) => None,
291 }
292 } else {
293 None
294 };
295
296 let empty_row: Vec<Value> = Vec::new();
297 let visit: Vec<usize> = match rowless_units {
298 Some(n) if chunk.selection.is_none() => (0..n).collect(),
299 _ => chunk.visible_indices(),
300 };
301 for idx in visit {
302 let row: &[Value] = match (rowless_units, chunk.rows.get(idx)) {
303 (_, Some(stored)) => stored,
304 (Some(_), None) => &empty_row,
305 (None, None) => panic!(
306 "rowless chunk reached the row loop outside the audited count morphology"
307 ),
308 };
309 let group_key: Vec<Value> = match &batch_eval {
310 Some((keys, _)) => keys.iter().map(|c| c[idx].clone()).collect(),
311 None => eval_group_key(row, &state.col_names, group_by_expressions),
312 };
313 let arg_values: Vec<Value> = match &batch_eval {
314 Some((_, args)) => args.iter().map(|c| c[idx].clone()).collect(),
315 None => {
316 let mut values = Vec::with_capacity(aggregate_functions.len());
317 for (i, (_func, func_args)) in
318 aggregate_functions.iter().enumerate()
319 {
320 if count_units[i] {
321 values.push(Value::Int(1));
322 continue;
323 }
324 let mut ctx = ValueRowContext::from_names(
325 row.to_vec(),
326 state.col_names.clone(),
327 );
328 let expr = func_args
329 .first()
330 .cloned()
331 .unwrap_or_else(|| Expression::Literal(Value::Int(1)));
332 values.push(
333 match ExpressionEvaluator::evaluate(&expr, &mut ctx) {
334 Ok(v) => v,
335 Err(_) => Value::Null(NullType::Null),
336 },
337 );
338 }
339 values
340 }
341 };
342 let partial_row_of =
343 |group_key: &[Value], arg_values: &[Value]| -> Vec<Value> {
344 let mut partial_row = group_key.to_vec();
345 for (i, (func, args)) in aggregate_functions.iter().enumerate() {
346 let value = arg_values
347 .get(i)
348 .cloned()
349 .unwrap_or_else(|| Value::Null(NullType::Null));
350 let mut acc = AggregateAccumulator::for_function(func, args)
351 .expect("every aggregate function has an accumulator");
352 acc.accumulate(&value);
353 partial_row.push(accumulator_to_value(&acc));
354 }
355 partial_row
356 };
357 if let Some(ref mut spiller) = state.partition_spiller {
358 let manager = sm.clone().ok_or_else(|| {
359 QueryError::execution("Spill manager not available".to_string())
360 })?;
361 let p = crate::executor::streaming::spill::hash_row_partition(
362 &group_key,
363 spiller.num_partitions(),
364 ) as usize;
365 let partial_row = partial_row_of(&group_key, &arg_values);
366 spiller.insert_row_to_partition(&partial_row, p, &manager)?;
367 continue;
368 }
369 if !state.group_map.contains_key(&group_key) {
370 if let Err(e) = memory_tracker.try_reserve(
371 MemoryBudget::estimate_row_memory(&group_key) + group_overhead,
372 ) {
373 if let Some(sm) =
374 ctx.runtime.as_ref().and_then(|rt| rt.get_spill_manager())
375 {
376 let config = HashPartitionConfig::default();
377 let num_partitions = config.num_partitions;
378 let mut spiller = HashPartitionSpiller::new(config, &sm, 0)?;
379
380 for (key, accs) in std::mem::take(&mut state.group_map) {
381 let p =
382 crate::executor::streaming::spill::hash_row_partition(
383 &key,
384 num_partitions,
385 ) as usize;
386 let mut partial_row = key.clone();
387 for acc in &accs {
388 partial_row.push(accumulator_to_value(acc));
389 }
390 spiller.insert_row_to_partition(&partial_row, p, &sm)?;
391 memory_tracker.release(
392 MemoryBudget::estimate_row_memory(&key)
393 + group_overhead,
394 );
395 }
396
397 let p = crate::executor::streaming::spill::hash_row_partition(
398 &group_key,
399 num_partitions,
400 ) as usize;
401 let partial_row = partial_row_of(&group_key, &arg_values);
402 spiller.insert_row_to_partition(&partial_row, p, &sm)?;
403
404 state.partition_spiller = Some(spiller);
405 state.has_spilled = true;
406 continue;
407 } else {
408 return Err(e);
409 }
410 }
411 }
412
413 let accs = state.group_map.entry(group_key).or_insert_with(|| {
414 aggregate_functions
415 .iter()
416 .map(|(f, args)| {
417 AggregateAccumulator::for_function(f, args)
418 .expect("every aggregate function has an accumulator")
419 })
420 .collect()
421 });
422 for (i, (_func, _expr)) in aggregate_functions.iter().enumerate() {
423 if let Some(acc) = accs.get_mut(i) {
424 let value = arg_values
425 .get(i)
426 .cloned()
427 .unwrap_or_else(|| Value::Null(NullType::Null));
428 acc.accumulate(&value);
429 }
430 }
431 }
432 }
433 None => {
434 accumulating = false;
435 }
436 }
437 }
438
439 if state.partition_spiller.is_some() {
441 let runs = finalize_partitions_with_runtime(
442 state.partition_spiller.take().unwrap(),
443 ctx.runtime.as_ref(),
444 )?;
445 state.spilled_runs = runs;
446 state.current_partition = 0;
447 continue;
448 }
449
450 let group_map = std::mem::take(&mut state.group_map);
452 state.result_batch.clear();
453 state.emitted_offset = 0;
454 for (group_key, accs) in group_map {
455 let mut result_row = if has_group_keys {
456 group_key
457 } else {
458 Vec::new()
459 };
460 for acc in accs {
461 result_row.push(acc.finalize());
462 }
463 state.result_batch.append_row(result_row);
464 }
465 if !has_group_keys && state.result_batch.is_empty() {
469 let mut result_row = Vec::new();
470 for (func, args) in aggregate_functions.iter() {
471 let acc = AggregateAccumulator::for_function(func, args)
472 .expect("every aggregate function has an accumulator");
473 result_row.push(acc.finalize());
474 }
475 state.result_batch.append_row(result_row);
476 }
477
478 if state.result_batch.is_empty() {
479 state.output_complete = true;
480 return Ok(None);
481 }
482 return Ok(Some(emit_batch_slice(
483 &state.result_batch,
484 &mut state.emitted_offset,
485 ctx,
486 )));
487 }
488}
489
490pub(super) fn next_groupby(
491 group_by_expressions: &[Expression],
492 memory_tracker: &mut MemoryTracker,
493 state: &mut GroupByState,
494 ctx: &BlockingContext<'_>,
495 input: &mut StreamingExecutor,
496) -> Result<Option<DataChunk>, QueryError> {
497 use crate::executor::streaming::spill::RunReader;
498
499 let group_rows = |rows: Vec<Vec<Value>>, col_names: &[String]| -> Vec<Vec<Value>> {
500 let mut groups: HashMap<String, Vec<Vec<Value>>> = HashMap::new();
501 for row in rows {
502 let key_parts: Vec<String> = eval_group_key(&row, col_names, group_by_expressions)
503 .iter()
504 .map(|v| format!("{:?}", v))
505 .collect();
506 let key = key_parts.join("|");
507 groups.entry(key).or_default().push(row);
508 }
509 groups.into_values().flatten().collect()
510 };
511
512 loop {
513 if state.output_complete {
514 return Ok(None);
515 }
516
517 if state.emitted_offset < state.result_batch.num_rows() {
519 return Ok(Some(emit_batch_slice(
520 &state.result_batch,
521 &mut state.emitted_offset,
522 ctx,
523 )));
524 }
525 if state.emitted_offset > 0 {
526 state.emitted_offset = 0;
527 state.result_batch.clear();
528 if !state.has_spilled || state.current_partition >= state.spilled_runs.len() {
529 state.output_complete = true;
530 return Ok(None);
531 }
532 }
533
534 if state.has_spilled && state.partition_spiller.is_none() {
536 while state.current_partition < state.spilled_runs.len() {
537 if let Some(rt) = ctx.runtime.as_ref() {
538 rt.ensure_not_cancelled()?;
539 }
540
541 let run = match &state.spilled_runs[state.current_partition] {
542 Some(r) => r,
543 None => {
544 state.current_partition += 1;
545 continue;
546 }
547 };
548
549 let mut reader = RunReader::open(run)?;
550 let mut partition_rows = Vec::new();
551 while let Some(row) = reader.read_row()? {
552 memory_tracker.try_reserve_row(&row)?;
553 partition_rows.push(row);
554 }
555
556 let col_names = if state.col_names.is_empty() {
557 (0..partition_rows.first().map_or(0, |r| r.len()))
558 .map(|i| format!("col_{}", i))
559 .collect()
560 } else {
561 state.col_names.clone()
562 };
563 let result_rows = group_rows(partition_rows, &col_names);
564
565 let _ = std::fs::remove_file(&run.path);
566 state.current_partition += 1;
567 memory_tracker.reset();
568
569 if !result_rows.is_empty() {
570 state.result_batch.clear();
571 state.emitted_offset = 0;
572 for result_row in result_rows {
573 state.result_batch.append_row(result_row);
574 }
575 return Ok(Some(emit_batch_slice(
576 &state.result_batch,
577 &mut state.emitted_offset,
578 ctx,
579 )));
580 }
581 }
582 state.output_complete = true;
583 return Ok(None);
584 }
585
586 let mut accumulating = true;
588 while accumulating {
589 match input.advance()? {
590 Some(mut chunk) => {
591 if let Some(rt) = ctx.runtime.as_ref() {
592 rt.ensure_not_cancelled()?;
593 }
594 chunk.normalize_for_opaque("GroupBy");
597 if state.col_names.is_empty() {
598 state.col_names = match chunk.col_names() {
599 names if !names.is_empty() => names,
600 _ => (0..chunk.rows.first().map_or(0, |r| r.len()))
601 .map(|i| format!("col_{}", i))
602 .collect(),
603 };
604 }
605 for row in chunk.rows {
606 if let Some(ref mut spiller) = state.partition_spiller {
607 let manager = ctx
608 .runtime
609 .as_ref()
610 .and_then(|rt| rt.get_spill_manager())
611 .ok_or_else(|| {
612 QueryError::execution("Spill manager not available".to_string())
613 })?;
614 let group_key =
615 eval_group_key(&row, &state.col_names, group_by_expressions);
616 let p = crate::executor::streaming::spill::hash_row_partition(
617 &group_key,
618 spiller.num_partitions(),
619 ) as usize;
620 spiller.insert_row_to_partition(&row, p, &manager)?;
621 continue;
622 }
623 if let Err(e) = memory_tracker.try_reserve_row(&row) {
624 if let Some(sm) =
625 ctx.runtime.as_ref().and_then(|rt| rt.get_spill_manager())
626 {
627 let config = HashPartitionConfig::default();
628 let num_partitions = config.num_partitions;
629 let mut spiller = HashPartitionSpiller::new(config, &sm, 0)?;
630
631 for pending in state.batch.into_rows() {
632 let group_key = eval_group_key(
633 &pending,
634 &state.col_names,
635 group_by_expressions,
636 );
637 let p = crate::executor::streaming::spill::hash_row_partition(
638 &group_key,
639 num_partitions,
640 ) as usize;
641 spiller.insert_row_to_partition(&pending, p, &sm)?;
642 memory_tracker
643 .release(MemoryBudget::estimate_row_memory(&pending));
644 }
645
646 let group_key =
647 eval_group_key(&row, &state.col_names, group_by_expressions);
648 let p = crate::executor::streaming::spill::hash_row_partition(
649 &group_key,
650 num_partitions,
651 ) as usize;
652 spiller.insert_row_to_partition(&row, p, &sm)?;
653
654 state.partition_spiller = Some(spiller);
655 state.has_spilled = true;
656 continue;
657 } else {
658 return Err(e);
659 }
660 }
661 state.batch.append_row(row);
662 }
663 }
664 None => {
665 accumulating = false;
666 }
667 }
668 }
669
670 if state.partition_spiller.is_some() {
672 let runs = finalize_partitions_with_runtime(
673 state.partition_spiller.take().unwrap(),
674 ctx.runtime.as_ref(),
675 )?;
676 state.spilled_runs = runs;
677 state.current_partition = 0;
678 continue;
679 }
680
681 if state.batch.is_empty() {
683 state.output_complete = true;
684 return Ok(None);
685 }
686 let col_names = if state.col_names.is_empty() {
687 (0..state.batch.num_columns())
688 .map(|i| format!("col_{}", i))
689 .collect()
690 } else {
691 state.col_names.clone()
692 };
693 let result_rows = group_rows(state.batch.into_rows(), &col_names);
694 state.result_batch.clear();
695 state.emitted_offset = 0;
696 for result_row in result_rows {
697 state.result_batch.append_row(result_row);
698 }
699 if state.result_batch.is_empty() {
700 state.output_complete = true;
701 return Ok(None);
702 }
703 return Ok(Some(emit_batch_slice(
704 &state.result_batch,
705 &mut state.emitted_offset,
706 ctx,
707 )));
708 }
709}
710
711pub(super) fn next_partial_aggregate(
712 group_by_expressions: &[Expression],
713 aggregate_functions: &[(AggregateFunction, Vec<Expression>)],
714 memory_tracker: &mut MemoryTracker,
715 state: &mut PartialAggregateState,
716 ctx: &BlockingContext<'_>,
717 input: &mut StreamingExecutor,
718) -> Result<Option<DataChunk>, QueryError> {
719 if state.emitted_offset < state.result_batch.num_rows() {
720 return Ok(Some(emit_batch_slice(
721 &state.result_batch,
722 &mut state.emitted_offset,
723 ctx,
724 )));
725 }
726 if state.emitted_offset > 0 {
727 return Ok(None);
728 }
729
730 let mut col_names: Vec<String> = vec![];
731 while let Some(mut chunk) = input.advance()? {
732 if let Some(rt) = ctx.runtime.as_ref() {
733 rt.ensure_not_cancelled()?;
734 }
735 let _ = chunk.expand_multiplicity_in_place();
739 if col_names.is_empty() {
740 col_names = chunk.col_names();
741 }
742 let visible = chunk.visible_indices();
743 for idx in &visible {
744 memory_tracker.try_reserve_row(&chunk.rows[*idx])?;
745 }
746 let batch_keys: Option<Vec<Vec<Value>>> =
750 if chunk.selection.is_none() && !chunk.rows.is_empty() {
751 chunk.evaluate_expressions(group_by_expressions, None).ok()
752 } else {
753 None
754 };
755 let field_indices: Vec<Option<usize>> = aggregate_functions
756 .iter()
757 .map(|(func, args)| {
758 let field = aggregate_arg_field_name(func, args);
759 field.and_then(|f| col_names.iter().position(|c| c == &f))
760 })
761 .collect();
762 for idx in visible {
763 let row = &chunk.rows[idx];
764 let mut group_key = Vec::new();
765 if group_by_expressions.is_empty() {
766 group_key.push(Value::Null(NullType::Null));
767 } else {
768 match &batch_keys {
769 Some(keys) => {
770 group_key = keys.iter().map(|c| c[idx].clone()).collect();
771 }
772 None => {
773 group_key = eval_group_key(row, &col_names, group_by_expressions);
774 }
775 }
776 }
777
778 let group_accs = state.group_map.entry(group_key).or_insert_with(|| {
779 aggregate_functions
780 .iter()
781 .filter_map(|(f, args)| AggregateAccumulator::for_function(f, args))
782 .collect()
783 });
784
785 for (i, (func, _args)) in aggregate_functions.iter().enumerate() {
786 if let Some(acc) = group_accs.get_mut(i) {
787 let value = match &field_indices[i] {
788 Some(j) => row
789 .get(*j)
790 .cloned()
791 .unwrap_or_else(|| Value::Null(NullType::Null)),
792 None => match func {
793 AggregateFunction::Count => Value::Int(1),
794 _ => Value::Null(NullType::Null),
795 },
796 };
797 acc.accumulate(&value);
798 }
799 }
800 }
801 }
802
803 let mut result_rows: Vec<Vec<Value>> = Vec::new();
804 let num_group_keys = group_by_expressions.len();
805 for (group_key, accs) in std::mem::take(&mut state.group_map) {
806 let mut row = if num_group_keys == 0 {
807 vec![]
808 } else {
809 group_key
810 };
811 for (i, _func) in aggregate_functions.iter().enumerate() {
812 if let Some(acc) = accs.get(i) {
813 row.push(accumulator_to_value(acc));
814 } else {
815 row.push(Value::Null(NullType::Null));
816 }
817 }
818 result_rows.push(row);
819 }
820
821 state.result_batch.clear();
822 state.emitted_offset = 0;
823 for row in result_rows {
824 state.result_batch.append_row(row);
825 }
826
827 if state.result_batch.is_empty() {
828 Ok(None)
829 } else {
830 Ok(Some(emit_batch_slice(
831 &state.result_batch,
832 &mut state.emitted_offset,
833 ctx,
834 )))
835 }
836}
837
838pub(super) fn next_final_aggregate(
839 group_by_expressions: &[Expression],
840 aggregate_functions: &[(AggregateFunction, Vec<Expression>)],
841 memory_tracker: &mut MemoryTracker,
842 state: &mut FinalAggregateState,
843 ctx: &BlockingContext<'_>,
844 input: &mut StreamingExecutor,
845) -> Result<Option<DataChunk>, QueryError> {
846 if state.emitted_offset < state.result_batch.num_rows() {
847 return Ok(Some(emit_batch_slice(
848 &state.result_batch,
849 &mut state.emitted_offset,
850 ctx,
851 )));
852 }
853 if state.emitted_offset > 0 {
854 return Ok(None);
855 }
856
857 let mut col_names: Vec<String> = vec![];
858 while let Some(mut chunk) = input.advance()? {
859 if let Some(rt) = ctx.runtime.as_ref() {
860 rt.ensure_not_cancelled()?;
861 }
862 chunk.normalize_for_opaque("Aggregate");
865 if col_names.is_empty() {
866 col_names = chunk.col_names();
867 }
868 for row in &chunk.rows {
869 memory_tracker.try_reserve_row(row)?;
870 }
871 for row in chunk.rows {
872 let num_group_keys = group_by_expressions.len();
873 let num_agg_funcs = aggregate_functions.len();
874 let group_key: Vec<Value> = if num_group_keys == 0 {
875 vec![Value::Null(NullType::Null)]
876 } else {
877 row[0..num_group_keys].to_vec()
878 };
879
880 let group_accs = state.group_map.entry(group_key).or_insert_with(|| {
881 aggregate_functions
882 .iter()
883 .filter_map(|(f, args)| AggregateAccumulator::for_function(f, args))
884 .collect()
885 });
886
887 for (i, func) in aggregate_functions.iter().enumerate().take(num_agg_funcs) {
888 if let Some(acc) = group_accs.get_mut(i) {
889 let acc_col_idx = num_group_keys + i;
890 let partial_value = row.get(acc_col_idx);
891 if let Some(val) = partial_value {
892 let partial_acc = value_to_partial_accumulator(&func.0, &func.1, val);
893 if let Some(other) = partial_acc {
894 acc.merge(&other);
895 }
896 }
897 }
898 }
899 }
900 }
901
902 let mut result_rows: Vec<Vec<Value>> = Vec::new();
903 for (group_key, accs) in std::mem::take(&mut state.group_map) {
904 let mut row = if group_by_expressions.is_empty() {
905 vec![]
906 } else {
907 group_key
908 };
909 for (_i, _func) in aggregate_functions.iter().enumerate() {
910 if let Some(acc) = accs.get(_i) {
911 row.push(acc.finalize());
912 } else {
913 row.push(Value::Null(NullType::Null));
914 }
915 }
916 result_rows.push(row);
917 }
918
919 state.result_batch.clear();
920 state.emitted_offset = 0;
921 for row in result_rows {
922 state.result_batch.append_row(row);
923 }
924
925 if state.result_batch.is_empty() {
926 Ok(None)
927 } else {
928 Ok(Some(emit_batch_slice(
929 &state.result_batch,
930 &mut state.emitted_offset,
931 ctx,
932 )))
933 }
934}
935
936pub(super) fn close_aggregate(state: &mut Option<AggregateState>) {
937 if let Some(ref s) = state {
938 for r in s.spilled_runs.iter().flatten() {
939 let _ = std::fs::remove_file(&r.path);
940 }
941 }
942 *state = None;
943}
944
945pub(super) fn close_groupby(state: &mut Option<GroupByState>) {
946 if let Some(ref s) = state {
947 for r in s.spilled_runs.iter().flatten() {
948 let _ = std::fs::remove_file(&r.path);
949 }
950 }
951 *state = None;
952}
953
954pub(super) fn close_partial_aggregate(state: &mut Option<PartialAggregateState>) {
955 *state = None;
956}
957
958pub(super) fn close_final_aggregate(state: &mut Option<FinalAggregateState>) {
959 *state = None;
960}
961
962pub(super) fn spill_aggregate(
963 state: &mut AggregateState,
964 memory_tracker: &mut MemoryTracker,
965 sm: &SpillManager,
966) -> Result<(), QueryError> {
967 if state.partition_spiller.is_none() && !state.group_map.is_empty() {
968 let config = HashPartitionConfig::default();
969 let num_partitions = config.num_partitions;
970 let mut spiller = HashPartitionSpiller::new(config, sm, 0)?;
971 for (key, accs) in std::mem::take(&mut state.group_map) {
972 let p = crate::executor::streaming::spill::hash_row_partition(&key, num_partitions)
973 as usize;
974 let mut partial_row = key.clone();
975 for acc in &accs {
976 partial_row.push(accumulator_to_value(acc));
977 }
978 spiller.insert_row_to_partition(&partial_row, p, sm)?;
979 memory_tracker
980 .release(MemoryBudget::estimate_row_memory(&key) + state.accumulator_overhead);
981 }
982 state.partition_spiller = Some(spiller);
983 state.has_spilled = true;
984 }
985 Ok(())
986}
987
988pub(super) fn spill_groupby(
989 state: &mut GroupByState,
990 memory_tracker: &mut MemoryTracker,
991 group_by_expressions: &[Expression],
992 sm: &SpillManager,
993) -> Result<(), QueryError> {
994 if state.partition_spiller.is_none() && !state.batch.is_empty() {
995 let config = HashPartitionConfig::default();
996 let num_partitions = config.num_partitions;
997 let mut spiller = HashPartitionSpiller::new(config, sm, 0)?;
998 for row in state.batch.into_rows() {
999 let mut group_key = Vec::new();
1000 for expr in group_by_expressions.iter() {
1001 let mut ctx = ValueRowContext::from_names(row.clone(), state.col_names.clone());
1002 group_key.push(
1003 ExpressionEvaluator::evaluate(expr, &mut ctx)
1004 .unwrap_or(Value::Null(NullType::Null)),
1005 );
1006 }
1007 let p =
1008 crate::executor::streaming::spill::hash_row_partition(&group_key, num_partitions)
1009 as usize;
1010 spiller.insert_row_to_partition(&row, p, sm)?;
1011 memory_tracker.release(MemoryBudget::estimate_row_memory(&row));
1012 }
1013 state.partition_spiller = Some(spiller);
1014 state.has_spilled = true;
1015 }
1016 Ok(())
1017}