Skip to main content

uqa_sql/semantics/sets/
rewrite.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Set-returning and aggregate dependency expression rewrites.
8
9use crate::plan::{ProjectionPlan, QueryBlockPlan};
10use crate::{FunctionTypeResolver, RowSchema, ScalarExpr, ScalarFrameBound};
11use crate::{SQLError, SQLParam};
12use uqa_core::Value;
13
14use super::validation::{
15    expression_may_return_set, function_may_return_set, resolve_set_function_binding,
16};
17use super::{
18    AggregateOutputProjectionPlan, GroupSetProjectionPlan, ProjectionTarget, SetFunctionCall,
19    SetFunctionCatalog,
20};
21use crate::semantics::aggregates::{exprs_match, is_aggregate};
22use crate::semantics::projection_columns;
23
24#[expect(
25    clippy::too_many_lines,
26    reason = "preserves SELECT schema and row identity"
27)]
28pub fn rewrite_set_calls(
29    engine: &dyn SetFunctionCatalog,
30    resolver: &dyn FunctionTypeResolver,
31    mut expression: ScalarExpr,
32    calls: &mut Vec<SetFunctionCall>,
33    call_relation: crate::ast::InternalRelationId,
34    schema: &RowSchema,
35    params: &[SQLParam],
36) -> Result<ScalarExpr, SQLError> {
37    let descendant_start = calls.len();
38    match &mut expression {
39        ScalarExpr::Func {
40            args,
41            order_by,
42            filter,
43            ..
44        } => {
45            for argument in args {
46                *argument = rewrite_set_calls(
47                    engine,
48                    resolver,
49                    argument.clone(),
50                    calls,
51                    call_relation,
52                    schema,
53                    params,
54                )?;
55            }
56            for order in order_by {
57                order.expr = rewrite_set_calls(
58                    engine,
59                    resolver,
60                    order.expr.clone(),
61                    calls,
62                    call_relation,
63                    schema,
64                    params,
65                )?;
66            }
67            if let Some(filter) = filter {
68                **filter = rewrite_set_calls(
69                    engine,
70                    resolver,
71                    (**filter).clone(),
72                    calls,
73                    call_relation,
74                    schema,
75                    params,
76                )?;
77            }
78        }
79        ScalarExpr::Array(items)
80        | ScalarExpr::Row(items)
81        | ScalarExpr::CompositeRow { items, .. }
82        | ScalarExpr::And(items)
83        | ScalarExpr::Or(items) => {
84            for item in items {
85                *item = rewrite_set_calls(
86                    engine,
87                    resolver,
88                    item.clone(),
89                    calls,
90                    call_relation,
91                    schema,
92                    params,
93                )?;
94            }
95        }
96        ScalarExpr::Binary { lhs, rhs, .. } => {
97            **lhs = rewrite_set_calls(
98                engine,
99                resolver,
100                (**lhs).clone(),
101                calls,
102                call_relation,
103                schema,
104                params,
105            )?;
106            **rhs = rewrite_set_calls(
107                engine,
108                resolver,
109                (**rhs).clone(),
110                calls,
111                call_relation,
112                schema,
113                params,
114            )?;
115        }
116        ScalarExpr::Not(inner)
117        | ScalarExpr::UnaryMinus(inner)
118        | ScalarExpr::IsNull { expr: inner, .. }
119        | ScalarExpr::Cast { expr: inner, .. }
120        | ScalarExpr::Collated { expr: inner, .. } => {
121            **inner = rewrite_set_calls(
122                engine,
123                resolver,
124                (**inner).clone(),
125                calls,
126                call_relation,
127                schema,
128                params,
129            )?;
130        }
131        ScalarExpr::Between { expr, low, high } => {
132            **expr = rewrite_set_calls(
133                engine,
134                resolver,
135                (**expr).clone(),
136                calls,
137                call_relation,
138                schema,
139                params,
140            )?;
141            **low = rewrite_set_calls(
142                engine,
143                resolver,
144                (**low).clone(),
145                calls,
146                call_relation,
147                schema,
148                params,
149            )?;
150            **high = rewrite_set_calls(
151                engine,
152                resolver,
153                (**high).clone(),
154                calls,
155                call_relation,
156                schema,
157                params,
158            )?;
159        }
160        ScalarExpr::InList { expr, list, .. } => {
161            **expr = rewrite_set_calls(
162                engine,
163                resolver,
164                (**expr).clone(),
165                calls,
166                call_relation,
167                schema,
168                params,
169            )?;
170            for item in list {
171                *item = rewrite_set_calls(
172                    engine,
173                    resolver,
174                    item.clone(),
175                    calls,
176                    call_relation,
177                    schema,
178                    params,
179                )?;
180            }
181        }
182        ScalarExpr::WindowCall {
183            args, spec, filter, ..
184        } => {
185            for argument in args {
186                *argument = rewrite_set_calls(
187                    engine,
188                    resolver,
189                    argument.clone(),
190                    calls,
191                    call_relation,
192                    schema,
193                    params,
194                )?;
195            }
196            if let Some(filter) = filter {
197                **filter = rewrite_set_calls(
198                    engine,
199                    resolver,
200                    (**filter).clone(),
201                    calls,
202                    call_relation,
203                    schema,
204                    params,
205                )?;
206            }
207            for item in &mut spec.partition_by {
208                *item = rewrite_set_calls(
209                    engine,
210                    resolver,
211                    item.clone(),
212                    calls,
213                    call_relation,
214                    schema,
215                    params,
216                )?;
217            }
218            for order in &mut spec.order_by {
219                order.expr = rewrite_set_calls(
220                    engine,
221                    resolver,
222                    order.expr.clone(),
223                    calls,
224                    call_relation,
225                    schema,
226                    params,
227                )?;
228            }
229            if let Some(frame) = &mut spec.frame {
230                rewrite_set_frame_bound(
231                    engine,
232                    resolver,
233                    &mut frame.start,
234                    calls,
235                    call_relation,
236                    schema,
237                    params,
238                )?;
239                rewrite_set_frame_bound(
240                    engine,
241                    resolver,
242                    &mut frame.end,
243                    calls,
244                    call_relation,
245                    schema,
246                    params,
247                )?;
248            }
249        }
250        ScalarExpr::Case {
251            base,
252            when,
253            else_branch,
254        } => {
255            if let Some(base) = base {
256                **base = rewrite_set_calls(
257                    engine,
258                    resolver,
259                    (**base).clone(),
260                    calls,
261                    call_relation,
262                    schema,
263                    params,
264                )?;
265            }
266            for (condition, result) in when {
267                *condition = rewrite_set_calls(
268                    engine,
269                    resolver,
270                    condition.clone(),
271                    calls,
272                    call_relation,
273                    schema,
274                    params,
275                )?;
276                *result = rewrite_set_calls(
277                    engine,
278                    resolver,
279                    result.clone(),
280                    calls,
281                    call_relation,
282                    schema,
283                    params,
284                )?;
285            }
286            if let Some(branch) = else_branch {
287                **branch = rewrite_set_calls(
288                    engine,
289                    resolver,
290                    (**branch).clone(),
291                    calls,
292                    call_relation,
293                    schema,
294                    params,
295                )?;
296            }
297        }
298        ScalarExpr::InSubquery { expr, .. } => {
299            **expr = rewrite_set_calls(
300                engine,
301                resolver,
302                (**expr).clone(),
303                calls,
304                call_relation,
305                schema,
306                params,
307            )?;
308        }
309        ScalarExpr::Default
310        | ScalarExpr::Star
311        | ScalarExpr::QualifiedStar(_)
312        | ScalarExpr::Column(_)
313        | ScalarExpr::Position(_)
314        | ScalarExpr::InternalColumn(_)
315        | ScalarExpr::QualifiedColumn { .. }
316        | ScalarExpr::Literal(_)
317        | ScalarExpr::TypedLiteral { .. }
318        | ScalarExpr::Param(_)
319        | ScalarExpr::ScalarSubquery(_)
320        | ScalarExpr::Exists { .. } => {}
321    }
322    if let ScalarExpr::Func {
323        name,
324        binding,
325        args,
326        ..
327    } = &expression
328    {
329        if function_may_return_set(
330            engine,
331            resolver,
332            name,
333            binding.as_ref(),
334            args,
335            schema,
336            params,
337        )? {
338            let binding = resolve_set_function_binding(
339                engine,
340                resolver,
341                name,
342                binding.as_ref(),
343                args,
344                schema,
345                params,
346            )?
347            .or_else(|| binding.clone());
348            let level = calls[descendant_start..]
349                .iter()
350                .map(|call| call.level + 1)
351                .max()
352                .unwrap_or(0);
353            let placeholder = call_relation.column(calls.len());
354            calls.push(SetFunctionCall {
355                placeholder,
356                name: name.clone(),
357                binding,
358                args: args.clone(),
359                level,
360            });
361            return Ok(ScalarExpr::InternalColumn(placeholder));
362        }
363    }
364    Ok(expression)
365}
366
367fn rewrite_set_frame_bound(
368    engine: &dyn SetFunctionCatalog,
369    resolver: &dyn FunctionTypeResolver,
370    bound: &mut ScalarFrameBound,
371    calls: &mut Vec<SetFunctionCall>,
372    call_relation: crate::ast::InternalRelationId,
373    schema: &RowSchema,
374    params: &[SQLParam],
375) -> Result<(), SQLError> {
376    match bound {
377        ScalarFrameBound::Preceding(expression) | ScalarFrameBound::Following(expression) => {
378            **expression = rewrite_set_calls(
379                engine,
380                resolver,
381                (**expression).clone(),
382                calls,
383                call_relation,
384                schema,
385                params,
386            )?;
387        }
388        ScalarFrameBound::UnboundedPreceding
389        | ScalarFrameBound::UnboundedFollowing
390        | ScalarFrameBound::CurrentRow => {}
391    }
392    Ok(())
393}
394
395fn replace_group_set_expression(
396    expression: &mut ScalarExpr,
397    mappings: &[(ScalarExpr, crate::ast::InternalColumnRef)],
398) {
399    if let Some((_, column)) = mappings
400        .iter()
401        .find(|(group, _)| exprs_match(expression, group))
402    {
403        *expression = ScalarExpr::InternalColumn(*column);
404        return;
405    }
406    match expression {
407        ScalarExpr::Func {
408            args,
409            order_by,
410            filter,
411            ..
412        } => {
413            for expression in args
414                .iter_mut()
415                .chain(order_by.iter_mut().map(|order| &mut order.expr))
416                .chain(filter.as_deref_mut())
417            {
418                replace_group_set_expression(expression, mappings);
419            }
420        }
421        ScalarExpr::Array(items)
422        | ScalarExpr::Row(items)
423        | ScalarExpr::CompositeRow { items, .. }
424        | ScalarExpr::And(items)
425        | ScalarExpr::Or(items) => {
426            for item in items {
427                replace_group_set_expression(item, mappings);
428            }
429        }
430        ScalarExpr::Binary { lhs, rhs, .. } => {
431            replace_group_set_expression(lhs, mappings);
432            replace_group_set_expression(rhs, mappings);
433        }
434        ScalarExpr::Not(inner)
435        | ScalarExpr::UnaryMinus(inner)
436        | ScalarExpr::IsNull { expr: inner, .. }
437        | ScalarExpr::Cast { expr: inner, .. }
438        | ScalarExpr::Collated { expr: inner, .. }
439        | ScalarExpr::InSubquery { expr: inner, .. } => {
440            replace_group_set_expression(inner, mappings);
441        }
442        ScalarExpr::Between { expr, low, high } => {
443            replace_group_set_expression(expr, mappings);
444            replace_group_set_expression(low, mappings);
445            replace_group_set_expression(high, mappings);
446        }
447        ScalarExpr::InList { expr, list, .. } => {
448            replace_group_set_expression(expr, mappings);
449            for item in list {
450                replace_group_set_expression(item, mappings);
451            }
452        }
453        ScalarExpr::WindowCall {
454            args, spec, filter, ..
455        } => {
456            for expression in args
457                .iter_mut()
458                .chain(filter.as_deref_mut())
459                .chain(&mut spec.partition_by)
460                .chain(spec.order_by.iter_mut().map(|order| &mut order.expr))
461            {
462                replace_group_set_expression(expression, mappings);
463            }
464            if let Some(frame) = &mut spec.frame {
465                replace_group_set_frame_bound(&mut frame.start, mappings);
466                replace_group_set_frame_bound(&mut frame.end, mappings);
467            }
468        }
469        ScalarExpr::Case {
470            base,
471            when,
472            else_branch,
473        } => {
474            if let Some(base) = base {
475                replace_group_set_expression(base, mappings);
476            }
477            for (condition, result) in when {
478                replace_group_set_expression(condition, mappings);
479                replace_group_set_expression(result, mappings);
480            }
481            if let Some(branch) = else_branch {
482                replace_group_set_expression(branch, mappings);
483            }
484        }
485        ScalarExpr::Default
486        | ScalarExpr::Star
487        | ScalarExpr::QualifiedStar(_)
488        | ScalarExpr::Column(_)
489        | ScalarExpr::Position(_)
490        | ScalarExpr::InternalColumn(_)
491        | ScalarExpr::QualifiedColumn { .. }
492        | ScalarExpr::Literal(_)
493        | ScalarExpr::TypedLiteral { .. }
494        | ScalarExpr::Param(_)
495        | ScalarExpr::ScalarSubquery(_)
496        | ScalarExpr::Exists { .. } => {}
497    }
498}
499
500fn replace_group_set_frame_bound(
501    bound: &mut ScalarFrameBound,
502    mappings: &[(ScalarExpr, crate::ast::InternalColumnRef)],
503) {
504    match bound {
505        ScalarFrameBound::Preceding(expression) | ScalarFrameBound::Following(expression) => {
506            replace_group_set_expression(expression, mappings);
507        }
508        ScalarFrameBound::UnboundedPreceding
509        | ScalarFrameBound::UnboundedFollowing
510        | ScalarFrameBound::CurrentRow => {}
511    }
512}
513
514pub fn prepare_group_set_projection(
515    engine: &dyn SetFunctionCatalog,
516    resolver: &dyn FunctionTypeResolver,
517    statement: &QueryBlockPlan,
518    schema: &RowSchema,
519    params: &[SQLParam],
520) -> Result<Option<GroupSetProjectionPlan>, SQLError> {
521    let mut groups = Vec::new();
522    for expression in statement
523        .group_by
524        .iter()
525        .chain(statement.grouping_sets.iter().flatten())
526    {
527        if expression_may_return_set(engine, resolver, expression, schema, params)?
528            && !groups
529                .iter()
530                .any(|existing| exprs_match(existing, expression))
531        {
532            groups.push(expression.clone());
533        }
534    }
535    if groups.is_empty() {
536        return Ok(None);
537    }
538
539    let relation = crate::ast::InternalRelationId::allocate();
540    let mappings = groups
541        .iter()
542        .enumerate()
543        .map(|(index, expression)| (expression.clone(), relation.column(index)))
544        .collect::<Vec<_>>();
545    let projections = mappings
546        .iter()
547        .map(|(expression, column)| (ProjectionTarget::Internal(*column), expression.clone()))
548        .collect();
549    let mut rewritten = statement.clone();
550    let projection_labels = projection_columns(&rewritten.projections);
551    for expression in &mut rewritten.group_by {
552        replace_group_set_expression(expression, &mappings);
553    }
554    for set in &mut rewritten.grouping_sets {
555        for expression in set {
556            replace_group_set_expression(expression, &mappings);
557        }
558    }
559    for (projection, label) in rewritten.projections.iter_mut().zip(projection_labels) {
560        if projection.alias.is_none() {
561            projection.alias = Some(label);
562        }
563        replace_group_set_expression(&mut projection.expr, &mappings);
564    }
565    if let Some(having) = &mut rewritten.having {
566        replace_group_set_expression(having, &mappings);
567    }
568    for order in &mut rewritten.order_by {
569        replace_group_set_expression(&mut order.expr, &mappings);
570    }
571    for expression in &mut rewritten.distinct_on {
572        replace_group_set_expression(expression, &mappings);
573    }
574    Ok(Some(GroupSetProjectionPlan {
575        statement: rewritten,
576        projections,
577    }))
578}
579
580fn capture_aggregate_dependency(
581    expression: &ScalarExpr,
582    dependencies: &mut Vec<ProjectionPlan>,
583) -> ScalarExpr {
584    let position = dependencies.len();
585    dependencies.push(ProjectionPlan {
586        expr: expression.clone(),
587        alias: None,
588    });
589    ScalarExpr::Position(position)
590}
591
592#[expect(
593    clippy::too_many_lines,
594    reason = "preserves SELECT schema and row identity"
595)]
596fn rewrite_aggregate_dependencies(
597    engine: &dyn SetFunctionCatalog,
598    group_by: &[&ScalarExpr],
599    expression: &ScalarExpr,
600    dependencies: &mut Vec<ProjectionPlan>,
601) -> ScalarExpr {
602    if is_aggregate(engine, expression)
603        || group_by.iter().any(|group| exprs_match(expression, group))
604    {
605        return capture_aggregate_dependency(expression, dependencies);
606    }
607    match expression {
608        ScalarExpr::Column(_)
609        | ScalarExpr::Position(_)
610        | ScalarExpr::InternalColumn(_)
611        | ScalarExpr::QualifiedColumn { .. } => {
612            capture_aggregate_dependency(expression, dependencies)
613        }
614        ScalarExpr::Func {
615            order_syntax,
616            name,
617            binding,
618            args,
619            distinct,
620            order_by,
621            filter,
622        } => ScalarExpr::Func {
623            order_syntax: *order_syntax,
624            name: name.clone(),
625            binding: binding.clone(),
626            args: args
627                .iter()
628                .map(|argument| {
629                    rewrite_aggregate_dependencies(engine, group_by, argument, dependencies)
630                })
631                .collect(),
632            distinct: *distinct,
633            order_by: order_by
634                .iter()
635                .map(|order| {
636                    let mut order = order.clone();
637                    order.expr =
638                        rewrite_aggregate_dependencies(engine, group_by, &order.expr, dependencies);
639                    order
640                })
641                .collect(),
642            filter: filter.as_deref().map(|filter| {
643                Box::new(rewrite_aggregate_dependencies(
644                    engine,
645                    group_by,
646                    filter,
647                    dependencies,
648                ))
649            }),
650        },
651        ScalarExpr::Array(items) => ScalarExpr::Array(
652            items
653                .iter()
654                .map(|item| rewrite_aggregate_dependencies(engine, group_by, item, dependencies))
655                .collect(),
656        ),
657        ScalarExpr::Row(items) => ScalarExpr::Row(
658            items
659                .iter()
660                .map(|item| rewrite_aggregate_dependencies(engine, group_by, item, dependencies))
661                .collect(),
662        ),
663        ScalarExpr::CompositeRow {
664            items,
665            binding,
666            bound_type,
667        } => ScalarExpr::CompositeRow {
668            items: items
669                .iter()
670                .map(|item| rewrite_aggregate_dependencies(engine, group_by, item, dependencies))
671                .collect(),
672            binding: binding.clone(),
673            bound_type: bound_type.clone(),
674        },
675        ScalarExpr::Binary { op, lhs, rhs } => ScalarExpr::Binary {
676            op: *op,
677            lhs: Box::new(rewrite_aggregate_dependencies(
678                engine,
679                group_by,
680                lhs,
681                dependencies,
682            )),
683            rhs: Box::new(rewrite_aggregate_dependencies(
684                engine,
685                group_by,
686                rhs,
687                dependencies,
688            )),
689        },
690        ScalarExpr::Not(inner) => ScalarExpr::Not(Box::new(rewrite_aggregate_dependencies(
691            engine,
692            group_by,
693            inner,
694            dependencies,
695        ))),
696        ScalarExpr::UnaryMinus(inner) => ScalarExpr::UnaryMinus(Box::new(
697            rewrite_aggregate_dependencies(engine, group_by, inner, dependencies),
698        )),
699        ScalarExpr::And(items) => ScalarExpr::And(
700            items
701                .iter()
702                .map(|item| rewrite_aggregate_dependencies(engine, group_by, item, dependencies))
703                .collect(),
704        ),
705        ScalarExpr::Or(items) => ScalarExpr::Or(
706            items
707                .iter()
708                .map(|item| rewrite_aggregate_dependencies(engine, group_by, item, dependencies))
709                .collect(),
710        ),
711        ScalarExpr::IsNull { expr, negated } => ScalarExpr::IsNull {
712            expr: Box::new(rewrite_aggregate_dependencies(
713                engine,
714                group_by,
715                expr,
716                dependencies,
717            )),
718            negated: *negated,
719        },
720        ScalarExpr::Between { expr, low, high } => ScalarExpr::Between {
721            expr: Box::new(rewrite_aggregate_dependencies(
722                engine,
723                group_by,
724                expr,
725                dependencies,
726            )),
727            low: Box::new(rewrite_aggregate_dependencies(
728                engine,
729                group_by,
730                low,
731                dependencies,
732            )),
733            high: Box::new(rewrite_aggregate_dependencies(
734                engine,
735                group_by,
736                high,
737                dependencies,
738            )),
739        },
740        ScalarExpr::InList {
741            expr,
742            list,
743            negated,
744        } => ScalarExpr::InList {
745            expr: Box::new(rewrite_aggregate_dependencies(
746                engine,
747                group_by,
748                expr,
749                dependencies,
750            )),
751            list: list
752                .iter()
753                .map(|item| rewrite_aggregate_dependencies(engine, group_by, item, dependencies))
754                .collect(),
755            negated: *negated,
756        },
757        ScalarExpr::WindowCall {
758            name,
759            args,
760            spec,
761            filter,
762            modifiers,
763        } => {
764            let mut spec = spec.clone();
765            spec.partition_by = spec
766                .partition_by
767                .iter()
768                .map(|item| rewrite_aggregate_dependencies(engine, group_by, item, dependencies))
769                .collect();
770            for order in &mut spec.order_by {
771                order.expr =
772                    rewrite_aggregate_dependencies(engine, group_by, &order.expr, dependencies);
773            }
774            if let Some(frame) = &mut spec.frame {
775                rewrite_aggregate_frame_bound(engine, group_by, &mut frame.start, dependencies);
776                rewrite_aggregate_frame_bound(engine, group_by, &mut frame.end, dependencies);
777            }
778            ScalarExpr::WindowCall {
779                modifiers: *modifiers,
780                name: name.clone(),
781                args: args
782                    .iter()
783                    .map(|argument| {
784                        rewrite_aggregate_dependencies(engine, group_by, argument, dependencies)
785                    })
786                    .collect(),
787                spec,
788                filter: filter.as_deref().map(|filter| {
789                    Box::new(rewrite_aggregate_dependencies(
790                        engine,
791                        group_by,
792                        filter,
793                        dependencies,
794                    ))
795                }),
796            }
797        }
798        ScalarExpr::Case {
799            base,
800            when,
801            else_branch,
802        } => ScalarExpr::Case {
803            base: base.as_deref().map(|base| {
804                Box::new(rewrite_aggregate_dependencies(
805                    engine,
806                    group_by,
807                    base,
808                    dependencies,
809                ))
810            }),
811            when: when
812                .iter()
813                .map(|(condition, result)| {
814                    (
815                        rewrite_aggregate_dependencies(engine, group_by, condition, dependencies),
816                        rewrite_aggregate_dependencies(engine, group_by, result, dependencies),
817                    )
818                })
819                .collect(),
820            else_branch: else_branch.as_deref().map(|branch| {
821                Box::new(rewrite_aggregate_dependencies(
822                    engine,
823                    group_by,
824                    branch,
825                    dependencies,
826                ))
827            }),
828        },
829        ScalarExpr::Collated {
830            expr,
831            ty,
832            collation,
833        } => ScalarExpr::Collated {
834            expr: Box::new(rewrite_aggregate_dependencies(
835                engine,
836                group_by,
837                expr,
838                dependencies,
839            )),
840            ty: ty.clone(),
841            collation: *collation,
842        },
843        ScalarExpr::Cast { expr, ty, implicit } => ScalarExpr::Cast {
844            implicit: *implicit,
845            expr: Box::new(rewrite_aggregate_dependencies(
846                engine,
847                group_by,
848                expr,
849                dependencies,
850            )),
851            ty: ty.clone(),
852        },
853        ScalarExpr::InSubquery {
854            expr,
855            subquery,
856            negated,
857        } => ScalarExpr::InSubquery {
858            expr: Box::new(rewrite_aggregate_dependencies(
859                engine,
860                group_by,
861                expr,
862                dependencies,
863            )),
864            subquery: *subquery,
865            negated: *negated,
866        },
867        ScalarExpr::Default
868        | ScalarExpr::Star
869        | ScalarExpr::QualifiedStar(_)
870        | ScalarExpr::Literal(_)
871        | ScalarExpr::TypedLiteral { .. }
872        | ScalarExpr::Param(_)
873        | ScalarExpr::ScalarSubquery(_)
874        | ScalarExpr::Exists { .. } => expression.clone(),
875    }
876}
877
878fn rewrite_aggregate_frame_bound(
879    engine: &dyn SetFunctionCatalog,
880    group_by: &[&ScalarExpr],
881    bound: &mut ScalarFrameBound,
882    dependencies: &mut Vec<ProjectionPlan>,
883) {
884    match bound {
885        ScalarFrameBound::Preceding(expression) | ScalarFrameBound::Following(expression) => {
886            **expression =
887                rewrite_aggregate_dependencies(engine, group_by, expression, dependencies);
888        }
889        ScalarFrameBound::UnboundedPreceding
890        | ScalarFrameBound::UnboundedFollowing
891        | ScalarFrameBound::CurrentRow => {}
892    }
893}
894
895pub fn prepare_aggregate_output_projection(
896    engine: &dyn SetFunctionCatalog,
897    statement: &QueryBlockPlan,
898    internal_targets: &[(usize, crate::ast::InternalColumnRef)],
899) -> AggregateOutputProjectionPlan {
900    let labels = projection_columns(&statement.projections);
901    // A grouping-set expression remains one aggregate dependency. Splitting it into its input columns would replace those ungrouped inputs with NULL before evaluating the final projection.
902    let group_by = statement
903        .group_by
904        .iter()
905        .chain(statement.grouping_sets.iter().flatten())
906        .collect::<Vec<_>>();
907    let mut dependencies = Vec::new();
908    let projections = statement
909        .projections
910        .iter()
911        .enumerate()
912        .zip(labels)
913        .map(|((position, projection), label)| {
914            let target = internal_targets
915                .iter()
916                .find(|(target_position, _)| *target_position == position)
917                .map_or_else(
918                    || ProjectionTarget::Column(label),
919                    |(_, column)| ProjectionTarget::Internal(*column),
920                );
921            (
922                target,
923                rewrite_aggregate_dependencies(
924                    engine,
925                    &group_by,
926                    &projection.expr,
927                    &mut dependencies,
928                ),
929            )
930        })
931        .collect();
932    if dependencies.is_empty() {
933        dependencies.push(ProjectionPlan {
934            expr: ScalarExpr::Literal(Value::Int(1)),
935            alias: None,
936        });
937    }
938    let mut aggregate_statement = statement.clone();
939    aggregate_statement.projections = dependencies;
940    AggregateOutputProjectionPlan {
941        statement: aggregate_statement,
942        projections,
943    }
944}