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