| 18 | use super::spec::{FrameBound, WindowFuncSpec}; |
| 19 | |
| 20 | pub(super) fn apply_aggregate_window( |
| 21 | rows: &mut [(String, serde_json::Value)], |
| 22 | indices: &[usize], |
| 23 | spec: &WindowFuncSpec, |
| 24 | ) { |
| 25 | let field = spec |
| 26 | .args |
| 27 | .first() |
| 28 | .and_then(|e| match e { |
| 29 | SqlExpr::Column(c) => Some(c.as_str()), |
| 30 | _ => None, |
| 31 | }) |
| 32 | .unwrap_or("*"); |
| 33 | |
| 34 | // Fast path: RANGE UNBOUNDED PRECEDING TO CURRENT ROW is the most common |
| 35 | // pattern (the PostgreSQL default for ordered windows). Use the running |
| 36 | // accumulator rather than re-aggregating the slice from scratch each row. |
| 37 | let use_running = spec.frame.mode == "range" |
| 38 | && matches!(spec.frame.start, FrameBound::UnboundedPreceding) |
| 39 | && matches!(spec.frame.end, FrameBound::CurrentRow); |
| 40 | |
| 41 | if use_running { |
| 42 | running_aggregate(rows, indices, spec, field); |
| 43 | return; |
| 44 | } |
| 45 | |
| 46 | per_row_aggregate(rows, indices, spec, field); |
| 47 | } |
| 48 | |
| 49 | /// Per-row frame evaluator. |
| 50 | /// |